我有一个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";
答案 0 :(得分:9)
我明白了。这个SSL教程(http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html)包含了最终为我工作的密钥。引用:
您可以重复使用已建立的SSL会话中的信息 创建新的SSL连接。因为新的SSL连接是 重用相同的主密钥,可以执行SSL握手 更快速。因此,SSL会话恢复可以减少负载 接受许多SSL连接的服务器。
以下是我如何使用Boost ASIO:
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()。知道连接已经建立,只需读取和写入套接字。