Asio 包含用于基本 SSL 支持的类和类模板。 这些类允许在现有流(例如 TCP 套接字)之上进行加密通信。
在创建一个加密流之前,应用必须构造一个SSL上下文对象。这个对象用来设置SSL选项,例如认证方式,证书文件等等。举个例子,客户端的初始化看起来如下:
ssl::context ctx(ssl::context::sslv23);
ctx.set_verify_mode(ssl::verify_peer);
ctx.load_verify_file("ca.pem");
要在 TCP 套接字中使用 SSL,可以这样写:
ssl::stream<ip::tcp::socket> ssl_sock(my_io_context, ctx);
要执行特定于套接字的操作,例如建立出站连接或接受传入连接,必须首先使用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_context);
ssl::stream<ip::tcp::socket&> ssl_sock(sock, ctx);
SSL 握手必须在通过加密连接传输或接收数据之前执行。 这是使用 ssl::stream
模板的 handshake()
或 async_handshake()
成员函数来完成的。
一旦连接,SSL 流对象将用作同步或异步读写流。 这意味着对象可以与任何 read()、async_read()、write()、async_write()、read_until()
或 async_read_until()
自由函数一起使用。
证书认证
Asio 提供了多种方法来配置 SSL 证书的验证方式:
ssl::context::set_default_verify_paths()
ssl::context::set_verify_mode()
ssl::context::load_verify_file()
ssl::stream::set_verify_mode()
ssl::stream::set_verify_callback()
为了简化根据 RFC 6125(传输层安全上下文中的身份验证)中的规则验证证书的使用场景,Asio 提供了一个可重用的验证回调作为函数对象:
ssl::host_name_verification
以下示例显示了根据 HTTPS 使用的规则验证远程主机的证书:
using boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
typedef ssl::stream<tcp::socket> ssl_socket;
// 使用CE证书的默认路径创建上下文
ssl::context ctx(ssl::context::sslv23);
ctx.set_default_verify_paths();
// 打开一个套接字并连接到远程主机
boost::asio::io_context io_context;
ssl_socket sock(io_context, ctx);
tcp::resolver resolver(io_context);
tcp::resolver::query query("host.name", "https");
boost::asio::connect(sock.lowest_layer(), resolver.resolve(query));
sock.lowest_layer().set_option(tcp::no_delay(true));
// 执行SSL握手并认证远程主机的证书
sock.set_verify_mode(ssl::verify_peer);
sock.set_verify_callback(ssl::host_name_verification("host.name"));
sock.handshake(ssl_socket::client);
// ... read and write as normal ...
SSL和Threads
SSL 流对象不执行自己的锁定。 因此,所有异步 SSL 操作都必须在隐式或显式strand中执行。 请注意,这意味着在单线程程序中不需要同步(因此不会产生锁定开销)。
需要 OpenSSL 才能使用 Asio 的 SSL 支持。 当应用程序需要使用 Asio 未封装的 OpenSSL 功能时,可以通过调用ssl::context::native_handle()
或 ssl::stream::native_handle()
获取底层 OpenSSL 类型。