Files
Marius Ciepluch 0116f9bea6 feat(real-world-vfc-slice): add labeled OpenSSL/Firefox/Chromium/curl pair corpus
Harvest 176 isolated vuln-vs-fix functions (109 CVEs, 352 training rows)
into benchmarks/pairs/vfc with provenance and a JSONL training manifest.
Score the slice as an honesty dashboard (ousast pairs --slice vfc);
keep the pair gate on the local fixtures only.
2026-09-04 16:45:38 +02:00

168 lines
5.8 KiB
C

/* Provenance: openssl/openssl tree_init (fixed).
* repo: openssl/openssl
* commit: 959c59c7a0164117e7f8366466a32bb1f8d77ff1
* parent: c309c4dce742c3eeb393a0f03f9c567d0e368ccc
* commit_url: https://github.com/openssl/openssl/commit/959c59c7a0164117e7f8366466a32bb1f8d77ff1
* cve: CVE-2023-0464
* license: Apache-2.0
* function: tree_init
* relpath: crypto/x509/pcy_tree.c
*/
static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
unsigned int flags)
{
X509_POLICY_TREE *tree;
X509_POLICY_LEVEL *level;
const X509_POLICY_CACHE *cache;
X509_POLICY_DATA *data = NULL;
int ret = X509_PCY_TREE_VALID;
int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */
int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1;
int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1;
int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1;
int i;
*ptree = NULL;
/* Can't do anything with just a trust anchor */
if (n == 0)
return X509_PCY_TREE_EMPTY;
/*
* First setup the policy cache in all n non-TA certificates, this will be
* used in X509_verify_cert() which will invoke the verify callback for all
* certificates with invalid policy extensions.
*/
for (i = n - 1; i >= 0; i--) {
X509 *x = sk_X509_value(certs, i);
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, 0);
/* If cache is NULL, likely ENOMEM: return immediately */
if (ossl_policy_cache_set(x) == NULL)
return X509_PCY_TREE_INTERNAL;
}
/*
* At this point check for invalid policies and required explicit policy.
* Note that the explicit_policy counter is a count-down to zero, with the
* requirement kicking in if and once it does that. The counter is
* decremented for every non-self-issued certificate in the path, but may
* be further reduced by policy constraints in a non-leaf certificate.
*
* The ultimate policy set is the intersection of all the policies along
* the path, if we hit a certificate with an empty policy set, and explicit
* policy is required we're done.
*/
for (i = n - 1;
i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0);
i--) {
X509 *x = sk_X509_value(certs, i);
uint32_t ex_flags = X509_get_extension_flags(x);
/* All the policies are already cached, we can return early */
if (ex_flags & EXFLAG_INVALID_POLICY)
return X509_PCY_TREE_INVALID;
/* Access the cache which we now know exists */
cache = ossl_policy_cache_set(x);
if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL)
ret = X509_PCY_TREE_EMPTY;
if (explicit_policy > 0) {
if (!(ex_flags & EXFLAG_SI))
explicit_policy--;
if ((cache->explicit_skip >= 0)
&& (cache->explicit_skip < explicit_policy))
explicit_policy = cache->explicit_skip;
}
}
if (explicit_policy == 0)
ret |= X509_PCY_TREE_EXPLICIT;
if ((ret & X509_PCY_TREE_VALID) == 0)
return ret;
/* If we get this far initialize the tree */
if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) {
ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
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.
*
* The top level is implicitly for the trust anchor with valid expected
* policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at
* depth n, we have the leaf at depth 0 and the TA at depth n).
*/
if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) {
OPENSSL_free(tree);
ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE);
return X509_PCY_TREE_INTERNAL;
}
tree->nlevel = n+1;
level = tree->levels;
if ((data = ossl_policy_data_new(NULL,
OBJ_nid2obj(NID_any_policy), 0)) == NULL)
goto bad_tree;
if (ossl_policy_level_add_node(level, data, NULL, tree, 1) == NULL) {
ossl_policy_data_free(data);
goto bad_tree;
}
/*
* In this pass initialize all the tree levels and whether anyPolicy and
* policy mapping are inhibited at each level.
*/
for (i = n - 1; i >= 0; i--) {
X509 *x = sk_X509_value(certs, i);
uint32_t ex_flags = X509_get_extension_flags(x);
/* Access the cache which we now know exists */
cache = ossl_policy_cache_set(x);
X509_up_ref(x);
(++level)->cert = x;
if (!cache->anyPolicy)
level->flags |= X509_V_FLAG_INHIBIT_ANY;
/* Determine inhibit any and inhibit map flags */
if (any_skip == 0) {
/*
* Any matching allowed only if certificate is self issued and not
* the last in the chain.
*/
if (!(ex_flags & EXFLAG_SI) || (i == 0))
level->flags |= X509_V_FLAG_INHIBIT_ANY;
} else {
if (!(ex_flags & EXFLAG_SI))
any_skip--;
if ((cache->any_skip >= 0) && (cache->any_skip < any_skip))
any_skip = cache->any_skip;
}
if (map_skip == 0)
level->flags |= X509_V_FLAG_INHIBIT_MAP;
else {
if (!(ex_flags & EXFLAG_SI))
map_skip--;
if ((cache->map_skip >= 0) && (cache->map_skip < map_skip))
map_skip = cache->map_skip;
}
}
*ptree = tree;
return ret;
bad_tree:
X509_policy_tree_free(tree);
return X509_PCY_TREE_INTERNAL;
}