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 類型。