Keep the system CAs out when a custom CA comes through empty

Under the default system CA policy, a custom CA given to a client keeps
the system CAs out. SSLClient and WebSocketClient only noted the custom
CA when set_ca_cert_store() got a store or load_ca_cert_store() got some
bytes, so a NULL store, such as the one tls::create_ca_store() returns
for a PEM it cannot parse, or an empty PEM left the client trusting
every system CA instead. Note the custom CA on every call, so that such
a client fails verification. A redirect still passes a CA on only when
the original client had one.
This commit is contained in:
yhirose committed 2026-10-21 17:11:52 -04:00
1 parent 8772d10c90
commit 6304fc6abb
2 files changed
+49 -9

No files matched your search

+32
View File
@@ -70,6 +70,7 @@ namespace tls {
// live below the split border; the definitions are linked from httplib.cc.
ca_store_t create_ca_store(const char *pem, size_t len);
bool set_verify_callback(ctx_t ctx, VerifyCallback callback);
std::vector<std::string> get_ca_names(ctx_t ctx);
} // namespace tls
} // namespace httplib
#endif
@@ -18157,6 +18158,37 @@ TEST(SSLClientTest, IpHostUntrustedChainFails) {
ASSERT_FALSE(res);
}
#ifndef CPPHTTPLIB_WOLFSSL_SUPPORT
// A custom CA that brings no certificate still keeps the system CAs out, so a
// CA that failed to come through fails verification instead of trusting them.
// (wolfSSL does not list the system CAs it loaded.)
TEST(SSLClientTest, EmptyCustomCaKeepsSystemCasOut) {
SSLServer svr(SERVER_CERT2_FILE, SERVER_PRIVATE_KEY_FILE);
ASSERT_TRUE(svr.is_valid());
auto port = svr.bind_to_any_port("127.0.0.1");
ASSERT_LT(0, port);
thread t = thread([&] { svr.listen_after_bind(); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
});
svr.wait_until_ready();
// The CAs a client trusts once its first request has loaded them
auto loaded_cas = [&](const std::function<void(Client &)> &setup) {
Client cli("https://127.0.0.1:" + std::to_string(port));
setup(cli);
cli.Get("/");
return tls::get_ca_names(cli.tls_context()).size();
};
EXPECT_EQ(0u, loaded_cas([](Client &cli) { cli.load_ca_cert_store("", 0); }));
EXPECT_EQ(0u,
loaded_cas([](Client &cli) { cli.set_ca_cert_store(nullptr); }));
}
#endif
// enable_system_ca(false) prevents system CA loading entirely
TEST(SSLClientTest, DisableSystemCa_Online) {
SSLClient cli("google.com");