我正在尝试使用Boost.Asio从C++应用程序通过HTTPS连接读取数据。我参考了一个类似的SO问题(使用Boost.Asio和OpenSSL进行HTTPS请求),但仍然遇到“证书验证失败”的错误。
我稍微更新了代码 - 使用谷歌代替www.mtgox.com,因为该网站已更改并给我浏览器警告,提示存在自签名证书的问题。我想象Google的证书链不会有这些问题。
我已下载发行者证书并确认它可以在命令行中正常工作:
给我:
我得到了Google首页的HTML/JavaScript代码,这正是我期望的内容。
然而,我的代码仍然无法实现预期的功能。(我已经尽可能把代码缩短了):
我认为我已经正确加载了证书,但我不确定如何从Boost中获取更多信息以更好地解决问题。我使用的是Linux Mint系统,因此我不知道Debian与SSL 3的问题是否也会影响到我。即使进行了广泛的搜索并阅读了Boost.Asio文档,也没有得到太多帮助。虽然有很多参考资料,但是解释较少。
如果您有任何关于我的错误或如何找出问题原因的建议,将不胜感激。
我稍微更新了代码 - 使用谷歌代替www.mtgox.com,因为该网站已更改并给我浏览器警告,提示存在自签名证书的问题。我想象Google的证书链不会有这些问题。
我已下载发行者证书并确认它可以在命令行中正常工作:
openssl s_client -showcerts -CApath ./certs -connect google.com:443
给我:
CONNECTED(00000003)
depth=2 C = US, O = Equifax, OU = Equifax Secure Certificate Authority
verify return:1
depth=1 C = US, O = Google Inc, CN = Google Internet Authority
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = *.google.com
verify return:1
---
Certificate chain
0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.com
i:/C=US/O=Google Inc/CN=Google Internet Authority
-----BEGIN CERTIFICATE-----
MIIF/DCCBWWgAwIBAgIKHN4TOQAAAAB/azANBgkqhkiG9w0BAQUFADBGMQswCQYD
VQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZR29vZ2xlIElu
dGVybmV0IEF1dGhvcml0eTAeFw0xMzAzMDcxNDI0MDFaFw0xMzA2MDcxOTQzMjda
MGYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1N
b3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgSW5jMRUwEwYDVQQDFAwqLmdv
b2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANVtYuy195QvNel7
trGWR58HJwAZ+ePoaDQgb2tBFllwxpNZDWSAeUi+L2FHDla/L7DEig62yWvR2xgJ
Fg0w9XZkm5uyKIi4olF9ahjWDdlzRJNwYp8cEfReW2d7buBbRIRx7QHywR3FSi9B
uY7BEwIne/Sppz/j8RttVSDXYGNJAgMBAAGjggPPMIIDyzAdBgNVHSUEFjAUBggr
BgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFDeOUXJygXLBA10KGrRYrS7UX19J
MB8GA1UdIwQYMBaAFL/AMOv1QxE+Z7qekfv8atrjaxIkMFsGA1UdHwRUMFIwUKBO
oEyGSmh0dHA6Ly93d3cuZ3N0YXRpYy5jb20vR29vZ2xlSW50ZXJuZXRBdXRob3Jp
dHkvR29vZ2xlSW50ZXJuZXRBdXRob3JpdHkuY3JsMGYGCCsGAQUFBwEBBFowWDBW
BggrBgEFBQcwAoZKaHR0cDovL3d3dy5nc3RhdGljLmNvbS9Hb29nbGVJbnRlcm5l
dEF1dGhvcml0eS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS5jcnQwDAYDVR0TAQH/
BAIwADCCApUGA1UdEQSCAowwggKIggwqLmdvb2dsZS5jb22CDSouYW5kcm9pZC5j
b22CFiouYXBwZW5naW5lLmdvb2dsZS5jb22CEiouY2xvdWQuZ29vZ2xlLmNvbYIW
Ki5nb29nbGUtYW5hbHl0aWNzLmNvbYILKi5nb29nbGUuY2GCCyouZ29vZ2xlLmNs
gg4qLmdvb2dsZS5jby5pboIOKi5nb29nbGUuY28uanCCDiouZ29vZ2xlLmNvLnVr
gg8qLmdvb2dsZS5jb20uYXKCDyouZ29vZ2xlLmNvbS5hdYIPKi5nb29nbGUuY29t
LmJygg8qLmdvb2dsZS5jb20uY2+CDyouZ29vZ2xlLmNvbS5teIIPKi5nb29nbGUu
Y29tLnRygg8qLmdvb2dsZS5jb20udm6CCyouZ29vZ2xlLmRlggsqLmdvb2dsZS5l
c4ILKi5nb29nbGUuZnKCCyouZ29vZ2xlLmh1ggsqLmdvb2dsZS5pdIILKi5nb29n
bGUubmyCCyouZ29vZ2xlLnBsggsqLmdvb2dsZS5wdIIPKi5nb29nbGVhcGlzLmNu
ghQqLmdvb2dsZWNvbW1lcmNlLmNvbYINKi5nc3RhdGljLmNvbYIMKi51cmNoaW4u
Y29tghAqLnVybC5nb29nbGUuY29tghYqLnlvdXR1YmUtbm9jb29raWUuY29tgg0q
LnlvdXR1YmUuY29tggsqLnl0aW1nLmNvbYILYW5kcm9pZC5jb22CBGcuY2+CBmdv
by5nbIIUZ29vZ2xlLWFuYWx5dGljcy5jb22CCmdvb2dsZS5jb22CEmdvb2dsZWNv
bW1lcmNlLmNvbYIKdXJjaGluLmNvbYIIeW91dHUuYmWCC3lvdXR1YmUuY29tMA0G
CSqGSIb3DQEBBQUAA4GBAFnvOnn7rF3Tj94qGAPl09lYFYZxoObOYvqQg5H2tEr6
JZk1OEn/743r3yyTllwk8E6zyyerXMzNPXI9dOtkdNwGUcEaWw19eDAWUiZOi7EI
wIRY2VPT5+7BPIwFgcydtyqcDJz39HdNNHtIkOXHzgEnwnFiqJT2cjeX27DWyqwl
-----END CERTIFICATE-----
1 s:/C=US/O=Google Inc/CN=Google Internet Authority
i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
-----BEGIN CERTIFICATE-----
MIICsDCCAhmgAwIBAgIDC2dxMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDkwNjA4MjA0MzI3WhcNMTMwNjA3MTk0MzI3
WjBGMQswCQYDVQQGEwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzEiMCAGA1UEAxMZ
R29vZ2xlIEludGVybmV0IEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEAye23pIucV+eEPkB9hPSP0XFjU5nneXQUr0SZMyCSjXvlKAy6rWxJfoNf
NFlOCnowzdDXxFdF7dWq1nMmzq0yE7jXDx07393cCDaob1FEm8rWIFJztyaHNWrb
qeXUWaUr/GcZOfqTGBhs3t0lig4zFEfC7wFQeeT9adGnwKziV28CAwEAAaOBozCB
oDAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFL/AMOv1QxE+Z7qekfv8atrjaxIk
MB8GA1UdIwQYMBaAFEjmaPkr0rKV10fYIyAQTzOYkJ/UMBIGA1UdEwEB/wQIMAYB
Af8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20v
Y3Jscy9zZWN1cmVjYS5jcmwwDQYJKoZIhvcNAQEFBQADgYEAuIojxkiWsRF8YHde
BZqrocb6ghwYB8TrgbCoZutJqOkM0ymt9e8kTP3kS8p/XmOrmSfLnzYhLLkQYGfN
0rTw8Ktx5YtaiScRhKqOv5nwnQkhClIZmloJ0pC3+gz4fniisIWvXEyZ2VxVKfml
UUIuOss4jHg7y/j7lYe8vJD5UDI=
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.google.com
issuer=/C=US/O=Google Inc/CN=Google Internet Authority
---
No client certificate CA names sent
---
SSL handshake has read 2744 bytes and written 348 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-RC4-SHA
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1.1
Cipher : ECDHE-RSA-RC4-SHA
Session-ID: A69DDC4E1D33F3D03603AED0CC9F101CC1A49BEE76D61AC0508A780D9E2AF06A
Session-ID-ctx:
Master-Key: 8B08C4A8FB1332EE278F037B115EB4E3E6EF51BCE464B05F8B0652A2773FD34FC2F769B2AB51DCC57CF9844A8B747F97
Key-Arg : None
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 100800 (seconds)
TLS session ticket:
0000 - 1f 6b 71 a9 3c 1f 83 b0-ad 45 ee 74 5f bb d6 3f .kq.<....E.t_..?
0010 - 06 a3 01 3a a6 00 53 da-b2 72 9b 16 d5 5f 54 75 ...:..S..r..._Tu
0020 - 7e 35 10 1d c8 7e 6e 9e-29 dc f1 67 97 aa 94 77 ~5...~n.)..g...w
0030 - 81 f5 a4 6c 25 29 61 13-12 6b d3 13 86 40 95 ae ...l%)a..k...@..
0040 - d0 6b d9 1f 9e 62 a4 09-68 8a fb 7b 6a b0 34 74 .k...b..h..{j.4t
0050 - 57 0e 2f 45 d8 e9 9c 10-af 43 dc 83 b7 bd 8f 63 W./E.....C.....c
0060 - 5e 84 d4 e1 bd 8a 18 55-de 4b a7 58 1e 9d b1 bf ^......U.K.X....
0070 - 84 de bb 0b 4a 9b 46 7f-cf 94 8b e3 48 53 54 49 ....J.F.....HSTI
0080 - 1a 3b f9 41 4b 08 fc ac-b6 09 f0 5b 65 bf e3 cd .;.AK......[e...
0090 - 62 7b ad e4 b{..
Start Time: 1363898770
Timeout : 300 (sec)
Verify return code: 0 (ok)
如果我接着输入
GET
我得到了Google首页的HTML/JavaScript代码,这正是我期望的内容。
然而,我的代码仍然无法实现预期的功能。(我已经尽可能把代码缩短了):
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>
class client
{
public:
client(boost::asio::io_service& io_service, boost::asio::ssl::context& context, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
: socket_(io_service, context)
{
socket_.set_verify_mode(boost::asio::ssl::context::verify_peer);
socket_.set_verify_callback(boost::bind(&client::verify_certificate, this, _1, _2));
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator, boost::bind(&client::handle_connect, this, boost::asio::placeholders::error));
}
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx)
{
char subject_name[256];
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying:\n" << subject_name << std::endl;
return preverified;
}
void handle_connect(const boost::system::error_code& error)
{
if(!error){
std::cout << "Connection OK!" << std::endl;
socket_.async_handshake(boost::asio::ssl::stream_base::client, boost::bind(&client::handle_handshake, this, boost::asio::placeholders::error));
}else{
std::cout << "Connect failed: " << error.message() << std::endl;
}
}
void handle_handshake(const boost::system::error_code& error)
{
if(!error){
std::cout << "Sending request: " << std::endl;
std::stringstream request_;
request_ << "GET HTTP/1.1\r\n";
request_ << "Host: google.com\r\n";
request_ << "Accept-Encoding: *\r\n";
request_ << "\r\n";
std::cout << request_.str() << std::endl;
boost::asio::async_write(socket_, boost::asio::buffer(request_.str()), boost::bind(&client::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}else{
std::cout << "Handshake failed: " << error.message() << std::endl;
}
}
void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
if (!error){
std::cout << "Sending request OK!" << std::endl;
boost::asio::async_read(socket_, boost::asio::buffer(reply_, bytes_transferred), boost::bind(&client::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}else{
std::cout << "Write failed: " << error.message() << std::endl;
}
}
void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
if (!error){
std::cout << "Reply: ";
std::cout.write(reply_, bytes_transferred);
std::cout << "\n";
}else{
std::cout << "Read failed: " << error.message() << std::endl;
}
}
private:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
char reply_[0x1 << 16];
};
int main(int argc, char* argv[])
{
try{
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query("www.google.com", "443");
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
context.add_verify_path("/home/mint/workspace/BoostExamples/certs");
client c(io_service, context, iterator);
io_service.run();
}catch (std::exception& e){
std::cerr << "Exception: " << e.what() << "\n";
}
std::cin.get();
return 0;
}
出现以下错误:
Connection OK!
Verifying:
/C=US/O=Google Inc/CN=Google Internet Authority
Handshake failed: certificate verify failed
我认为我已经正确加载了证书,但我不确定如何从Boost中获取更多信息以更好地解决问题。我使用的是Linux Mint系统,因此我不知道Debian与SSL 3的问题是否也会影响到我。即使进行了广泛的搜索并阅读了Boost.Asio文档,也没有得到太多帮助。虽然有很多参考资料,但是解释较少。
如果您有任何关于我的错误或如何找出问题原因的建议,将不胜感激。