1From 879f7080d7e141f415c79eaa3a8ac4a3dad0348b Mon Sep 17 00:00:00 2001 2From: Pauli <pauli@openssl.org> 3Date: Wed, 8 Mar 2023 15:28:20 +1100 4Subject: [PATCH] x509: excessive resource use verifying policy constraints 5 6A security vulnerability has been identified in all supported versions 7of OpenSSL related to the verification of X.509 certificate chains 8that include policy constraints. Attackers may be able to exploit this 9vulnerability by creating a malicious certificate chain that triggers 10exponential use of computational resources, leading to a denial-of-service 11(DoS) attack on affected systems. 12 13Fixes CVE-2023-0464 14 15Reviewed-by: Tomas Mraz <tomas@openssl.org> 16Reviewed-by: Shane Lontis <shane.lontis@oracle.com> 17(Merged from https://github.com/openssl/openssl/pull/20569) 18--- 19 crypto/x509v3/pcy_local.h | 8 +++++++- 20 crypto/x509v3/pcy_node.c | 12 +++++++++--- 21 crypto/x509v3/pcy_tree.c | 37 +++++++++++++++++++++++++++---------- 22 3 files changed, 43 insertions(+), 14 deletions(-) 23 24diff --git a/crypto/x509v3/pcy_local.h b/crypto/x509v3/pcy_local.h 25index 5daf78de45..344aa06765 100644 26--- a/crypto/x509v3/pcy_local.h 27+++ b/crypto/x509v3/pcy_local.h 28@@ -111,6 +111,11 @@ struct X509_POLICY_LEVEL_st { 29 }; 30 31 struct X509_POLICY_TREE_st { 32+ /* The number of nodes in the tree */ 33+ size_t node_count; 34+ /* The maximum number of nodes in the tree */ 35+ size_t node_maximum; 36+ 37 /* This is the tree 'level' data */ 38 X509_POLICY_LEVEL *levels; 39 int nlevel; 40@@ -159,7 +164,8 @@ X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk, 41 X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, 42 X509_POLICY_DATA *data, 43 X509_POLICY_NODE *parent, 44- X509_POLICY_TREE *tree); 45+ X509_POLICY_TREE *tree, 46+ int extra_data); 47 void policy_node_free(X509_POLICY_NODE *node); 48 int policy_node_match(const X509_POLICY_LEVEL *lvl, 49 const X509_POLICY_NODE *node, const ASN1_OBJECT *oid); 50diff --git a/crypto/x509v3/pcy_node.c b/crypto/x509v3/pcy_node.c 51index e2d7b15322..d574fb9d66 100644 52--- a/crypto/x509v3/pcy_node.c 53+++ b/crypto/x509v3/pcy_node.c 54@@ -59,10 +59,15 @@ X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, 55 X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, 56 X509_POLICY_DATA *data, 57 X509_POLICY_NODE *parent, 58- X509_POLICY_TREE *tree) 59+ X509_POLICY_TREE *tree, 60+ int extra_data) 61 { 62 X509_POLICY_NODE *node; 63 64+ /* Verify that the tree isn't too large. This mitigates CVE-2023-0464 */ 65+ if (tree->node_maximum > 0 && tree->node_count >= tree->node_maximum) 66+ return NULL; 67+ 68 node = OPENSSL_zalloc(sizeof(*node)); 69 if (node == NULL) { 70 X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE); 71@@ -70,7 +75,7 @@ X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, 72 } 73 node->data = data; 74 node->parent = parent; 75- if (level) { 76+ if (level != NULL) { 77 if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) { 78 if (level->anyPolicy) 79 goto node_error; 80@@ -90,7 +95,7 @@ X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, 81 } 82 } 83 84- if (tree) { 85+ if (extra_data) { 86 if (tree->extra_data == NULL) 87 tree->extra_data = sk_X509_POLICY_DATA_new_null(); 88 if (tree->extra_data == NULL){ 89@@ -103,6 +108,7 @@ X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, 90 } 91 } 92 93+ tree->node_count++; 94 if (parent) 95 parent->nchild++; 96 97diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c 98index 6e8322cbc5..6c7fd35405 100644 99--- a/crypto/x509v3/pcy_tree.c 100+++ b/crypto/x509v3/pcy_tree.c 101@@ -13,6 +13,18 @@ 102 103 #include "pcy_local.h" 104 105+/* 106+ * If the maximum number of nodes in the policy tree isn't defined, set it to 107+ * a generous default of 1000 nodes. 108+ * 109+ * Defining this to be zero means unlimited policy tree growth which opens the 110+ * door on CVE-2023-0464. 111+ */ 112+ 113+#ifndef OPENSSL_POLICY_TREE_NODES_MAX 114+# define OPENSSL_POLICY_TREE_NODES_MAX 1000 115+#endif 116+ 117 /* 118 * Enable this to print out the complete policy tree at various point during 119 * evaluation. 120@@ -168,6 +180,9 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, 121 return X509_PCY_TREE_INTERNAL; 122 } 123 124+ /* Limit the growth of the tree to mitigate CVE-2023-0464 */ 125+ tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX; 126+ 127 /* 128 * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. 129 * 130@@ -184,7 +199,7 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, 131 level = tree->levels; 132 if ((data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0)) == NULL) 133 goto bad_tree; 134- if (level_add_node(level, data, NULL, tree) == NULL) { 135+ if (level_add_node(level, data, NULL, tree, 1) == NULL) { 136 policy_data_free(data); 137 goto bad_tree; 138 } 139@@ -243,7 +258,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, 140 * Return value: 1 on success, 0 otherwise 141 */ 142 static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, 143- X509_POLICY_DATA *data) 144+ X509_POLICY_DATA *data, 145+ X509_POLICY_TREE *tree) 146 { 147 X509_POLICY_LEVEL *last = curr - 1; 148 int i, matched = 0; 149@@ -253,13 +269,13 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, 150 X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i); 151 152 if (policy_node_match(last, node, data->valid_policy)) { 153- if (level_add_node(curr, data, node, NULL) == NULL) 154+ if (level_add_node(curr, data, node, tree, 0) == NULL) 155 return 0; 156 matched = 1; 157 } 158 } 159 if (!matched && last->anyPolicy) { 160- if (level_add_node(curr, data, last->anyPolicy, NULL) == NULL) 161+ if (level_add_node(curr, data, last->anyPolicy, tree, 0) == NULL) 162 return 0; 163 } 164 return 1; 165@@ -272,7 +288,8 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, 166 * Return value: 1 on success, 0 otherwise. 167 */ 168 static int tree_link_nodes(X509_POLICY_LEVEL *curr, 169- const X509_POLICY_CACHE *cache) 170+ const X509_POLICY_CACHE *cache, 171+ X509_POLICY_TREE *tree) 172 { 173 int i; 174 175@@ -280,7 +297,7 @@ static int tree_link_nodes(X509_POLICY_LEVEL *curr, 176 X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i); 177 178 /* Look for matching nodes in previous level */ 179- if (!tree_link_matching_nodes(curr, data)) 180+ if (!tree_link_matching_nodes(curr, data, tree)) 181 return 0; 182 } 183 return 1; 184@@ -311,7 +328,7 @@ static int tree_add_unmatched(X509_POLICY_LEVEL *curr, 185 /* Curr may not have anyPolicy */ 186 data->qualifier_set = cache->anyPolicy->qualifier_set; 187 data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; 188- if (level_add_node(curr, data, node, tree) == NULL) { 189+ if (level_add_node(curr, data, node, tree, 1) == NULL) { 190 policy_data_free(data); 191 return 0; 192 } 193@@ -373,7 +390,7 @@ static int tree_link_any(X509_POLICY_LEVEL *curr, 194 } 195 /* Finally add link to anyPolicy */ 196 if (last->anyPolicy && 197- level_add_node(curr, cache->anyPolicy, last->anyPolicy, NULL) == NULL) 198+ level_add_node(curr, cache->anyPolicy, last->anyPolicy, tree, 0) == NULL) 199 return 0; 200 return 1; 201 } 202@@ -555,7 +572,7 @@ static int tree_calculate_user_set(X509_POLICY_TREE *tree, 203 extra->qualifier_set = anyPolicy->data->qualifier_set; 204 extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS 205 | POLICY_DATA_FLAG_EXTRA_NODE; 206- node = level_add_node(NULL, extra, anyPolicy->parent, tree); 207+ node = level_add_node(NULL, extra, anyPolicy->parent, tree, 1); 208 } 209 if (!tree->user_policies) { 210 tree->user_policies = sk_X509_POLICY_NODE_new_null(); 211@@ -582,7 +599,7 @@ static int tree_evaluate(X509_POLICY_TREE *tree) 212 213 for (i = 1; i < tree->nlevel; i++, curr++) { 214 cache = policy_cache_set(curr->cert); 215- if (!tree_link_nodes(curr, cache)) 216+ if (!tree_link_nodes(curr, cache, tree)) 217 return X509_PCY_TREE_INTERNAL; 218 219 if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) 220-- 2212.34.1 222 223