Reject a certificate whose verify callback throws

An exception from a verify callback unwound through the TLS library,
which is C: OpenSSL leaked the objects of the handshake, and a server
worker thread ended the process. It also left the handshake count that
update_certs_pem() waits on raised, so with a task queue that caught the
exception, every later update waited forever. Take the exception as a
rejection, and lower the count on every way out of the handshake.
This commit is contained in:
yhirose committed 2026-10-16 23:52:15 -04:00
1 parent 567e099361
commit 645bdab90e
2 files changed
+63 -7

No files matched your search

+40
View File
@@ -4933,6 +4933,46 @@ TEST(SSLClientServerTest, VerifyCallbackKeepsClientCertificateRequired) {
EXPECT_EQ("ok", res->body);
}
TEST(SSLClientServerTest, ThrowingVerifyCallbackRejectsTheCertificate) {
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE);
ASSERT_TRUE(svr.is_valid());
tls::set_verify_callback(svr.tls_context(),
[](const tls::VerifyContext &) -> bool {
throw std::runtime_error("verify");
});
svr.Get("/test", [](const Request &, Response &res) {
res.set_content("ok", "text/plain");
});
thread t = thread([&]() { ASSERT_TRUE(svr.listen(HOST, PORT)); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
auto get = [] {
SSLClient cli(HOST, PORT, CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE);
cli.enable_server_certificate_verification(false);
return cli.Get("/test");
};
EXPECT_FALSE(get());
// The handshake is over, so an update does not wait for it.
std::string cert_pem, key_pem;
read_file(SERVER_CERT_FILE, cert_pem);
read_file(SERVER_PRIVATE_KEY_FILE, key_pem);
EXPECT_TRUE(svr.update_certs_pem(cert_pem.c_str(), key_pem.c_str()));
tls::set_verify_callback(svr.tls_context(), [](const tls::VerifyContext &v) {
return v.preverify_ok;
});
auto res = get();
ASSERT_TRUE(res) << "Error: " << to_string(res.error());
EXPECT_EQ("ok", res->body);
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
// A client that resumes its session gets through, but not once the client CA
// has changed, as a resumed session does not show the certificate again.