14
14
15
15
#include "pcy_local.h"
16
16
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
+
17
28
static void expected_print (BIO * channel ,
18
29
X509_POLICY_LEVEL * lev , X509_POLICY_NODE * node ,
19
30
int indent )
@@ -163,6 +174,9 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
163
174
return X509_PCY_TREE_INTERNAL ;
164
175
}
165
176
177
+ /* Limit the growth of the tree to mitigate CVE-2023-0464 */
178
+ tree -> node_maximum = OPENSSL_POLICY_TREE_NODES_MAX ;
179
+
166
180
/*
167
181
* http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3.
168
182
*
@@ -180,7 +194,7 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
180
194
if ((data = ossl_policy_data_new (NULL ,
181
195
OBJ_nid2obj (NID_any_policy ), 0 )) == NULL )
182
196
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 ) {
184
198
ossl_policy_data_free (data );
185
199
goto bad_tree ;
186
200
}
@@ -239,7 +253,8 @@ static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
239
253
* Return value: 1 on success, 0 otherwise
240
254
*/
241
255
static int tree_link_matching_nodes (X509_POLICY_LEVEL * curr ,
242
- X509_POLICY_DATA * data )
256
+ X509_POLICY_DATA * data ,
257
+ X509_POLICY_TREE * tree )
243
258
{
244
259
X509_POLICY_LEVEL * last = curr - 1 ;
245
260
int i , matched = 0 ;
@@ -249,13 +264,13 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
249
264
X509_POLICY_NODE * node = sk_X509_POLICY_NODE_value (last -> nodes , i );
250
265
251
266
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 )
253
268
return 0 ;
254
269
matched = 1 ;
255
270
}
256
271
}
257
272
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 )
259
274
return 0 ;
260
275
}
261
276
return 1 ;
@@ -268,15 +283,16 @@ static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
268
283
* Return value: 1 on success, 0 otherwise.
269
284
*/
270
285
static 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 )
272
288
{
273
289
int i ;
274
290
275
291
for (i = 0 ; i < sk_X509_POLICY_DATA_num (cache -> data ); i ++ ) {
276
292
X509_POLICY_DATA * data = sk_X509_POLICY_DATA_value (cache -> data , i );
277
293
278
294
/* Look for matching nodes in previous level */
279
- if (!tree_link_matching_nodes (curr , data ))
295
+ if (!tree_link_matching_nodes (curr , data , tree ))
280
296
return 0 ;
281
297
}
282
298
return 1 ;
@@ -307,7 +323,7 @@ static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
307
323
/* Curr may not have anyPolicy */
308
324
data -> qualifier_set = cache -> anyPolicy -> qualifier_set ;
309
325
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 ) {
311
327
ossl_policy_data_free (data );
312
328
return 0 ;
313
329
}
@@ -370,7 +386,7 @@ static int tree_link_any(X509_POLICY_LEVEL *curr,
370
386
/* Finally add link to anyPolicy */
371
387
if (last -> anyPolicy &&
372
388
ossl_policy_level_add_node (curr , cache -> anyPolicy ,
373
- last -> anyPolicy , NULL ) == NULL )
389
+ last -> anyPolicy , tree , 0 ) == NULL )
374
390
return 0 ;
375
391
return 1 ;
376
392
}
@@ -553,7 +569,7 @@ static int tree_calculate_user_set(X509_POLICY_TREE *tree,
553
569
extra -> flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
554
570
| POLICY_DATA_FLAG_EXTRA_NODE ;
555
571
node = ossl_policy_level_add_node (NULL , extra , anyPolicy -> parent ,
556
- tree );
572
+ tree , 1 );
557
573
}
558
574
if (!tree -> user_policies ) {
559
575
tree -> user_policies = sk_X509_POLICY_NODE_new_null ();
@@ -580,7 +596,7 @@ static int tree_evaluate(X509_POLICY_TREE *tree)
580
596
581
597
for (i = 1 ; i < tree -> nlevel ; i ++ , curr ++ ) {
582
598
cache = ossl_policy_cache_set (curr -> cert );
583
- if (!tree_link_nodes (curr , cache ))
599
+ if (!tree_link_nodes (curr , cache , tree ))
584
600
return X509_PCY_TREE_INTERNAL ;
585
601
586
602
if (!(curr -> flags & X509_V_FLAG_INHIBIT_ANY )
0 commit comments