1414
1515#include "pcy_local.h"
1616
17+ /*
18+ * If the maximum number of nodes in the policy tree isn't defined, set it to
19+ * a generous default of 1000 nodes.
20+ *
21+ * Defining this to be zero means unlimited policy tree growth which opens the
22+ * door on CVE-2023-0464.
23+ */
24+ #ifndef OPENSSL_POLICY_TREE_NODES_MAX
25+ # define OPENSSL_POLICY_TREE_NODES_MAX 1000
26+ #endif
27+
1728static void expected_print (BIO * channel ,
1829 X509_POLICY_LEVEL * lev , X509_POLICY_NODE * node ,
1930 int indent )
@@ -163,6 +174,9 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
163174 return X509_PCY_TREE_INTERNAL ;
164175 }
165176
177+ /* Limit the growth of the tree to mitigate CVE-2023-0464 */
178+ tree -> node_maximum = OPENSSL_POLICY_TREE_NODES_MAX ;
179+
166180 /*
167181 * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3.
168182 *
@@ -180,7 +194,7 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
180194 if ((data = ossl_policy_data_new (NULL ,
181195 OBJ_nid2obj (NID_any_policy ), 0 )) == NULL )
182196 goto bad_tree ;
183- if (ossl_policy_level_add_node (level , data , NULL , tree ) == NULL ) {
197+ if (ossl_policy_level_add_node (level , data , NULL , tree , 1 ) == NULL ) {
184198 ossl_policy_data_free (data );
185199 goto bad_tree ;
186200 }
@@ -239,7 +253,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
239253 * Return value: 1 on success, 0 otherwise
240254 */
241255static int tree_link_matching_nodes (X509_POLICY_LEVEL * curr ,
242- X509_POLICY_DATA * data )
256+ X509_POLICY_DATA * data ,
257+ X509_POLICY_TREE * tree )
243258{
244259 X509_POLICY_LEVEL * last = curr - 1 ;
245260 int i , matched = 0 ;
@@ -249,13 +264,13 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
249264 X509_POLICY_NODE * node = sk_X509_POLICY_NODE_value (last -> nodes , i );
250265
251266 if (ossl_policy_node_match (last , node , data -> valid_policy )) {
252- if (ossl_policy_level_add_node (curr , data , node , NULL ) == NULL )
267+ if (ossl_policy_level_add_node (curr , data , node , tree , 0 ) == NULL )
253268 return 0 ;
254269 matched = 1 ;
255270 }
256271 }
257272 if (!matched && last -> anyPolicy ) {
258- if (ossl_policy_level_add_node (curr , data , last -> anyPolicy , NULL ) == NULL )
273+ if (ossl_policy_level_add_node (curr , data , last -> anyPolicy , tree , 0 ) == NULL )
259274 return 0 ;
260275 }
261276 return 1 ;
@@ -268,15 +283,16 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
268283 * Return value: 1 on success, 0 otherwise.
269284 */
270285static int tree_link_nodes (X509_POLICY_LEVEL * curr ,
271- const X509_POLICY_CACHE * cache )
286+ const X509_POLICY_CACHE * cache ,
287+ X509_POLICY_TREE * tree )
272288{
273289 int i ;
274290
275291 for (i = 0 ; i < sk_X509_POLICY_DATA_num (cache -> data ); i ++ ) {
276292 X509_POLICY_DATA * data = sk_X509_POLICY_DATA_value (cache -> data , i );
277293
278294 /* Look for matching nodes in previous level */
279- if (!tree_link_matching_nodes (curr , data ))
295+ if (!tree_link_matching_nodes (curr , data , tree ))
280296 return 0 ;
281297 }
282298 return 1 ;
@@ -307,7 +323,7 @@ static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
307323 /* Curr may not have anyPolicy */
308324 data -> qualifier_set = cache -> anyPolicy -> qualifier_set ;
309325 data -> flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS ;
310- if (ossl_policy_level_add_node (curr , data , node , tree ) == NULL ) {
326+ if (ossl_policy_level_add_node (curr , data , node , tree , 1 ) == NULL ) {
311327 ossl_policy_data_free (data );
312328 return 0 ;
313329 }
@@ -370,7 +386,7 @@ static int tree_link_any(X509_POLICY_LEVEL *curr,
370386 /* Finally add link to anyPolicy */
371387 if (last -> anyPolicy &&
372388 ossl_policy_level_add_node (curr , cache -> anyPolicy ,
373- last -> anyPolicy , NULL ) == NULL )
389+ last -> anyPolicy , tree , 0 ) == NULL )
374390 return 0 ;
375391 return 1 ;
376392}
@@ -553,7 +569,7 @@ static int tree_calculate_user_set(X509_POLICY_TREE *tree,
553569 extra -> flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
554570 | POLICY_DATA_FLAG_EXTRA_NODE ;
555571 node = ossl_policy_level_add_node (NULL , extra , anyPolicy -> parent ,
556- tree );
572+ tree , 1 );
557573 }
558574 if (!tree -> user_policies ) {
559575 tree -> user_policies = sk_X509_POLICY_NODE_new_null ();
@@ -580,7 +596,7 @@ static int tree_evaluate(X509_POLICY_TREE *tree)
580596
581597 for (i = 1 ; i < tree -> nlevel ; i ++ , curr ++ ) {
582598 cache = ossl_policy_cache_set (curr -> cert );
583- if (!tree_link_nodes (curr , cache ))
599+ if (!tree_link_nodes (curr , cache , tree ))
584600 return X509_PCY_TREE_INTERNAL ;
585601
586602 if (!(curr -> flags & X509_V_FLAG_INHIBIT_ANY )
0 commit comments