如果您可以配置连接的两端,则可以使用空密码。当您创建 boost::asio::ssl::stream 时,仅使用不加密的密码对其进行配置。这可以通过传递封装的 OpenSSL 指针使用 OpenSSL API 来完成:
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslSocket(io, ssl);
SSL_set_cipher_list(sslSocket.native_handle(), "eNULL");
SSL_set_options(sslSocket.native_handle(), SSL_OP_NO_COMPRESSION);
SSL_set_cipher_list() 调用设置允许的密码,"eNULL" 匹配未加密的密码(请参阅OpenSSL ciphers)。 SSL_set_options() 调用关闭了与加密无关的压缩,但在没有压缩的情况下更容易查看线路上的流量。 SSL_OP_NO_COMPRESSION 可能仅适用于 OpenSSL 0.9.9 或更高版本。如果您使用的是较早的 OpenSSL 版本,this page 有一个解决方法来禁用压缩。在连接的一侧禁用压缩就足够了。
eNULL 默认情况下从不启用密码,因此您需要明确配置两端。如果只配置一端,则握手将失败。您可以使用 OpenSSL s_server 命令设置一个简单的测试服务器,如下所示:
openssl s_server -accept 8443 -cert server.pem -key server.pem -cipher eNULL
添加-debug 标志也会转储协议,如果您的客户端禁用了压缩,您应该能够看到纯文本。
这是一个概念验证客户端,它将与上述s_server 命令对话(verify_none 模式用于简单,升级模式用于防止 MITM 攻击):
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
int main() {
boost::asio::io_service io;
boost::asio::ssl::context ssl(io,boost::asio::ssl::context::sslv23);
ssl.set_verify_mode(boost::asio::ssl::context::verify_none);
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslSocket(io, ssl);
SSL_set_cipher_list(sslSocket.native_handle(), "eNULL");
SSL_set_options(sslSocket.native_handle(), SSL_OP_NO_COMPRESSION);
boost::asio::ip::tcp::resolver resolver(io);
boost::asio::ip::tcp::resolver::query query("localhost", "8443");
boost::asio::ip::tcp::resolver::iterator endpoint = resolver.resolve(query);
boost::system::error_code error = boost::asio::error::host_not_found;
while (error && endpoint != boost::asio::ip::tcp::resolver::iterator())
{
sslSocket.lowest_layer().close();
sslSocket.lowest_layer().connect(*endpoint++, error);
}
sslSocket.handshake(boost::asio::ssl::stream_base::client);
boost::asio::write(sslSocket, boost::asio::buffer("how now brown cow\n"));
sslSocket.shutdown(error);
return 0;
}