2012-03-04 17 views
12

Ho un'app client C++ che utilizza Boost ASIO per effettuare connessioni SSL a vari server. Ma contro 2 server specifici, la connessione SSL non può essere stabilita. Si blocca nella chiamata a boost::asio::ssl::stream::handshake().Boost ASIO: l'handshake SSL() non termina mai

Ho usato Wireshark per osservare la conversazione tra client e server. Una connessione SSL lavoro sembra fare questo:

sslsocket.lowest_layer().connect(endpoint, ec); 
C -> SYN -> S 
C <- SYN ACK <- S 
C -> ACK -> S 
sslsocket.handshake(SSLSocket::client, ec); 
C -> 209 bytes -> S 
C <- 690 bytes <- S 
C -> 198 bytes -> S 
C <- 415 bytes <- S 

... ea questo punto i ASIO handshake() chiamata rendimenti che indicano tutto va bene, e la connessione socket SSL funziona bene.

Ma contro 2 server diversi [*], la stretta di mano assomiglia a questo:

sslsocket.lowest_layer().connect(endpoint, ec); 
C -> SYN -> S 
C <- SYN ACK <- S 
C -> ACK -> S 
sslsocket.handshake(SSLSocket::client, ec); 
C -> 209 bytes -> S 
...2 minute pause... 
C <- RST <- S 

Guardando i file di log su questi server, sembra come se dopo i primi 209 byte vengono inviati nella stretta di mano, il server ha considerato la connessione SSL completamente stabilita. Ma il client è ancora presente nella chiamata di handshake() ASIO Boost e alla fine restituisce ec = 104 quando viene ripristinata la connessione.

Quindi penso che forse ci sono diversi tipi di handshake SSL, e forse c'è un "più semplice" che dovrei usare?

[*] So che qualcuno vorrà sapere: uno dei server che causa questo problema con l'app client è FileZilla Server per l'installazione di Windows per utilizzare SSL/TLS [FTPS], e l'altro è un servizio proprietario in esecuzione su Linux)


UPDATE:. Sam Miller ha chiesto che ho posto il mio codice che descrive come il contesto SSL è impostato:

Class (file .hpp) contiene questo:

typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLSocket; 
boost::asio::io_service ioservice; 
boost::asio::ssl::context sslcontext; 
SSLSocket     sslDataSocket; 
boost::system::error_code ec; 

Costruttore ha queste initializers:

ioservice  (2), 
sslcontext  (ioservice, boost::asio::ssl::context::sslv23), 
sslDataSocket (ioservice, sslcontext), 

... e di questo codice:

sslcontext.set_options(boost::asio::ssl::context::default_workarounds | 
         boost::asio::ssl::context::verify_none  ); 

E questo è il codice in cui è stabilito il socket SSL e la stretta di mano si blocca:

std::cout << "connecting SSL socket to endpoint " << buffer << std::endl; 
sslDataSocket.lowest_layer().connect(tcpEndpoint, ec); 
std::cout << "connect() done, ec=" << ec.value() << std::endl; 
if (ec) throw "test 1"; 

std::cout << "starting ssl handshake" << std::endl; 
sslDataSocket.handshake(SSLSocket::client, ec); 
std::cout << "handshake done, ec=" << ec.value() << std::endl; 
if (ec) throw "test 2"; 
+0

Domanda molto ben fatta. –

+0

Recentemente ho avuto un problema con SSL [collegamento] (http://stackoverflow.com/questions/9411506/boosts-asio-ssl-dont-work-in-some-conditions). Il comando 'openssl s_client -connect server_ip: server_port' mi ha aiutato a capire la causa. Potrebbe essere che ti aiuterà anche. – megabyte1024

+0

per favore pubblica il tuo codice descrivendo come è impostato il contesto ssl –

risposta

9

L'avevo capito. Questo tutorial SSL (http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html) conteneva la chiave che finalmente ha funzionato per me. Codice:

È possibile riutilizzare le informazioni da una sessione SSL già stabilita per creare una nuova connessione SSL. Poiché la nuova connessione SSL è riutilizzando lo stesso segreto principale, è possibile eseguire più rapidamente l'handshake SSL . Di conseguenza, la ripresa della sessione SSL può ridurre il carico di di un server che accetta molte connessioni SSL.

Quindi, ecco come ho ottenuto questo lavoro con Boost ASIO:

  • configurazione della presa normale SSL di controllo (un sacco di esempi, tra cui questa domanda)
  • quando è necessario impostare il 2 ° SSL presa di dati, fare questo:

    sslSocket2.lowest_layer().connect(tcpEndpoint, ec); 
    SSLSocket::impl_type impl1 = sslSocket1.impl(); 
    SSLSocket::impl_type impl2 = sslSocket2.impl(); 
    SSL_SESSION *savedSession = SSL_get1_session(impl1->ssl); 
    SSL_set_session(impl2->ssl, savedSession); 
    SSL_connect(impl2->ssl); 

questo è tutto. A questo punto, non è necessario chiamare sslSocket2.handshake(). Basta leggere e scrivere sul socket sapendo che la connessione è stata stabilita.

+1

Vedere anche: http://stackoverflow.com/questions/7786352/ssl-session-resume-on-ftp-transfer-connection-with-openssl –

+0

Probabilmente si desidera chiamare sslSocket2.async_handshake invece di chiamare direttamente SSL_connect se si utilizzano le funzioni asincrone, async_handshake chiama internamente SSL_connect. – John