Guard against DoS in name constraints handling.
[openssl.git] / crypto / x509v3 / v3_ncons.c
index 7731bac..561128e 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "e_os.h"               /* for strncasecmp */
 #include "internal/cryptlib.h"
+#include <limits.h>
 #include <stdio.h>
 #include "internal/asn1_int.h"
 #include <openssl/asn1t.h>
@@ -166,6 +167,22 @@ static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
     return 1;
 }
 
+#define NAME_CHECK_MAX (1 << 20)
+
+static int add_lengths(int *out, int a, int b)
+{
+    /* sk_FOO_num(NULL) returns -1 but is effectively 0 when iterating. */
+    if (a < 0)
+        a = 0;
+    if (b < 0)
+        b = 0;
+
+    if (a > INT_MAX - b)
+        return 0;
+    *out = a + b;
+    return 1;
+}
+
 /*-
  * Check a certificate conforms to a specified set of constraints.
  * Return values:
@@ -180,11 +197,23 @@ static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
 
 int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc)
 {
-    int r, i;
+    int r, i, name_count, constraint_count;
     X509_NAME *nm;
 
     nm = X509_get_subject_name(x);
 
+    /*
+     * Guard against certificates with an excessive number of names or
+     * constraints causing a computationally expensive name constraints check.
+     */
+    if (!add_lengths(&name_count, X509_NAME_entry_count(nm),
+                     sk_GENERAL_NAME_num(x->altname))
+        || !add_lengths(&constraint_count,
+                        sk_GENERAL_SUBTREE_num(nc->permittedSubtrees),
+                        sk_GENERAL_SUBTREE_num(nc->excludedSubtrees))
+        || (name_count > 0 && constraint_count > NAME_CHECK_MAX / name_count))
+        return X509_V_ERR_UNSPECIFIED;
+
     if (X509_NAME_entry_count(nm) > 0) {
         GENERAL_NAME gntmp;
         gntmp.type = GEN_DIRNAME;