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 */
245260static 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 */
274290static 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