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.
This commit is contained in:
yhirose committed 2026-10-21 23:28:19 -04:00
1 parent 3599533c24
commit 3b8b9cf9d5
2 files changed
+22 -12

No files matched your search

+11 -12
View File
@@ -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; } if (!detail::ensure_mbedtls_psa_crypto()) { return nullptr; }
#endif #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; auto *ca_chain = new (std::nothrow) mbedtls_x509_crt;
if (!ca_chain) { return nullptr; } if (!ca_chain) { return nullptr; }
mbedtls_x509_crt_init(ca_chain); mbedtls_x509_crt_init(ca_chain);
// mbedtls_x509_crt_parse expects null-terminated PEM auto ret = mbedtls_x509_crt_parse(
int ret = mbedtls_x509_crt_parse(ca_chain, ca_chain, reinterpret_cast<const unsigned char *>(pem_str.c_str()),
reinterpret_cast<const unsigned char *>(pem), pem_str.size() + 1);
len + 1); // +1 for null terminator
if (ret != 0) { if (ret != 0) {
// Try without +1 in case PEM is already null-terminated mbedtls_x509_crt_free(ca_chain);
ret = mbedtls_x509_crt_parse( delete ca_chain;
ca_chain, reinterpret_cast<const unsigned char *>(pem), len); return nullptr;
if (ret != 0) {
mbedtls_x509_crt_free(ca_chain);
delete ca_chain;
return nullptr;
}
} }
return static_cast<ca_store_t>(ca_chain); return static_cast<ca_store_t>(ca_chain);
+11
View File
@@ -18304,6 +18304,17 @@ TEST(SSLClientTest, EmptyCustomCaKeepsSystemCasOut) {
} }
#endif #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 // enable_system_ca(false) prevents system CA loading entirely
TEST(SSLClientTest, DisableSystemCa_Online) { TEST(SSLClientTest, DisableSystemCa_Online) {
SSLClient cli("google.com"); SSLClient cli("google.com");