提升ASIO:SSL握手()永远不会完成

时间:2012-03-04 10:46:52

标签: c++ sockets ssl boost-asio

我有一个C ++客户端应用程序,它使用Boost ASIO与各种服务器建立SSL连接。但是对于2个特定服务器,无法建立SSL连接。它挂起在boost::asio::ssl::stream::handshake()的调用中。

我使用Wireshark来观察客户端和服务器之间的对话。一个有效的SSL连接似乎是这样做的:

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

...此时ASIO handshake()调用返回表明一切正常,SSL套接字连接正常。

但是对于2个不同的服务器[*],握手看起来像这样:

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

查看这些服务器上的日志文件,似乎在握手中发送了最初的209个字节之后,服务器认为SSL连接已完全建立。但是客户端仍然在Boost ASIO handshake()调用中,并且在重置连接时最终返回ec = 104。

所以我想也许有不同类型的SSL握手,也许我应该使用“更简单”的那种?

[*]我知道有人会想知道:客户端应用程序导致此问题的服务器之一是FileZilla Server for Windows设置使用SSL / TLS [FTPS],另一个是在Linux上运行的专有服务。)


更新:Sam Miller要求我发布我的代码,描述如何设置ssl上下文:

类(.hpp文件)包含:

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;

构造函数具有以下初始值设定项:

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

...而且这段代码:

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

这是建立SSL套接字并且握手挂起的代码:

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

1 个答案:

答案 0 :(得分:9)

我明白了。这个SSL教程(http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html)包含了最终为我工作的密钥。引用:

  

您可以重复使用已建立的SSL会话中的信息   创建新的SSL连接。因为新的SSL连接是   重用相同的主密钥,可以执行SSL握手   更快速。因此,SSL会话恢复可以减少负载   接受许多SSL连接的服务器。

以下是我如何使用Boost ASIO:

  • 设置正常的SSL控制套接字(很多示例,包括此问题)
  • 当您需要设置第二个SSL数据套接字时,请执行以下操作:

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

就是这样。此时,无需调用sslSocket2.handshake()。知道连接已经建立,只需读取和写入套接字。