]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/x509/pcy_tree.c
x509: excessive resource use verifying policy constraints
[thirdparty/openssl.git] / crypto / x509 / pcy_tree.c
index 4b954b07768e2f80af1780dc3d31bf46dc7b6cf2..95fb46f4ec911db821429cf904dea97e2aa85a97 100644 (file)
 
 #include "pcy_local.h"
 
+/*
+ * If the maximum number of nodes in the policy tree isn't defined, set it to
+ * a generous default of 1000 nodes.
+ *
+ * Defining this to be zero means unlimited policy tree growth which opens the
+ * door on CVE-2023-0464.
+ */
+#ifndef OPENSSL_POLICY_TREE_NODES_MAX
+# define OPENSSL_POLICY_TREE_NODES_MAX 1000
+#endif
+
 static void expected_print(BIO *channel,
                            X509_POLICY_LEVEL *lev, X509_POLICY_NODE *node,
                            int indent)
@@ -161,6 +172,9 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
     if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL)
         return X509_PCY_TREE_INTERNAL;
 
+    /* Limit the growth of the tree to mitigate CVE-2023-0464 */
+    tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX;
+
     /*
      * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3.
      *
@@ -177,7 +191,7 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
     if ((data = ossl_policy_data_new(NULL,
                                      OBJ_nid2obj(NID_any_policy), 0)) == NULL)
         goto bad_tree;
-    if (ossl_policy_level_add_node(level, data, NULL, tree) == NULL) {
+    if (ossl_policy_level_add_node(level, data, NULL, tree, 1) == NULL) {
         ossl_policy_data_free(data);
         goto bad_tree;
     }
@@ -236,7 +250,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
  * Return value: 1 on success, 0 otherwise
  */
 static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
-                                    X509_POLICY_DATA *data)
+                                    X509_POLICY_DATA *data,
+                                    X509_POLICY_TREE *tree)
 {
     X509_POLICY_LEVEL *last = curr - 1;
     int i, matched = 0;
@@ -246,13 +261,13 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
         X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i);
 
         if (ossl_policy_node_match(last, node, data->valid_policy)) {
-            if (ossl_policy_level_add_node(curr, data, node, NULL) == NULL)
+            if (ossl_policy_level_add_node(curr, data, node, tree, 0) == NULL)
                 return 0;
             matched = 1;
         }
     }
     if (!matched && last->anyPolicy) {
-        if (ossl_policy_level_add_node(curr, data, last->anyPolicy, NULL) == NULL)
+        if (ossl_policy_level_add_node(curr, data, last->anyPolicy, tree, 0) == NULL)
             return 0;
     }
     return 1;
@@ -265,7 +280,8 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
  * Return value: 1 on success, 0 otherwise.
  */
 static int tree_link_nodes(X509_POLICY_LEVEL *curr,
-                           const X509_POLICY_CACHE *cache)
+                           const X509_POLICY_CACHE *cache,
+                           X509_POLICY_TREE *tree)
 {
     int i;
 
@@ -273,7 +289,7 @@ static int tree_link_nodes(X509_POLICY_LEVEL *curr,
         X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i);
 
         /* Look for matching nodes in previous level */
-        if (!tree_link_matching_nodes(curr, data))
+        if (!tree_link_matching_nodes(curr, data, tree))
             return 0;
     }
     return 1;
@@ -304,7 +320,7 @@ static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
     /* Curr may not have anyPolicy */
     data->qualifier_set = cache->anyPolicy->qualifier_set;
     data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
-    if (ossl_policy_level_add_node(curr, data, node, tree) == NULL) {
+    if (ossl_policy_level_add_node(curr, data, node, tree, 1) == NULL) {
         ossl_policy_data_free(data);
         return 0;
     }
@@ -367,7 +383,7 @@ static int tree_link_any(X509_POLICY_LEVEL *curr,
     /* Finally add link to anyPolicy */
     if (last->anyPolicy &&
             ossl_policy_level_add_node(curr, cache->anyPolicy,
-                                       last->anyPolicy, NULL) == NULL)
+                                       last->anyPolicy, tree, 0) == NULL)
         return 0;
     return 1;
 }
@@ -550,7 +566,7 @@ static int tree_calculate_user_set(X509_POLICY_TREE *tree,
             extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
                 | POLICY_DATA_FLAG_EXTRA_NODE;
             node = ossl_policy_level_add_node(NULL, extra, anyPolicy->parent,
-                                              tree);
+                                              tree, 1);
         }
         if (!tree->user_policies) {
             tree->user_policies = sk_X509_POLICY_NODE_new_null();
@@ -577,7 +593,7 @@ static int tree_evaluate(X509_POLICY_TREE *tree)
 
     for (i = 1; i < tree->nlevel; i++, curr++) {
         cache = ossl_policy_cache_set(curr->cert);
-        if (!tree_link_nodes(curr, cache))
+        if (!tree_link_nodes(curr, cache, tree))
             return X509_PCY_TREE_INTERNAL;
 
         if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)