Changeset View
Changeset View
Standalone View
Standalone View
crypto/x509/pcy_tree.c
/* | /* | ||||
* Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved. | * Copyright 2004-2023 The OpenSSL Project Authors. All Rights Reserved. | ||||
* | * | ||||
* Licensed under the Apache License 2.0 (the "License"). You may not use | * Licensed under the Apache License 2.0 (the "License"). You may not use | ||||
* this file except in compliance with the License. You can obtain a copy | * this file except in compliance with the License. You can obtain a copy | ||||
Context not available. | |||||
#include "pcy_local.h" | #include "pcy_local.h" | ||||
/* | |||||
* If the maximum number of nodes in the policy tree isn't defined, set it to | |||||
* a generous default of 1000 nodes. | |||||
* | |||||
* Defining this to be zero means unlimited policy tree growth which opens the | |||||
* door on CVE-2023-0464. | |||||
*/ | |||||
#ifndef OPENSSL_POLICY_TREE_NODES_MAX | |||||
# define OPENSSL_POLICY_TREE_NODES_MAX 1000 | |||||
#endif | |||||
static void exnode_free(X509_POLICY_NODE *node); | |||||
static void expected_print(BIO *channel, | static void expected_print(BIO *channel, | ||||
X509_POLICY_LEVEL *lev, X509_POLICY_NODE *node, | X509_POLICY_LEVEL *lev, X509_POLICY_NODE *node, | ||||
int indent) | int indent) | ||||
Context not available. | |||||
return X509_PCY_TREE_INTERNAL; | return X509_PCY_TREE_INTERNAL; | ||||
} | } | ||||
/* Limit the growth of the tree to mitigate CVE-2023-0464 */ | |||||
tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX; | |||||
/* | /* | ||||
* http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. | * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. | ||||
* | * | ||||
Context not available. | |||||
if ((data = ossl_policy_data_new(NULL, | if ((data = ossl_policy_data_new(NULL, | ||||
OBJ_nid2obj(NID_any_policy), 0)) == NULL) | OBJ_nid2obj(NID_any_policy), 0)) == NULL) | ||||
goto bad_tree; | goto bad_tree; | ||||
if (ossl_policy_level_add_node(level, data, NULL, tree) == NULL) { | if (ossl_policy_level_add_node(level, data, NULL, tree, 1) == NULL) { | ||||
ossl_policy_data_free(data); | ossl_policy_data_free(data); | ||||
goto bad_tree; | goto bad_tree; | ||||
} | } | ||||
Context not available. | |||||
* Return value: 1 on success, 0 otherwise | * Return value: 1 on success, 0 otherwise | ||||
*/ | */ | ||||
static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, | static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, | ||||
X509_POLICY_DATA *data) | X509_POLICY_DATA *data, | ||||
X509_POLICY_TREE *tree) | |||||
{ | { | ||||
X509_POLICY_LEVEL *last = curr - 1; | X509_POLICY_LEVEL *last = curr - 1; | ||||
int i, matched = 0; | int i, matched = 0; | ||||
Context not available. | |||||
X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i); | X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i); | ||||
if (ossl_policy_node_match(last, node, data->valid_policy)) { | if (ossl_policy_node_match(last, node, data->valid_policy)) { | ||||
if (ossl_policy_level_add_node(curr, data, node, NULL) == NULL) | if (ossl_policy_level_add_node(curr, data, node, tree, 0) == NULL) | ||||
return 0; | return 0; | ||||
matched = 1; | matched = 1; | ||||
} | } | ||||
} | } | ||||
if (!matched && last->anyPolicy) { | if (!matched && last->anyPolicy) { | ||||
if (ossl_policy_level_add_node(curr, data, last->anyPolicy, NULL) == NULL) | if (ossl_policy_level_add_node(curr, data, last->anyPolicy, tree, 0) == NULL) | ||||
return 0; | return 0; | ||||
} | } | ||||
return 1; | return 1; | ||||
Context not available. | |||||
* Return value: 1 on success, 0 otherwise. | * Return value: 1 on success, 0 otherwise. | ||||
*/ | */ | ||||
static int tree_link_nodes(X509_POLICY_LEVEL *curr, | static int tree_link_nodes(X509_POLICY_LEVEL *curr, | ||||
const X509_POLICY_CACHE *cache) | const X509_POLICY_CACHE *cache, | ||||
X509_POLICY_TREE *tree) | |||||
{ | { | ||||
int i; | int i; | ||||
Context not available. | |||||
X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i); | X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i); | ||||
/* Look for matching nodes in previous level */ | /* Look for matching nodes in previous level */ | ||||
if (!tree_link_matching_nodes(curr, data)) | if (!tree_link_matching_nodes(curr, data, tree)) | ||||
return 0; | return 0; | ||||
} | } | ||||
return 1; | return 1; | ||||
Context not available. | |||||
/* Curr may not have anyPolicy */ | /* Curr may not have anyPolicy */ | ||||
data->qualifier_set = cache->anyPolicy->qualifier_set; | data->qualifier_set = cache->anyPolicy->qualifier_set; | ||||
data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; | data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; | ||||
if (ossl_policy_level_add_node(curr, data, node, tree) == NULL) { | if (ossl_policy_level_add_node(curr, data, node, tree, 1) == NULL) { | ||||
ossl_policy_data_free(data); | ossl_policy_data_free(data); | ||||
return 0; | return 0; | ||||
} | } | ||||
Context not available. | |||||
/* Finally add link to anyPolicy */ | /* Finally add link to anyPolicy */ | ||||
if (last->anyPolicy && | if (last->anyPolicy && | ||||
ossl_policy_level_add_node(curr, cache->anyPolicy, | ossl_policy_level_add_node(curr, cache->anyPolicy, | ||||
last->anyPolicy, NULL) == NULL) | last->anyPolicy, tree, 0) == NULL) | ||||
return 0; | return 0; | ||||
return 1; | return 1; | ||||
} | } | ||||
Context not available. | |||||
extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS | extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS | ||||
| POLICY_DATA_FLAG_EXTRA_NODE; | | POLICY_DATA_FLAG_EXTRA_NODE; | ||||
node = ossl_policy_level_add_node(NULL, extra, anyPolicy->parent, | node = ossl_policy_level_add_node(NULL, extra, anyPolicy->parent, | ||||
tree); | tree, 1); | ||||
if (node == NULL) { | |||||
ossl_policy_data_free(extra); | |||||
return 0; | |||||
} | |||||
} | } | ||||
if (!tree->user_policies) { | if (!tree->user_policies) { | ||||
tree->user_policies = sk_X509_POLICY_NODE_new_null(); | tree->user_policies = sk_X509_POLICY_NODE_new_null(); | ||||
if (!tree->user_policies) | if (!tree->user_policies) { | ||||
return 1; | exnode_free(node); | ||||
return 0; | |||||
} | |||||
} | } | ||||
if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) | if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) { | ||||
exnode_free(node); | |||||
return 0; | return 0; | ||||
} | |||||
} | } | ||||
return 1; | return 1; | ||||
} | } | ||||
Context not available. | |||||
for (i = 1; i < tree->nlevel; i++, curr++) { | for (i = 1; i < tree->nlevel; i++, curr++) { | ||||
cache = ossl_policy_cache_set(curr->cert); | cache = ossl_policy_cache_set(curr->cert); | ||||
if (!tree_link_nodes(curr, cache)) | if (!tree_link_nodes(curr, cache, tree)) | ||||
return X509_PCY_TREE_INTERNAL; | return X509_PCY_TREE_INTERNAL; | ||||
if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) | if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) | ||||
Context not available. |