소스 검색

Read a NUL-terminated client CA in SSLServer::PemMemory

SSLServer::PemMemory takes a length of 0 to mean a NUL-terminated
string for cert_pem and key_pem, but skipped client_ca_pem when its
length was 0, so a server given its client CA that way started without
requiring client certificates. Read the client CA under the same rule
as the other fields. An empty client CA now fails to load instead of
turning the check off, and the README documents the length-0 rule.
yhirose 2 일 전
부모
커밋
71b5f0a1c8
3개의 변경된 파일과 20개의 추가작업 그리고 6개의 파일을 삭제
  1. 2 0
      README.md
  2. 4 2
      httplib.h
  3. 14 4
      test/test.cc

+ 2 - 0
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

+ 4 - 2
httplib.h

@@ -18824,8 +18824,10 @@ inline SSLServer::SSLServer(const PemMemory &pem) {
       last_ssl_error_ = static_cast<int>(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<int>(get_error());
         free_context(ctx_);
         ctx_ = nullptr;

+ 14 - 4
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