6363
6464#include "pcy_int.h"
6565
66+ /*
67+ * If the maximum number of nodes in the policy tree isn't defined, set it to
68+ * a generous default of 1000 nodes.
69+ *
70+ * Defining this to be zero means unlimited policy tree growth which opens the
71+ * door on CVE-2023-0464.
72+ */
73+
74+ #ifndef OPENSSL_POLICY_TREE_NODES_MAX
75+ # define OPENSSL_POLICY_TREE_NODES_MAX 1000
76+ #endif
77+
6678/*
6779 * Enable this to print out the complete policy tree at various point during
6880 * evaluation.
@@ -225,6 +237,10 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
225237 if (!tree )
226238 return 0 ;
227239
240+ /* Limit the growth of the tree to mitigate CVE-2023-0464 */
241+ tree -> node_maximum = OPENSSL_POLICY_TREE_NODES_MAX ;
242+ tree -> node_count = 0 ;
243+
228244 tree -> flags = 0 ;
229245 tree -> levels = OPENSSL_malloc (sizeof (X509_POLICY_LEVEL ) * n );
230246 tree -> nlevel = 0 ;
@@ -247,7 +263,7 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
247263
248264 data = policy_data_new (NULL , OBJ_nid2obj (NID_any_policy ), 0 );
249265
250- if (!data || !level_add_node (level , data , NULL , tree ))
266+ if (!data || !level_add_node (level , data , NULL , tree , 1 ))
251267 goto bad_tree ;
252268
253269 for (i = n - 2 ; i >= 0 ; i -- ) {
@@ -304,7 +320,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
304320}
305321
306322static int tree_link_matching_nodes (X509_POLICY_LEVEL * curr ,
307- const X509_POLICY_DATA * data )
323+ const X509_POLICY_DATA * data ,
324+ X509_POLICY_TREE * tree )
308325{
309326 X509_POLICY_LEVEL * last = curr - 1 ;
310327 X509_POLICY_NODE * node ;
@@ -313,13 +330,13 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
313330 for (i = 0 ; i < sk_X509_POLICY_NODE_num (last -> nodes ); i ++ ) {
314331 node = sk_X509_POLICY_NODE_value (last -> nodes , i );
315332 if (policy_node_match (last , node , data -> valid_policy )) {
316- if (! level_add_node (curr , data , node , NULL ) )
333+ if (level_add_node (curr , data , node , tree , 0 ) == NULL )
317334 return 0 ;
318335 matched = 1 ;
319336 }
320337 }
321338 if (!matched && last -> anyPolicy ) {
322- if (! level_add_node (curr , data , last -> anyPolicy , NULL ) )
339+ if (level_add_node (curr , data , last -> anyPolicy , tree , 0 ) == NULL )
323340 return 0 ;
324341 }
325342 return 1 ;
@@ -331,7 +348,8 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
331348 */
332349
333350static int tree_link_nodes (X509_POLICY_LEVEL * curr ,
334- const X509_POLICY_CACHE * cache )
351+ const X509_POLICY_CACHE * cache ,
352+ X509_POLICY_TREE * tree )
335353{
336354 int i ;
337355 X509_POLICY_DATA * data ;
@@ -352,7 +370,7 @@ static int tree_link_nodes(X509_POLICY_LEVEL *curr,
352370 continue ;
353371#endif
354372 /* Look for matching nodes in previous level */
355- if (!tree_link_matching_nodes (curr , data ))
373+ if (!tree_link_matching_nodes (curr , data , tree ))
356374 return 0 ;
357375 }
358376 return 1 ;
@@ -382,7 +400,7 @@ static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
382400 /* Curr may not have anyPolicy */
383401 data -> qualifier_set = cache -> anyPolicy -> qualifier_set ;
384402 data -> flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS ;
385- if (! level_add_node (curr , data , node , tree ) ) {
403+ if (level_add_node (curr , data , node , tree , 1 ) == NULL ) {
386404 policy_data_free (data );
387405 return 0 ;
388406 }
@@ -464,18 +482,17 @@ static int tree_link_any(X509_POLICY_LEVEL *curr,
464482 /* Curr may not have anyPolicy */
465483 data -> qualifier_set = cache -> anyPolicy -> qualifier_set ;
466484 data -> flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS ;
467- if (!level_add_node (curr , data , node , tree )) {
485+ if (!level_add_node (curr , data , node , tree , 1 )) {
468486 policy_data_free (data );
469487 return 0 ;
470488 }
471489#endif
472490
473491 }
474492 /* Finally add link to anyPolicy */
475- if (last -> anyPolicy ) {
476- if (!level_add_node (curr , cache -> anyPolicy , last -> anyPolicy , NULL ))
477- return 0 ;
478- }
493+ if (last -> anyPolicy &&
494+ level_add_node (curr , cache -> anyPolicy , last -> anyPolicy , tree , 0 ) == NULL )
495+ return 0 ;
479496 return 1 ;
480497}
481498
@@ -646,7 +663,7 @@ static int tree_calculate_user_set(X509_POLICY_TREE *tree,
646663 extra -> qualifier_set = anyPolicy -> data -> qualifier_set ;
647664 extra -> flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
648665 | POLICY_DATA_FLAG_EXTRA_NODE ;
649- node = level_add_node (NULL , extra , anyPolicy -> parent , tree );
666+ node = level_add_node (NULL , extra , anyPolicy -> parent , tree , 1 );
650667 }
651668 if (!tree -> user_policies ) {
652669 tree -> user_policies = sk_X509_POLICY_NODE_new_null ();
@@ -668,7 +685,7 @@ static int tree_evaluate(X509_POLICY_TREE *tree)
668685
669686 for (i = 1 ; i < tree -> nlevel ; i ++ , curr ++ ) {
670687 cache = policy_cache_set (curr -> cert );
671- if (!tree_link_nodes (curr , cache ))
688+ if (!tree_link_nodes (curr , cache , tree ))
672689 return 0 ;
673690
674691 if (!(curr -> flags & X509_V_FLAG_INHIBIT_ANY )
0 commit comments