Skip to content

Commit 879f708

Browse files
committed
x509: excessive resource use verifying policy constraints
A security vulnerability has been identified in all supported versions of OpenSSL related to the verification of X.509 certificate chains that include policy constraints. Attackers may be able to exploit this vulnerability by creating a malicious certificate chain that triggers exponential use of computational resources, leading to a denial-of-service (DoS) attack on affected systems. Fixes CVE-2023-0464 Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from #20569)
1 parent 9693273 commit 879f708

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

crypto/x509v3/pcy_local.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ struct X509_POLICY_LEVEL_st {
111111
};
112112

113113
struct X509_POLICY_TREE_st {
114+
/* The number of nodes in the tree */
115+
size_t node_count;
116+
/* The maximum number of nodes in the tree */
117+
size_t node_maximum;
118+
114119
/* This is the tree 'level' data */
115120
X509_POLICY_LEVEL *levels;
116121
int nlevel;
@@ -159,7 +164,8 @@ X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk,
159164
X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
160165
X509_POLICY_DATA *data,
161166
X509_POLICY_NODE *parent,
162-
X509_POLICY_TREE *tree);
167+
X509_POLICY_TREE *tree,
168+
int extra_data);
163169
void policy_node_free(X509_POLICY_NODE *node);
164170
int policy_node_match(const X509_POLICY_LEVEL *lvl,
165171
const X509_POLICY_NODE *node, const ASN1_OBJECT *oid);

crypto/x509v3/pcy_node.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,23 @@ X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level,
5959
X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
6060
X509_POLICY_DATA *data,
6161
X509_POLICY_NODE *parent,
62-
X509_POLICY_TREE *tree)
62+
X509_POLICY_TREE *tree,
63+
int extra_data)
6364
{
6465
X509_POLICY_NODE *node;
6566

67+
/* Verify that the tree isn't too large. This mitigates CVE-2023-0464 */
68+
if (tree->node_maximum > 0 && tree->node_count >= tree->node_maximum)
69+
return NULL;
70+
6671
node = OPENSSL_zalloc(sizeof(*node));
6772
if (node == NULL) {
6873
X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE);
6974
return NULL;
7075
}
7176
node->data = data;
7277
node->parent = parent;
73-
if (level) {
78+
if (level != NULL) {
7479
if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
7580
if (level->anyPolicy)
7681
goto node_error;
@@ -90,7 +95,7 @@ X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
9095
}
9196
}
9297

93-
if (tree) {
98+
if (extra_data) {
9499
if (tree->extra_data == NULL)
95100
tree->extra_data = sk_X509_POLICY_DATA_new_null();
96101
if (tree->extra_data == NULL){
@@ -103,6 +108,7 @@ X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
103108
}
104109
}
105110

111+
tree->node_count++;
106112
if (parent)
107113
parent->nchild++;
108114

crypto/x509v3/pcy_tree.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@
1313

1414
#include "pcy_local.h"
1515

16+
/*
17+
* If the maximum number of nodes in the policy tree isn't defined, set it to
18+
* a generous default of 1000 nodes.
19+
*
20+
* Defining this to be zero means unlimited policy tree growth which opens the
21+
* door on CVE-2023-0464.
22+
*/
23+
24+
#ifndef OPENSSL_POLICY_TREE_NODES_MAX
25+
# define OPENSSL_POLICY_TREE_NODES_MAX 1000
26+
#endif
27+
1628
/*
1729
* Enable this to print out the complete policy tree at various point during
1830
* evaluation.
@@ -168,6 +180,9 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
168180
return X509_PCY_TREE_INTERNAL;
169181
}
170182

183+
/* Limit the growth of the tree to mitigate CVE-2023-0464 */
184+
tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX;
185+
171186
/*
172187
* http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3.
173188
*
@@ -184,7 +199,7 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
184199
level = tree->levels;
185200
if ((data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0)) == NULL)
186201
goto bad_tree;
187-
if (level_add_node(level, data, NULL, tree) == NULL) {
202+
if (level_add_node(level, data, NULL, tree, 1) == NULL) {
188203
policy_data_free(data);
189204
goto bad_tree;
190205
}
@@ -243,7 +258,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
243258
* Return value: 1 on success, 0 otherwise
244259
*/
245260
static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
246-
X509_POLICY_DATA *data)
261+
X509_POLICY_DATA *data,
262+
X509_POLICY_TREE *tree)
247263
{
248264
X509_POLICY_LEVEL *last = curr - 1;
249265
int i, matched = 0;
@@ -253,13 +269,13 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
253269
X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i);
254270

255271
if (policy_node_match(last, node, data->valid_policy)) {
256-
if (level_add_node(curr, data, node, NULL) == NULL)
272+
if (level_add_node(curr, data, node, tree, 0) == NULL)
257273
return 0;
258274
matched = 1;
259275
}
260276
}
261277
if (!matched && last->anyPolicy) {
262-
if (level_add_node(curr, data, last->anyPolicy, NULL) == NULL)
278+
if (level_add_node(curr, data, last->anyPolicy, tree, 0) == NULL)
263279
return 0;
264280
}
265281
return 1;
@@ -272,15 +288,16 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
272288
* Return value: 1 on success, 0 otherwise.
273289
*/
274290
static int tree_link_nodes(X509_POLICY_LEVEL *curr,
275-
const X509_POLICY_CACHE *cache)
291+
const X509_POLICY_CACHE *cache,
292+
X509_POLICY_TREE *tree)
276293
{
277294
int i;
278295

279296
for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) {
280297
X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i);
281298

282299
/* Look for matching nodes in previous level */
283-
if (!tree_link_matching_nodes(curr, data))
300+
if (!tree_link_matching_nodes(curr, data, tree))
284301
return 0;
285302
}
286303
return 1;
@@ -311,7 +328,7 @@ static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
311328
/* Curr may not have anyPolicy */
312329
data->qualifier_set = cache->anyPolicy->qualifier_set;
313330
data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
314-
if (level_add_node(curr, data, node, tree) == NULL) {
331+
if (level_add_node(curr, data, node, tree, 1) == NULL) {
315332
policy_data_free(data);
316333
return 0;
317334
}
@@ -373,7 +390,7 @@ static int tree_link_any(X509_POLICY_LEVEL *curr,
373390
}
374391
/* Finally add link to anyPolicy */
375392
if (last->anyPolicy &&
376-
level_add_node(curr, cache->anyPolicy, last->anyPolicy, NULL) == NULL)
393+
level_add_node(curr, cache->anyPolicy, last->anyPolicy, tree, 0) == NULL)
377394
return 0;
378395
return 1;
379396
}
@@ -555,7 +572,7 @@ static int tree_calculate_user_set(X509_POLICY_TREE *tree,
555572
extra->qualifier_set = anyPolicy->data->qualifier_set;
556573
extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
557574
| POLICY_DATA_FLAG_EXTRA_NODE;
558-
node = level_add_node(NULL, extra, anyPolicy->parent, tree);
575+
node = level_add_node(NULL, extra, anyPolicy->parent, tree, 1);
559576
}
560577
if (!tree->user_policies) {
561578
tree->user_policies = sk_X509_POLICY_NODE_new_null();
@@ -582,7 +599,7 @@ static int tree_evaluate(X509_POLICY_TREE *tree)
582599

583600
for (i = 1; i < tree->nlevel; i++, curr++) {
584601
cache = policy_cache_set(curr->cert);
585-
if (!tree_link_nodes(curr, cache))
602+
if (!tree_link_nodes(curr, cache, tree))
586603
return X509_PCY_TREE_INTERNAL;
587604

588605
if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)

0 commit comments

Comments
 (0)