]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
vtls: handle possible malicious certs_num from peer
authorx2018 <xkernel.wang@foxmail.com>
Fri, 7 Nov 2025 12:51:22 +0000 (20:51 +0800)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 8 Nov 2025 09:33:06 +0000 (10:33 +0100)
For GnuTLS, mbedTLS, Rustls, Schannel and wolfSSL

This check was previously added for OpenSSL in 3df71e6dc23e80466c2d448

Closes #19397

lib/vtls/gtls.c
lib/vtls/mbedtls.c
lib/vtls/openssl.c
lib/vtls/rustls.c
lib/vtls/schannel.c
lib/vtls/vtls.h
lib/vtls/wolfssl.c

index ebd2c8de1eb0c95c0ddf609ebd1869c9bcfdc410..34d9b84d7914b34204391d14630356016f393f02 100644 (file)
@@ -1618,19 +1618,27 @@ Curl_gtls_verifyserver(struct Curl_cfilter *cf,
   }
 
   if(data->set.ssl.certinfo && chain.certs) {
-    unsigned int i;
-
-    result = Curl_ssl_init_certinfo(data, (int)chain.num_certs);
-    if(result)
+    if(chain.num_certs > MAX_ALLOWED_CERT_AMOUNT) {
+      failf(data, "%u certificates is more than allowed (%u)",
+            chain.num_certs, MAX_ALLOWED_CERT_AMOUNT);
+      result = CURLE_SSL_CONNECT_ERROR;
       goto out;
+    }
+    else {
+      unsigned int i;
 
-    for(i = 0; i < chain.num_certs; i++) {
-      const char *beg = (const char *) chain.certs[i].data;
-      const char *end = beg + chain.certs[i].size;
-
-      result = Curl_extract_certinfo(data, (int)i, beg, end);
+      result = Curl_ssl_init_certinfo(data, (int)chain.num_certs);
       if(result)
         goto out;
+
+      for(i = 0; i < chain.num_certs; i++) {
+        const char *beg = (const char *) chain.certs[i].data;
+        const char *end = beg + chain.certs[i].size;
+
+        result = Curl_extract_certinfo(data, (int)i, beg, end);
+        if(result)
+          goto out;
+      }
     }
   }
 
index 36200de6fa6f9745ae9c595199c89c270c7b501d..f5302499bdd74d2173d86352b7ddd5bf94fe49d5 100644 (file)
@@ -475,10 +475,19 @@ mbed_extract_certinfo(struct Curl_easy *data, const mbedtls_x509_crt *crt)
 {
   CURLcode result;
   const mbedtls_x509_crt *cur;
+  int cert_count = 0;
   int i;
 
-  for(i = 0, cur = crt; cur; ++i, cur = cur->next);
-  result = Curl_ssl_init_certinfo(data, i);
+  for(cur = crt; cur && cert_count <= MAX_ALLOWED_CERT_AMOUNT; cur = cur->next)
+    cert_count++;
+
+  if(cert_count > MAX_ALLOWED_CERT_AMOUNT) {
+    infof(data, "Certificates is more than allowed (%u), skipping certinfo",
+          MAX_ALLOWED_CERT_AMOUNT);
+    return;
+  }
+
+  result = Curl_ssl_init_certinfo(data, cert_count);
 
   for(i = 0, cur = crt; result == CURLE_OK && cur; ++i, cur = cur->next) {
     const char *beg = (const char *) cur->raw.p;
index 87b00cc252a94ed9fb0182608e10c49e45d035b3..59fd0cbd6de5b390db091dc612e488fde8927889 100644 (file)
@@ -349,8 +349,6 @@ static CURLcode X509V3_ext(struct Curl_easy *data,
   return result;
 }
 
-#define MAX_ALLOWED_CERT_AMOUNT 100
-
 static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
 {
   CURLcode result;
index ecf4d03152535541c7bbf1bfe8ea71be7031c47c..262f016f9fea15fa0e552cf0d640aa9fb508b075 100644 (file)
@@ -1211,8 +1211,13 @@ cr_connect(struct Curl_cfilter *cf,
       if(data->set.ssl.certinfo) {
         size_t num_certs = 0;
         size_t i;
-        while(rustls_connection_get_peer_certificate(rconn, (int)num_certs)) {
+        while(rustls_connection_get_peer_certificate(rconn, num_certs)) {
           num_certs++;
+          if(num_certs > MAX_ALLOWED_CERT_AMOUNT) {
+            failf(data, "%zu certificates is more than allowed (%u)",
+                  num_certs, MAX_ALLOWED_CERT_AMOUNT);
+            return CURLE_SSL_CONNECT_ERROR;
+          }
         }
         result = Curl_ssl_init_certinfo(data, (int)num_certs);
         if(result)
index f9d697bbb8448cc41a65d4b8bdb191e45868b7bd..c96e0df77b50c4a1df3ad337f7d4ce3ad6e72615 100644 (file)
@@ -1478,6 +1478,8 @@ cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order,
   (void)reverse_order;
   if(valid_cert_encoding(ccert_context))
     (*(int *)certs_count)++;
+  if(*(int *)certs_count > MAX_ALLOWED_CERT_AMOUNT)
+    return FALSE;
   return TRUE;
 }
 
@@ -1623,6 +1625,12 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
     }
 
     traverse_cert_store(ccert_context, cert_counter_callback, &certs_count);
+    if(certs_count > MAX_ALLOWED_CERT_AMOUNT) {
+      failf(data, "%d certificates is more than allowed (%u)",
+            certs_count, MAX_ALLOWED_CERT_AMOUNT);
+      CertFreeCertificateContext(ccert_context);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
 
     result = Curl_ssl_init_certinfo(data, certs_count);
     if(!result) {
index 180333e63cc8f83dca00bdf3233f5cb80fe1713e..dbe13c59030bba4fcb7ec47d4389076619eca4cd 100644 (file)
@@ -165,6 +165,7 @@ void Curl_ssl_version(char *buffer, size_t size);
 
 /* Certificate information list handling. */
 #define CURL_X509_STR_MAX  100000
+#define MAX_ALLOWED_CERT_AMOUNT 100
 
 void Curl_ssl_free_certinfo(struct Curl_easy *data);
 CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num);
index 19e8c5558aec3c8fe376b444342e5b60817b9a5c..585a4060021dd1f8cd9a5563b8e9667d3f3762f6 100644 (file)
@@ -1512,9 +1512,13 @@ wssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
     wolfSSL_set_bio(wssl->ssl, bio, bio);
   }
 #else /* USE_BIO_CHAIN */
+  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+  if(sockfd > INT_MAX) {
+    failf(data, "SSL: socket value too large");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
   /* pass the raw socket into the SSL layer */
-  if(!wolfSSL_set_fd(wssl->ssl,
-                     (int)Curl_conn_cf_get_socket(cf, data))) {
+  if(!wolfSSL_set_fd(wssl->ssl, (int)sockfd)) {
     failf(data, "SSL: wolfSSL_set_fd failed");
     return CURLE_SSL_CONNECT_ERROR;
   }