2015-02-01 15 views
8

Ciao Sto cercando di scaricare il contenuto da una pagina web che utilizza https via C++. Il mio programma client di base preso dagli esempi di Boost asio viene compilato e funziona bene, ma quando lo collaudo ad esempio con Google: www.google.co.uk/?gws_rd=ssl, mi dà l'errore "handshake: certificate certificate failed" .Certificati SSL e Boost asio

Penso che questo sia dovuto al fatto che ctx.set_default_verify_paths() non contiene un percorso con un certificato per Google (sono su Windows).

sto molto di nuovo da SSL, per favore potete aiutarmi con le seguenti domande:

1) Quando ho installato OpenSSL, vero bastone un elenco di autorità di certificazione di fiducia sul mio computer? In caso affermativo, cosa causerebbe la mancata verifica del certificato di Google?

2) C'è comunque da dire che non mi interessa la verifica, procedere comunque alla connessione, come quando si aggiunge manualmente un'eccezione in firefox? Non sono particolarmente interessato a sapere se la connessione è affidabile poiché non sto trasmettendo nulla che debba essere sicuro.

Le risposte a entrambi sarebbero molto apprezzate!

#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; 
} 

risposta

7

certificati vengono spesso installati o aggiornati tramite il sistema operativo, browser, o di singoli pacchetti. Ad esempio, nel mondo * nix, i certificati sono spesso disponibili tramite il pacchetto ca-certificates e i certificati vengono installati in posizioni che troveranno boost::asio::ssl::context::set_default_verify_paths().

La verifica di certificazione sta fallendo perché il cliente sta tentando di verificare i certificati del pari con la verifica hostname (rfc2818), e sta controllando per letterale "host.name" di essere nel certificato, ei certificati del server non elencano "host.name" come nome. Prova a cambiare:

socket.set_verify_callback(ssl::rfc2818_verification("host.name")); 

a:

socket.set_verify_callback(ssl::rfc2818_verification(argv[1])); 

Per disattivare la verifica tra pari, forniscono boost::asio::ssl::verify_none al boost::asio::ssl::stream::set_verify_mode():

socket.set_verify_mode(boost::asio::ssl::verify_none); 

Boost.Asio fornisce altri peer verify_mode s.


Quando la verifica tra pari sta venendo a mancare, può essere utile per fornire un callback personalizzata per boost::asio::ssl::stream::set_verify_callback che fornisce informazioni diagnostiche.Come indicato nella documentazione, la firma conduttore deve essere:

bool verify_callback(
    bool preverified, // True if the certificate passed pre-verification. 
    verify_context& ctx // The peer certificate and other context. 
); 

Ecco un funtore personalizzato che consente di stampare il nome del certificato soggetto:

///@brief Helper class that prints the current certificate's subject 
///  name and the verification results. 
template <typename Verifier> 
class verbose_verification 
{ 
public: 
    verbose_verification(Verifier verifier) 
    : verifier_(verifier) 
    {} 

    bool operator()(
    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); 
    bool verified = verifier_(preverified, ctx); 
    std::cout << "Verifying: " << subject_name << "\n" 
       "Verified: " << verified << std::endl; 
    return verified; 
    } 
private: 
    Verifier verifier_; 
}; 

///@brief Auxiliary function to make verbose_verification objects. 
template <typename Verifier> 
verbose_verification<Verifier> 
make_verbose_verification(Verifier verifier) 
{ 
    return verbose_verification<Verifier>(verifier); 
} 

e il suo utilizzo:

socket.set_verify_callback(make_verbose_verification(
    boost::asio::ssl::rfc2818_verification(argv[1]))); 

On la mia macchina, quando lo si utilizza e set_default_verify_paths() non viene richiamato, ottengo il seguente output:

$ ./a.out www.google.co.uk /?gws_rd=ssl 
Verifying: /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 
Verified: 0 
Exception: handshake: certificate verify failed 

E quando set_default_verify_paths() è invocato:

$ ./a.out www.google.co.uk /?gws_rd=ssl 
Verifying: /C=US/O=Equifax/OU=Equifax Secure Certificate Authority 
Verified: 1 
Verifying: /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 
Verified: 1 
Verifying: /C=US/O=Google Inc/CN=Google Internet Authority G2 
Verified: 1 
Verifying: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=google.com 
Verified: 1 

E quando rfc2818_verification("host.name") viene utilizzato:

$ ./a.out www.google.co.uk /?gws_rd=ssl 
Verifying: /C=US/O=Equifax/OU=Equifax Secure Certificate Authority 
Verified: 1 
Verifying: /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA 
Verified: 1 
Verifying: /C=US/O=Google Inc/CN=Google Internet Authority G2 
Verified: 1 
Verifying: /C=US/ST=California/L=Mountain View/O=Google Inc/CN=google.com 
Verified: 0 
Exception: handshake: certificate verify failed 
+0

Ciao vi ringrazio molto per il vostro aiuto. Quando ho messo in funzione diagnostica ottengo la prima uscita che trovate: 'Verifica:/C = US/O = GeoTrust Inc./CN=GeoTrust globale CA Verificati: 0 Eccezione: la stretta di mano: certificato di verifica failed' ... dopo aver rimosso l'errore "host.name". Ho ragione nel pensare che questo indichi che set_default_verify_paths() non sta facendo un ottimo lavoro? ... Quando faccio 'socket.set_verify_mode (boost :: asio :: :: SSL verify_none);' ottengo un'eccezione lettura breve che credo sia un problema di non correlato. Grazie ancora per il vostro aiuto – Jez

+0

@Jez E 'possibile che l'installazione non ha incluso certificati attendibili, il percorso è non essere trovato tramite 'set_default_verify_paths()', oppure l'applicazione non dispone delle autorizzazioni per leggere dalla directory. Consultare la documentazione dell'installatore o sfogliare il file system. Se si trova un percorso contenente i certificati, aggiungere che il percorso al contesto tramite [ 'add_verify_path()'] (http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/reference/ssl__context/ add_verify_path/overload1.html). –

+0

Si scopre che non avevo i certificati installati come parte di OpenSSL. Ho in mano la lista dei certificati di Mozilla in un unico file PEM, ma quando ho drill-down in quanto 'add_verify_path()' [in realtà è un wrapper per] (https://www.openssl.org/docs/ssl/ SSL_CTX_load_verify_locations.html), sembra che ogni certificato sia necessario in un file separato e l'estensione di questi file deve essere .0 non .pem. E 'corretto e se sì, come faccio a prendere il mio singolo file PEM e dividerlo? Cheers – Jez