From 3b8b9cf9d53668b3dc1fd045352d927b132ea57f Mon Sep 17 00:00:00 2001 From: yhirose Date: Wed, 21 Oct 2026 23:28:19 -0400 Subject: [PATCH] Parse a CA store PEM through a NUL-terminated copy on Mbed TLS tls::create_ca_store() on Mbed TLS parsed the caller's buffer with one byte more than its length, so it read past the end of the buffer, and when that byte was not a NUL the PEM was not recognized and the call returned NULL. Parse a NUL-terminated copy instead, as load_ca_pem() does. DER input still parses, since its own length ends it. --- httplib.h | 23 +++++++++++------------ test/test.cc | 11 +++++++++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/httplib.h b/httplib.h index 666cd9d3..bfc322c2 100644 --- a/httplib.h +++ b/httplib.h @@ -21986,24 +21986,23 @@ inline ca_store_t create_ca_store(const char *pem, size_t len) { if (!detail::ensure_mbedtls_psa_crypto()) { return nullptr; } #endif + if (!pem) { return nullptr; } + + // mbedtls_x509_crt_parse expects null-terminated PEM + std::string pem_str(pem, len); + auto *ca_chain = new (std::nothrow) mbedtls_x509_crt; if (!ca_chain) { return nullptr; } mbedtls_x509_crt_init(ca_chain); - // mbedtls_x509_crt_parse expects null-terminated PEM - int ret = mbedtls_x509_crt_parse(ca_chain, - reinterpret_cast(pem), - len + 1); // +1 for null terminator + auto ret = mbedtls_x509_crt_parse( + ca_chain, reinterpret_cast(pem_str.c_str()), + pem_str.size() + 1); if (ret != 0) { - // Try without +1 in case PEM is already null-terminated - ret = mbedtls_x509_crt_parse( - ca_chain, reinterpret_cast(pem), len); - if (ret != 0) { - mbedtls_x509_crt_free(ca_chain); - delete ca_chain; - return nullptr; - } + mbedtls_x509_crt_free(ca_chain); + delete ca_chain; + return nullptr; } return static_cast(ca_chain); diff --git a/test/test.cc b/test/test.cc index f426c5d5..78d273c9 100644 --- a/test/test.cc +++ b/test/test.cc @@ -18304,6 +18304,17 @@ TEST(SSLClientTest, EmptyCustomCaKeepsSystemCasOut) { } #endif +// A PEM given to create_ca_store() needs no NUL after it +TEST(SSLClientTest, CreateCaStoreFromPemWithoutNul) { + std::string pem; + read_file(SERVER_CERT2_FILE, pem); + auto buf = pem + "X"; + auto store = tls::create_ca_store(buf.data(), pem.size()); + EXPECT_TRUE(store != nullptr); + SSLClient cli("localhost"); + cli.set_ca_cert_store(store); +} + // enable_system_ca(false) prevents system CA loading entirely TEST(SSLClientTest, DisableSystemCa_Online) { SSLClient cli("google.com");