Keep TLS verify callbacks per context

tls::set_verify_callback(), which set_server_certificate_verifier() uses,
stored the callback in a single thread_local slot shared by every context.
A verifier was skipped when the handshake ran on another thread, ran for
other clients on the thread that set it, and could run after its client
was destroyed.

Store it with the context instead: in SSL_CTX ex_data for OpenSSL, and in
MbedTlsContext and WolfSSLContext for Mbed TLS and wolfSSL.
This commit is contained in:
yhirose committed 2026-10-16 04:55:45 -04:00
1 parent e3749669bc
commit 6fc677444f
2 files changed
+115 -65

No files matched your search

+47
View File
@@ -15659,6 +15659,53 @@ TEST(VerifyCallbackTest, VerifyContextFields) {
EXPECT_TRUE(saw_leaf_cert);
}
// A verifier belongs to the client that set it, not to the thread that set it.
TEST(VerifyCallbackTest, VerifierStaysWithItsClient) {
using namespace httplib::tls;
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(svr.is_valid());
svr.Get("/test", [](const Request &, Response &res) {
res.set_content("ok", "text/plain");
});
auto port = svr.bind_to_any_port(HOST);
thread t([&]() { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
});
svr.wait_until_ready();
auto rejecting_calls = 0;
SSLClient rejecting(HOST, port);
rejecting.enable_server_certificate_verification(false);
rejecting.set_server_certificate_verifier([&](const VerifyContext &) {
rejecting_calls++;
return false;
});
auto accepting_calls = 0;
SSLClient accepting(HOST, port);
accepting.enable_server_certificate_verification(false);
// Set on another thread than the requests below.
thread([&]() {
accepting.set_server_certificate_verifier([&](const VerifyContext &) {
accepting_calls++;
return true;
});
}).join();
// Requested on another thread than the verifier was set on.
thread([&]() { EXPECT_FALSE(rejecting.Get("/test")); }).join();
EXPECT_GT(rejecting_calls, 0);
auto res = accepting.Get("/test");
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
EXPECT_GT(accepting_calls, 0);
}
TEST(TlsVerifyErrorTest, GetVerifyErrorString) {
using httplib::tls::TlsError;