Hello I'm trying to download content from webpage that uses https via C++. My very basic client program taken from the Boost asio examples compiles and runs fine, but when I test it eg with Google: www.google.co.uk/?gws_rd=ssl, it gives me the error "handshake: certificate verify failed".
I think this is because ctx.set_default_verify_paths() doesn't contain a path with a certificate for Google (I'm on Windows).
I'm very new to SSL, please can you help me with the following questions:
1) When I installed openSSL, did it stick a list of trusted certifying authorities on my computer? If it did, what would cause Google's certificate not to be verified?
2) Is there anyway of saying I don't care about verification, proceed to connect anyway, like when you add an exception manually in firefox? I'm not particularly interested in whether the connection is trusted as I am not transmitting anything that needs to be secure.
Answers to either would be greatly appreciated!
#include <iostream>
#include <istream>
#include <ostream>
#include <fstream>
#include <string>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
using boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
typedef ssl::stream<tcp::socket> ssl_socket;
int main(int argc, char* argv[])
{
try
{
if (argc != 3)
{
std::cout << argc;
std::cout << "Usage: sync_client <server> <path>\n";
std::cout << "Example:\n";
std::cout << " sync_client www.boost.org /LICENSE_1_0.txt\n";
return 1;
}
boost::asio::io_service io_service;
// Create a context that uses the default paths for
// finding CA certificates.
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
// Get a list of endpoints corresponding to the server name.
tcp::resolver resolver(io_service);
tcp::resolver::query query(argv[1], "https");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
// Try each endpoint until we successfully establish a connection.
ssl_socket socket(io_service, ctx);
boost::asio::connect(socket.lowest_layer(), endpoint_iterator);
socket.lowest_layer().set_option(tcp::no_delay(true));
// Perform SSL handshake and verify the remote host's
// certificate.
socket.set_verify_mode(ssl::verify_peer);
socket.set_verify_callback(ssl::rfc2818_verification("host.name"));
socket.handshake(ssl_socket::client);
// Form the request. We specify the "Connection: close" header so that the
// server will close the socket after transmitting the response. This will
// allow us to treat all data up until the EOF as the content.
boost::asio::streambuf request;
std::ostream request_stream(&request);
request_stream << "GET " << argv[2] << " HTTP/1.0\r\n";
request_stream << "Host: " << argv[1] << "\r\n";
request_stream << "Accept: */*\r\n";
request_stream << "Connection: close\r\n\r\n";
// Send the request.
boost::asio::write(socket, request);
// Read the response status line. The response streambuf will automatically
// grow to accommodate the entire line. The growth may be limited by passing
// a maximum size to the streambuf constructor.
boost::asio::streambuf response;
boost::asio::read_until(socket, response, "\r\n");
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
std::cout << "Invalid response\n";
return 1;
}
if (status_code != 200)
{
std::cout << "Response returned with status code " << status_code << "\n";
std::cout << status_message << "\n";
// Read the response headers, which are terminated by a blank line.
boost::asio::read_until(socket, response, "\r\n\r\n");
// Process the response headers.
std::string header;
while (std::getline(response_stream, header) && header != "\r")
std::cout << header << "\n";
std::cout << "\n";
return 1;
}
//code to read the data goes here, which works fine for http pages
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << "\n";
}
return 0;
}
Verifying: /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA Verified: 0 Exception: handshake: certificate verify failed
...after I remove the "host.name" error. Am I right in thinking this is indicating set_default_verify_paths() is not doing a very good job? ...When I dosocket.set_verify_mode(boost::asio::ssl::verify_none);
I get a short read exception which I guess is an unrelated problem. Thanks again for your help – Time