]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
vtls: pinned key check
authorStefan Eissing <stefan@eissing.org>
Fri, 14 Nov 2025 14:25:04 +0000 (15:25 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 14 Nov 2025 16:01:44 +0000 (17:01 +0100)
Cleanup the vtls pinned key matching somewhat. Add a DEBUGF
for pinned key hashes that do not match, so we can see in
traces what was going on.

Ref #19489
Closes #19529

lib/vtls/vtls.c

index 3858cad98312487f4f24ec25cb77c90a1edfe37f..918a4686fcbc414e855d76493f92ea1d003da36e 100644 (file)
@@ -772,8 +772,9 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
   /* only do this if pinnedpubkey starts with "sha256//", length 8 */
   if(!strncmp(pinnedpubkey, "sha256//", 8)) {
     CURLcode encode;
-    size_t encodedlen = 0;
-    char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos;
+    char *cert_hash = NULL;
+    const char *pinned_hash, *end_pos;
+    size_t cert_hash_len = 0, pinned_hash_len;
     unsigned char *sha256sumdigest;
 
     if(!Curl_ssl->sha256sum) {
@@ -790,50 +791,37 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
 
     if(!encode)
       encode = curlx_base64_encode((char *)sha256sumdigest,
-                                   CURL_SHA256_DIGEST_LENGTH, &encoded,
-                                   &encodedlen);
+                                   CURL_SHA256_DIGEST_LENGTH,
+                                   &cert_hash, &cert_hash_len);
     Curl_safefree(sha256sumdigest);
 
     if(encode)
       return encode;
 
-    infof(data, " public key hash: sha256//%s", encoded);
+    infof(data, " public key hash: sha256//%s", cert_hash);
 
-    /* it starts with sha256//, copy so we can modify it */
-    pinkeycopy = strdup(pinnedpubkey);
-    if(!pinkeycopy) {
-      Curl_safefree(encoded);
-      return CURLE_OUT_OF_MEMORY;
-    }
-    /* point begin_pos to the copy, and start extracting keys */
-    begin_pos = pinkeycopy;
-    do {
-      end_pos = strstr(begin_pos, ";sha256//");
-      /*
-       * if there is an end_pos, null-terminate, otherwise it will go to the
-       * end of the original string
-       */
-      if(end_pos)
-        end_pos[0] = '\0';
-
-      /* compare base64 sha256 digests, 8 is the length of "sha256//" */
-      if(encodedlen == strlen(begin_pos + 8) &&
-         !memcmp(encoded, begin_pos + 8, encodedlen)) {
+    pinned_hash = pinnedpubkey;
+    while(pinned_hash &&
+          !strncmp(pinned_hash, "sha256//", (sizeof("sha256//")-1))) {
+      pinned_hash = pinned_hash + (sizeof("sha256//")-1);
+      end_pos = strchr(pinned_hash, ';');
+      pinned_hash_len = end_pos ?
+                        (size_t)(end_pos - pinned_hash) : strlen(pinned_hash);
+
+      /* compare base64 sha256 digests" */
+      if(cert_hash_len == pinned_hash_len &&
+         !memcmp(cert_hash, pinned_hash, cert_hash_len)) {
+        DEBUGF(infof(data, "public key hash matches pinned value"));
         result = CURLE_OK;
         break;
       }
 
-      /*
-       * change back the null-terminator we changed earlier,
-       * and look for next begin
-       */
-      if(end_pos) {
-        end_pos[0] = ';';
-        begin_pos = strstr(end_pos, "sha256//");
-      }
-    } while(end_pos && begin_pos);
-    Curl_safefree(encoded);
-    Curl_safefree(pinkeycopy);
+      DEBUGF(infof(data, "public key hash does not match 'sha256//%.*s'",
+                   (int)pinned_hash_len, pinned_hash));
+      /* next one or we are at the end */
+      pinned_hash = end_pos ? (end_pos + 1) : NULL;
+    }
+    Curl_safefree(cert_hash);
   }
   else {
     long filesize;