diff --git a/README.md b/README.md index 50db44d2..4fe8b8d3 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,8 @@ client_pem.key_pem_len = client_key.size(); httplib::SSLClient cli("api.example.com", 443, client_pem); ``` +A length of 0 means the field is a NUL-terminated string. + `httplib::ws::WebSocketClient` has the same `PemMemory` constructor for `wss://` connections. See [README-websocket.md](README-websocket.md) for details. ### Peer Certificate Inspection diff --git a/httplib.h b/httplib.h index aecb8e95..88b306fb 100644 --- a/httplib.h +++ b/httplib.h @@ -18824,8 +18824,10 @@ inline SSLServer::SSLServer(const PemMemory &pem) { last_ssl_error_ = static_cast(get_error()); free_context(ctx_); ctx_ = nullptr; - } else if (pem.client_ca_pem && pem.client_ca_pem_len > 0) { - if (!load_ca_pem(ctx_, pem.client_ca_pem, pem.client_ca_pem_len)) { + } else if (pem.client_ca_pem) { + auto ca_len = pem.client_ca_pem_len ? pem.client_ca_pem_len + : strlen(pem.client_ca_pem); + if (!load_ca_pem(ctx_, pem.client_ca_pem, ca_len)) { last_ssl_error_ = static_cast(get_error()); free_context(ctx_); ctx_ = nullptr; diff --git a/test/test.cc b/test/test.cc index 99f67136..aa73f965 100644 --- a/test/test.cc +++ b/test/test.cc @@ -16309,7 +16309,8 @@ TEST(SSLClientServerTest, PemMemoryClientEncryptedCertPresent) { CLIENT_ENCRYPTED_PRIVATE_KEY_PASS); } -// A server built from PEM memory with a client CA requires client certificates +// A server built from PEM memory with a client CA requires client certificates, +// also when the CA is a NUL-terminated string passed with a length of 0 TEST(SSLClientServerTest, PemMemoryClientCertMissing) { std::string server_cert_pem, server_key_pem, client_ca_pem; read_file(SERVER_CERT_FILE, server_cert_pem); @@ -16325,9 +16326,18 @@ TEST(SSLClientServerTest, PemMemoryClientCertMissing) { client_ca_pem.size(), nullptr // no password for server key }; - SSLServer svr(server_pem); - ASSERT_TRUE(svr.is_valid()); - RejectsClientWithoutCert(svr); + for (auto client_ca_pem_len : {client_ca_pem.size(), size_t{0}}) { + SCOPED_TRACE(client_ca_pem_len); + server_pem.client_ca_pem_len = client_ca_pem_len; + SSLServer svr(server_pem); + ASSERT_TRUE(svr.is_valid()); + RejectsClientWithoutCert(svr); + } + + // An empty CA fails to load instead of turning the check off + server_pem.client_ca_pem = ""; + server_pem.client_ca_pem_len = 0; + EXPECT_FALSE(SSLServer(server_pem).is_valid()); } // The PemMemory lengths are honoured, so the PEM needs no NUL terminator