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

Sté*_*ane 14 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
Run Code Online (Sandbox Code Playgroud)

...此时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
Run Code Online (Sandbox Code Playgroud)

查看这些服务器上的日志文件,似乎在握手中发送了最初的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;
Run Code Online (Sandbox Code Playgroud)

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

ioservice      ( 2 ),
sslcontext     ( ioservice, boost::asio::ssl::context::sslv23 ),
sslDataSocket  ( ioservice, sslcontext ),
Run Code Online (Sandbox Code Playgroud)

......而这段代码:

sslcontext.set_options( boost::asio::ssl::context::default_workarounds |
                        boost::asio::ssl::context::verify_none         );
Run Code Online (Sandbox Code Playgroud)

这是建立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";
Run Code Online (Sandbox Code Playgroud)

Sté*_*ane 10

我想到了.这个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 );
Run Code Online (Sandbox Code Playgroud)

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