c++ - Boost ASIO: SSL handshake() nunca termina
sockets boost-asio (1)
Me lo imaginé. Este tutorial de SSL ( http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html ) contenía la clave que finalmente funcionaba para mí. Citar:
Puede volver a utilizar 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 está 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 lo hice trabajando con Boost ASIO:
- configure el socket de control SSL normal (muchos ejemplos, incluida esta pregunta)
- cuando necesite configurar el segundo socket de datos SSL, haga esto:
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. 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.
Tengo una aplicación de 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 para boost::asio::ssl::stream::handshake()
.
He usado Wireshark para observar la conversación entre el cliente y el servidor. Una conexión SSL operativa 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, la llamada ASIO handshake()
devuelve que todo está bien, y la conexión de socket SSL funciona bien.
Pero frente a 2 servidores diferentes [*], el saludo de mano se ve así:
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
Al observar los archivos de registro en estos servidores, parece que después de enviar los 209 bytes iniciales en el protocolo de enlace, el servidor consideró que la conexión SSL estaba 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 causa 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 en Linux.)
ACTUALIZACIÓN: Sam Miller me pidió que publicara mi código describiendo cómo se configura el contexto de SSL:
La clase (archivo .hpp) contiene esto:
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 estos 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 donde se establece el socket SSL y se cuelga el handshake:
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";