Boost Asio HTTPS request giving 'certificate verify failed' error
boost, boost-asio, c++, https
Solution
From the code you have posted I can, at the moment, only see one more or less obvious reason.
It seems like you simply return the `preverified` bool in the `verify_certificate(...)` function straight off. What if this is `false`? Which it would be if boost has not preverified it. Your function should do the verification - you don't...
Try returning true. If it works, look below.
I can grant you that the code you have should work out of the box, since it's the boost example code. But it could be that your `context.add_verify_path("/home/mint/workspace/BoostExamples/certs");` messes it up... Or rather, that the file in the directory does not have the expected name. From the reference:
Each file in the directory must contain a single certificate.
The files must be named using the subject name's hash and an extension of ".0".
Problem
I'm trying to read data over an HTTPS connection using Boost.Asio from a C++ application. I'm working off a similiar SO question (HTTPS request with Boost.Asio and OpenSSL), but am still getting a 'certificate verify failled' error. I've updated the code slightly - using Google instead since the www.mtgox.com site has changed and is giving me browser warnings about self-signed certificates. Google's certificate chain I imagine would be free of these problems. I've downloaded the issuer certificate and confirm that it works ok from the command line: ``` openssl s_client -showcerts -CApath ./certs -connect google.com:443 ``` gives me: ``` 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) ``` If i then type in ``` GET ``` I get the html/javascript code for the Google home page, which is what I'd expect. However, my code still fails. (I've tried to make it as short as possible): ``` #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; } ``` With the following error: ``` Connection OK! Verifying: /C=US/O=Google Inc/CN=Google Internet Authority Handshake failed: certificate verify failed ``` I think I'm loading the certificates correctly, but am not sure and it's not clear to me how to get more information out of Boost to shed more light on the problem. I'm on Linux Mint so I don't know whether the Debian issues with SSL 3 are also coming into play. Extensive searching and reading the Boost.Asio documentation haven't helped, either. There's lots of reference material but not much explanation. Any suggestions as to what I'm doing wrong, or how to find out what's causing the problem would be greatly appreciated.