mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
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.
168 lines
5.8 KiB
C
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;
|
|
}
|