SSL
Asio提供基础的类模板来支持SSL。这些类允许用户在已经存在的流顶层添加加密通信,比如在TCP socket上加密。
在创建加密流之前,应用必须要构造SSL上下文对象。这个对象被用来设置SSL选项,比如核实模块,文件证书等。客户端的初始化可能像这样实现:
ssl::context ctx(ssl::context::sslv23);
ctx.set_verify_mode(ssl::verify_peer);
ctx.set_verify_file("ca.pam");
在TCP上使用SSL,可以这样写:
ssl::stream<ip::tcp::socket> ssl_sock(my_io_service, ctx);
为了实现socket特有的操作,例如建立出站的连接或者接收外来的连接,底层的socket首先要使用ssl::stream的lowest_layer()函数:
ip::tcp::socket::lowest_layer_type& sock = ssl_sock.lowest_layer();
sock.connect(my_endpoint);
有的时候底层的流对象需要比SSL流更长的生存期,在这种情况下,模板的参数需要使用引用:
ip::tcp::socket sock(my_io_service);
ssl::stream<ip::tcp::socket&> ssl_sock(sock, ctx);
SSL握手必须要优先通过加密连接获取数据。这通过ssl::stream模板的handshake()和async_handshake()函数实现。
一旦连接成功,SSL流对象就变成了同步和异步的输入输出流。这意味着我们又可以用那些自由函数来读写了。
证书验证
Asio提供了多种方法来做SSL证书验证:
ssl::context::set_default_verify_paths()
ssl::context::set_verify_mode()
ssl::context::set_verify_callback()
ssl::context::load_verify_file()
ssl::stream::set_verify_mode()
ssl::stream::set_verify_callback()
为了简化RFC 2818规则(HTTPS的证书验证)的证书验证,Asio提供了一个可复用的验证回调,该回调是一个函数对象:
- ssl::rfc2818_verification
下面的用例展示了远程主机如何做HTTPS验证:
using asio::ip::tcp;
namespace ssl = asio::ssl;
typedef ssl::stream<tcp::socket>
// Create a context that use the defualt paths for
// finding CA certification
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
// Open a socket and connect it to the remote host.
asio::io_service my_io_service;
ssl_socket sock(my_io_service, ctx);
tcp::resolver reslvr(my_io_service);
tcp::resolver::query qery("host.name", "https");
asio::connect(sock.lowest_layer(), reslvr.resolve(qery));
sock.lowest_layer().set_option(tcp::no_delay(true));
// Perform SSL handshake and verify the remote host's
// certification
sock.set_verify_mode(ssl::verify_peer);
sock.set_verify_callback(ssl::rfc2818_verification("host.name"));
sock.handshake(ssl_socket::client);
// ... read and write normal
SSL和线程
SSL流对象是无阻塞设计的,因此,所有的异步SSL操作都要放在一个显式或者隐式的strand里面。当心,这意味着我们不需要在单线程中使用同步事件。(译者注:同步事件会引起阻塞)。
参见
ssl::context, ssl::rfc2818_verification, ssl::stream, SSL example
注意
Asio的SSL需要OpenSSL库的支持,如果应用程序想要使用未被包装过的OpenSSL功能,可以调用ssl::context::native_handle()或者ssl::stream::native_handle()来设置上下文。