Complete server certificate updates on every backend

OpenSSL allowed client-initiated renegotiation, which runs a handshake
update_certs_pem() does not wait for, and kept sessions and ticket keys
across a change of client CAs, so a client verified under the old ones
could resume. wolfSSL added new client CAs to the old instead of
replacing them, and a bad certificate or key left Mbed TLS and wolfSSL
half updated.

Turn renegotiation off, forget the sessions and ticket keys on a client
CA change, replace wolfSSL's CAs, and check new material before swapping
it in. Note that the update must not be called from a TLS callback.
This commit is contained in:
yhirose committed 2026-10-16 16:39:00 -04:00
1 parent 314e5577b8
commit fcf7568230
4 files changed
+103 -15

No files matched your search

+32
View File
@@ -4777,6 +4777,38 @@ TEST(SSLClientServerTest, UpdateCertsPemWithClientAuth) {
EXPECT_EQ("ok", res->body);
}
TEST(SSLClientServerTest, UpdateCertsPemReplacesClientCA) {
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE);
ASSERT_TRUE(svr.is_valid());
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");
};
ASSERT_TRUE(get());
// A CA that did not sign the client's certificate takes the old one's place.
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(SERVER_CERT2_FILE, ca_pem);
ASSERT_TRUE(
svr.update_certs_pem(cert_pem.c_str(), key_pem.c_str(), ca_pem.c_str()));
EXPECT_FALSE(get());
}
TEST(SSLClientServerTest, UpdateCertsPemWaitsForHandshakeInProgress) {
SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(svr.is_valid());