2012-03-04 17 views
12

Tengo una aplicación cliente C++ que usa Boost ASIO para hacer conexiones SSL a varios servidores. Pero contra 2 servidores específicos, la conexión SSL no se puede establecer. Se cuelga en la llamada al boost::asio::ssl::stream::handshake().Boost ASIO: SSL handshake() nunca termina

He usado Wireshark para observar la conversación entre el cliente y el servidor. Una conexión SSL trabajo parece hacer esto:

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 

... y en este punto los ASIO handshake() devuelve la llamada que indican todo está bien, y la conexión de socket SSL funciona bien.

Pero contra 2 servidores diferentes [*], el apretón de manos tiene el siguiente aspecto:

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 

En cuanto a los archivos de registro en estos servidores, parece como si después de los 209 bytes iniciales se envían en el apretón de manos, el el servidor considera que la conexión SSL está completamente establecida. Pero el cliente todavía está sentado en la llamada Boost ASIO handshake(), y finalmente devuelve ec = 104 cuando se restablece la conexión.

Así que estoy pensando que tal vez haya diferentes tipos de apretones de manos de SSL, y tal vez haya uno "más simple" que debería estar usando?

[*] Sé que alguien querrá saber: uno de los servidores que está causando este problema con la aplicación cliente es FileZilla Server para Windows que usa SSL/TLS [FTPS], y el otro es un servicio propietario que se ejecuta Linux)


ACTUALIZACIÓN:. Sam Miller pidió que fijo mi código que describe cómo el contexto SSL está configurado:

Clase (archivo .hpp) contiene lo siguiente:

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; 

Constructor tiene estas inicializadores:

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

... y este código:

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

Y este es el código que está establecido el socket SSL y el apretón de manos cuelga:

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

Pregunta muy bien hecha. –

+0

Recientemente tuve un problema con SSL [link] (http://stackoverflow.com/questions/9411506/boosts-asio-ssl-dont-work-in-some-conditions). El comando 'openssl s_client -connect server_ip: server_port' me ayudó a entender la causa. Puede ser que te ayude también. – megabyte1024

+0

publique su código describiendo cómo se configura el contexto de SSL –

Respuesta

9

Me lo imaginé. Este tutorial de SSL (http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html) contenía la clave que finalmente me funcionó. Cita:

Puede reutilizar la información de una sesión SSL ya establecida para crear una nueva conexión SSL. Debido a que la nueva conexión SSL es reutilizando el mismo secreto principal, el protocolo de enlace SSL se puede realizar más rápidamente. Como resultado, la reanudación de la sesión SSL puede reducir la carga de un servidor que acepta muchas conexiones SSL.

Así que aquí es cómo me este trabajo con refuerzo de ASIO:

  • configuración de la toma de corriente normal de SSL de control (un montón de ejemplos, incluyendo esta pregunta)
  • cuando se necesita para configurar la segunda SSL toma de datos, haga lo siguiente:

    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); 

Eso es todo. En este punto, no es necesario llamar a sslSocket2.handshake(). Simplemente lea y escriba en el socket sabiendo que la conexión ha sido establecida.

+1

También vea: http://stackoverflow.com/questions/7786352/ssl-session-resume-on-ftp-transfer-connection-with-openssl –

+0

Probablemente quiera llamar a sslSocket2.async_handshake en lugar de llamar directamente a SSL_connect si está utilizando funciones asincrónicas, async_handshake llama a SSL_connect internamente. – John

Cuestiones relacionadas