Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost ASIO: SSL handshake() never finishes

I have a C++ client app that uses Boost ASIO to make SSL connections to various servers. But against 2 specific servers, the SSL connection cannot be established. It hangs in the call to boost::asio::ssl::stream::handshake().

I've used Wireshark to observe the conversation between client and server. A working SSL connection seems to do this:

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

...and at this point the ASIO handshake() call returns indicating all is well, and the SSL socket connection works fine.

But against 2 different servers [*], the handshake looks like this:

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

Looking at log files on these servers, it seems as if after the initial 209 bytes are sent in the handshake, the server considered the SSL connection fully established. But the client is still sitting in the Boost ASIO handshake() call, and eventually returns ec=104 when the connection is reset.

So I'm thinking maybe there are different types of SSL handshakes, and maybe there is a "simpler" one I should be using?

[*] I know someone will want to know: one of the servers causing this problem with the client app is FileZilla Server for Windows setup to use SSL/TLS [FTPS], and the other is a proprietary service running on Linux.)


UPDATE: Sam Miller asked that I post my code describing how the ssl context is setup:

Class (.hpp file) contains this:

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 has these initializers:

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

...and this code:

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

And this is the code where the SSL socket is established and the handshake hangs:

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";
like image 489
Stéphane Avatar asked Mar 04 '12 10:03

Stéphane


1 Answers

I figured it out. This SSL tutorial (http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html) contained the key that finally got this working for me. Quote:

You can reuse the information from an already established SSL session to create a new SSL connection. Because the new SSL connection is reusing the same master secret, the SSL handshake can be performed more quickly. As a result, SSL session resumption can reduce the load of a server that is accepting many SSL connections.

So here is how I got this working with Boost ASIO:

  • setup the normal SSL control socket (lots of examples, including this question)
  • when you need to setup the 2nd SSL data socket, do this:

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

That's it. At this point, no need to call sslSocket2.handshake(). Just read and write to the socket knowing the connection has been established.

like image 119
Stéphane Avatar answered Sep 28 '22 04:09

Stéphane