diff --git a/README-websocket.md b/README-websocket.md index 223af7b7..96748cb9 100644 --- a/README-websocket.md +++ b/README-websocket.md @@ -204,6 +204,10 @@ void set_ca_cert_path(const std::string &ca_cert_file_path, void set_ca_cert_store(tls::ca_store_t store); void enable_server_certificate_verification(bool enabled); void enable_server_hostname_verification(bool enabled); +// The same verifiers as SSLClient's, e.g. to pin the server's certificate +void set_server_certificate_verifier(tls::VerifyCallback verifier); +void set_session_verifier( + std::function verifier); ``` ## Examples diff --git a/httplib.h b/httplib.h index 717cd72f..89403dae 100644 --- a/httplib.h +++ b/httplib.h @@ -4670,6 +4670,9 @@ public: void enable_server_certificate_verification(bool enabled); void enable_server_hostname_verification(bool enabled); void enable_system_ca(bool enabled); + void set_server_certificate_verifier(tls::VerifyCallback verifier); + void set_session_verifier( + std::function verifier); #endif private: @@ -4717,6 +4720,7 @@ private: SystemCAMode system_ca_mode_ = SystemCAMode::Auto; bool server_certificate_verification_ = true; bool server_hostname_verification_ = true; + std::function session_verifier_; #endif }; @@ -23360,6 +23364,7 @@ inline bool WebSocketClient::create_stream(std::unique_ptr &strm, detail::ClientTlsSessionOptions options; options.server_hostname_verification = server_hostname_verification_; + options.session_verifier = session_verifier_; detail::ClientTlsSessionError tls_error; if (!detail::setup_client_tls_session(host_, tls_ctx_, tls_session_, sock_, @@ -23544,6 +23549,16 @@ WebSocketClient::set_ca_cert_path(const std::string &ca_cert_file_path, ca_cert_dir_path_ = ca_cert_dir_path; } +inline void +WebSocketClient::set_server_certificate_verifier(tls::VerifyCallback verifier) { + if (tls_ctx_) { tls::set_verify_callback(tls_ctx_, std::move(verifier)); } +} + +inline void WebSocketClient::set_session_verifier( + std::function verifier) { + session_verifier_ = std::move(verifier); +} + inline void WebSocketClient::set_ca_cert_store(tls::ca_store_t store) { if (store && tls_ctx_) { // set_ca_store takes ownership of store diff --git a/test/test.cc b/test/test.cc index 9cd1b6cf..870e0633 100644 --- a/test/test.cc +++ b/test/test.cc @@ -27003,6 +27003,37 @@ protected: int port_ = 0; }; +TEST_F(WebSocketSSLIntegrationTest, VerifiersDecide) { + auto url = "wss://localhost:" + std::to_string(port_) + "/ws-echo"; + { + ws::WebSocketClient client(url); + client.enable_server_certificate_verification(false); + auto calls = 0; + client.set_server_certificate_verifier([&](const tls::VerifyContext &) { + calls++; + return false; + }); + EXPECT_FALSE(client.connect()); + EXPECT_GT(calls, 0); + } + { + ws::WebSocketClient client(url); + client.enable_server_certificate_verification(false); + client.set_session_verifier([](tls::session_t) { + return SSLVerifierResponse::CertificateRejected; + }); + EXPECT_FALSE(client.connect()); + } + { + ws::WebSocketClient client(url); + client.enable_server_certificate_verification(false); + client.set_session_verifier([](tls::session_t) { + return SSLVerifierResponse::CertificateAccepted; + }); + EXPECT_TRUE(client.connect()); + } +} + TEST_F(WebSocketSSLIntegrationTest, TextEcho) { ws::WebSocketClient client("wss://localhost:" + std::to_string(port_) + "/ws-echo");