From d00af3f4e6ef9ab968016c35e5013b291448611f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 17 Oct 2026 03:35:14 +0000 Subject: [PATCH] Test client cert rejection for PEM memory servers and update_certs_pem Split the rejection scenario out of ClientCertMissing so it can run against any server, then use it to check that a server built from PemMemory with a client CA, and a server whose certificates were replaced with update_certs_pem, both reject a client without a certificate. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01WGAYpQgXt95LdDQcJYgjB8 --- test/test.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/test/test.cc b/test/test.cc index b2bcbe3e..98ad3cc1 100644 --- a/test/test.cc +++ b/test/test.cc @@ -16097,12 +16097,9 @@ TEST(SSLClientServerTest, ClientEncryptedCertPresent) { CLIENT_ENCRYPTED_PRIVATE_KEY_PASS); } -void ClientCertMissing(const ClientCertServerSetup &setup = nullptr) { - SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE, - CLIENT_CA_CERT_DIR); - ASSERT_TRUE(svr.is_valid()); - if (setup) { setup(svr); } - +// Expects svr, which must require client certificates, to reject a client +// that has none +void RejectsClientWithoutCert(SSLServer &svr) { svr.Get("/test", [](const Request &, Response &) { FAIL(); }); auto port = svr.bind_to_any_port(HOST); @@ -16137,6 +16134,14 @@ void ClientCertMissing(const ClientCertServerSetup &setup = nullptr) { if (res.error() == Error::Write) { EXPECT_NE(0, res.ssl_error()); } } +void ClientCertMissing(const ClientCertServerSetup &setup = nullptr) { + SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE, + CLIENT_CA_CERT_DIR); + ASSERT_TRUE(svr.is_valid()); + if (setup) { setup(svr); } + RejectsClientWithoutCert(svr); +} + TEST(SSLClientServerTest, ClientCertMissing) { ClientCertMissing(); } // A server that requires client certificates must keep requiring them after a @@ -16162,6 +16167,18 @@ TEST(SSLClientServerTest, ClientCertStillRequiredAfterVerifyCallbackCleared) { ClientCertStillRequired(true); } +// Replacing the certificates must not stop the server requiring client ones +TEST(SSLClientServerTest, ClientCertStillRequiredAfterUpdateCertsPem) { + ClientCertMissing([](SSLServer &svr) { + std::string cert_pem, key_pem, ca_pem; + read_file(SERVER_CERT_FILE, cert_pem); + read_file(SERVER_PRIVATE_KEY_FILE, key_pem); + read_file(CLIENT_CA_CERT_FILE, ca_pem); + ASSERT_TRUE(svr.update_certs_pem(cert_pem.c_str(), key_pem.c_str(), + ca_pem.c_str())); + }); +} + // A TLS error from one request must not show up in a later request's Result TEST(SSLClientServerTest, SSLErrorNotCarriedToLaterRequest) { SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE); @@ -16263,6 +16280,27 @@ TEST(SSLClientServerTest, PemMemoryClientEncryptedCertPresent) { CLIENT_ENCRYPTED_PRIVATE_KEY_PASS); } +// A server built from PEM memory with a client CA requires client certificates +TEST(SSLClientServerTest, PemMemoryClientCertMissing) { + std::string server_cert_pem, server_key_pem, client_ca_pem; + read_file(SERVER_CERT_FILE, server_cert_pem); + read_file(SERVER_PRIVATE_KEY_FILE, server_key_pem); + read_file(CLIENT_CA_CERT_FILE, client_ca_pem); + + SSLServer::PemMemory server_pem = { + server_cert_pem.c_str(), + server_cert_pem.size(), + server_key_pem.c_str(), + server_key_pem.size(), + client_ca_pem.c_str(), + client_ca_pem.size(), + nullptr // no password for server key + }; + SSLServer svr(server_pem); + ASSERT_TRUE(svr.is_valid()); + RejectsClientWithoutCert(svr); +} + TEST(SSLClientServerTest, TrustDirOptional) { SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE); ASSERT_TRUE(svr.is_valid());