1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2004-2023 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 11e1051a39Sopenharmony_ci#include <openssl/trace.h> 12e1051a39Sopenharmony_ci#include <openssl/x509.h> 13e1051a39Sopenharmony_ci#include <openssl/x509v3.h> 14e1051a39Sopenharmony_ci 15e1051a39Sopenharmony_ci#include "pcy_local.h" 16e1051a39Sopenharmony_ci 17e1051a39Sopenharmony_ci/* 18e1051a39Sopenharmony_ci * If the maximum number of nodes in the policy tree isn't defined, set it to 19e1051a39Sopenharmony_ci * a generous default of 1000 nodes. 20e1051a39Sopenharmony_ci * 21e1051a39Sopenharmony_ci * Defining this to be zero means unlimited policy tree growth which opens the 22e1051a39Sopenharmony_ci * door on CVE-2023-0464. 23e1051a39Sopenharmony_ci */ 24e1051a39Sopenharmony_ci#ifndef OPENSSL_POLICY_TREE_NODES_MAX 25e1051a39Sopenharmony_ci# define OPENSSL_POLICY_TREE_NODES_MAX 1000 26e1051a39Sopenharmony_ci#endif 27e1051a39Sopenharmony_ci 28e1051a39Sopenharmony_cistatic void exnode_free(X509_POLICY_NODE *node); 29e1051a39Sopenharmony_ci 30e1051a39Sopenharmony_cistatic void expected_print(BIO *channel, 31e1051a39Sopenharmony_ci X509_POLICY_LEVEL *lev, X509_POLICY_NODE *node, 32e1051a39Sopenharmony_ci int indent) 33e1051a39Sopenharmony_ci{ 34e1051a39Sopenharmony_ci if ((lev->flags & X509_V_FLAG_INHIBIT_MAP) 35e1051a39Sopenharmony_ci || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK)) 36e1051a39Sopenharmony_ci BIO_puts(channel, " Not Mapped\n"); 37e1051a39Sopenharmony_ci else { 38e1051a39Sopenharmony_ci int i; 39e1051a39Sopenharmony_ci 40e1051a39Sopenharmony_ci STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set; 41e1051a39Sopenharmony_ci ASN1_OBJECT *oid; 42e1051a39Sopenharmony_ci BIO_puts(channel, " Expected: "); 43e1051a39Sopenharmony_ci for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) { 44e1051a39Sopenharmony_ci oid = sk_ASN1_OBJECT_value(pset, i); 45e1051a39Sopenharmony_ci if (i) 46e1051a39Sopenharmony_ci BIO_puts(channel, ", "); 47e1051a39Sopenharmony_ci i2a_ASN1_OBJECT(channel, oid); 48e1051a39Sopenharmony_ci } 49e1051a39Sopenharmony_ci BIO_puts(channel, "\n"); 50e1051a39Sopenharmony_ci } 51e1051a39Sopenharmony_ci} 52e1051a39Sopenharmony_ci 53e1051a39Sopenharmony_cistatic void tree_print(BIO *channel, 54e1051a39Sopenharmony_ci char *str, X509_POLICY_TREE *tree, 55e1051a39Sopenharmony_ci X509_POLICY_LEVEL *curr) 56e1051a39Sopenharmony_ci{ 57e1051a39Sopenharmony_ci X509_POLICY_LEVEL *plev; 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_ci if (!curr) 60e1051a39Sopenharmony_ci curr = tree->levels + tree->nlevel; 61e1051a39Sopenharmony_ci else 62e1051a39Sopenharmony_ci curr++; 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_ci BIO_printf(channel, "Level print after %s\n", str); 65e1051a39Sopenharmony_ci BIO_printf(channel, "Printing Up to Level %ld\n", 66e1051a39Sopenharmony_ci (long)(curr - tree->levels)); 67e1051a39Sopenharmony_ci for (plev = tree->levels; plev != curr; plev++) { 68e1051a39Sopenharmony_ci int i; 69e1051a39Sopenharmony_ci 70e1051a39Sopenharmony_ci BIO_printf(channel, "Level %ld, flags = %x\n", 71e1051a39Sopenharmony_ci (long)(plev - tree->levels), plev->flags); 72e1051a39Sopenharmony_ci for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) { 73e1051a39Sopenharmony_ci X509_POLICY_NODE *node = 74e1051a39Sopenharmony_ci sk_X509_POLICY_NODE_value(plev->nodes, i); 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_ci X509_POLICY_NODE_print(channel, node, 2); 77e1051a39Sopenharmony_ci expected_print(channel, plev, node, 2); 78e1051a39Sopenharmony_ci BIO_printf(channel, " Flags: %x\n", node->data->flags); 79e1051a39Sopenharmony_ci } 80e1051a39Sopenharmony_ci if (plev->anyPolicy) 81e1051a39Sopenharmony_ci X509_POLICY_NODE_print(channel, plev->anyPolicy, 2); 82e1051a39Sopenharmony_ci } 83e1051a39Sopenharmony_ci} 84e1051a39Sopenharmony_ci 85e1051a39Sopenharmony_ci#define TREE_PRINT(str, tree, curr) \ 86e1051a39Sopenharmony_ci OSSL_TRACE_BEGIN(X509V3_POLICY) { \ 87e1051a39Sopenharmony_ci tree_print(trc_out, "before tree_prune()", tree, curr); \ 88e1051a39Sopenharmony_ci } OSSL_TRACE_END(X509V3_POLICY) 89e1051a39Sopenharmony_ci 90e1051a39Sopenharmony_ci/*- 91e1051a39Sopenharmony_ci * Return value: <= 0 on error, or positive bit mask: 92e1051a39Sopenharmony_ci * 93e1051a39Sopenharmony_ci * X509_PCY_TREE_VALID: valid tree 94e1051a39Sopenharmony_ci * X509_PCY_TREE_EMPTY: empty tree (including bare TA case) 95e1051a39Sopenharmony_ci * X509_PCY_TREE_EXPLICIT: explicit policy required 96e1051a39Sopenharmony_ci */ 97e1051a39Sopenharmony_cistatic int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, 98e1051a39Sopenharmony_ci unsigned int flags) 99e1051a39Sopenharmony_ci{ 100e1051a39Sopenharmony_ci X509_POLICY_TREE *tree; 101e1051a39Sopenharmony_ci X509_POLICY_LEVEL *level; 102e1051a39Sopenharmony_ci const X509_POLICY_CACHE *cache; 103e1051a39Sopenharmony_ci X509_POLICY_DATA *data = NULL; 104e1051a39Sopenharmony_ci int ret = X509_PCY_TREE_VALID; 105e1051a39Sopenharmony_ci int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */ 106e1051a39Sopenharmony_ci int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1; 107e1051a39Sopenharmony_ci int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1; 108e1051a39Sopenharmony_ci int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1; 109e1051a39Sopenharmony_ci int i; 110e1051a39Sopenharmony_ci 111e1051a39Sopenharmony_ci *ptree = NULL; 112e1051a39Sopenharmony_ci 113e1051a39Sopenharmony_ci /* Can't do anything with just a trust anchor */ 114e1051a39Sopenharmony_ci if (n == 0) 115e1051a39Sopenharmony_ci return X509_PCY_TREE_EMPTY; 116e1051a39Sopenharmony_ci 117e1051a39Sopenharmony_ci /* 118e1051a39Sopenharmony_ci * First setup the policy cache in all n non-TA certificates, this will be 119e1051a39Sopenharmony_ci * used in X509_verify_cert() which will invoke the verify callback for all 120e1051a39Sopenharmony_ci * certificates with invalid policy extensions. 121e1051a39Sopenharmony_ci */ 122e1051a39Sopenharmony_ci for (i = n - 1; i >= 0; i--) { 123e1051a39Sopenharmony_ci X509 *x = sk_X509_value(certs, i); 124e1051a39Sopenharmony_ci 125e1051a39Sopenharmony_ci /* Call for side-effect of computing hash and caching extensions */ 126e1051a39Sopenharmony_ci X509_check_purpose(x, -1, 0); 127e1051a39Sopenharmony_ci 128e1051a39Sopenharmony_ci /* If cache is NULL, likely ENOMEM: return immediately */ 129e1051a39Sopenharmony_ci if (ossl_policy_cache_set(x) == NULL) 130e1051a39Sopenharmony_ci return X509_PCY_TREE_INTERNAL; 131e1051a39Sopenharmony_ci } 132e1051a39Sopenharmony_ci 133e1051a39Sopenharmony_ci /* 134e1051a39Sopenharmony_ci * At this point check for invalid policies and required explicit policy. 135e1051a39Sopenharmony_ci * Note that the explicit_policy counter is a count-down to zero, with the 136e1051a39Sopenharmony_ci * requirement kicking in if and once it does that. The counter is 137e1051a39Sopenharmony_ci * decremented for every non-self-issued certificate in the path, but may 138e1051a39Sopenharmony_ci * be further reduced by policy constraints in a non-leaf certificate. 139e1051a39Sopenharmony_ci * 140e1051a39Sopenharmony_ci * The ultimate policy set is the intersection of all the policies along 141e1051a39Sopenharmony_ci * the path, if we hit a certificate with an empty policy set, and explicit 142e1051a39Sopenharmony_ci * policy is required we're done. 143e1051a39Sopenharmony_ci */ 144e1051a39Sopenharmony_ci for (i = n - 1; 145e1051a39Sopenharmony_ci i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0); 146e1051a39Sopenharmony_ci i--) { 147e1051a39Sopenharmony_ci X509 *x = sk_X509_value(certs, i); 148e1051a39Sopenharmony_ci uint32_t ex_flags = X509_get_extension_flags(x); 149e1051a39Sopenharmony_ci 150e1051a39Sopenharmony_ci /* All the policies are already cached, we can return early */ 151e1051a39Sopenharmony_ci if (ex_flags & EXFLAG_INVALID_POLICY) 152e1051a39Sopenharmony_ci return X509_PCY_TREE_INVALID; 153e1051a39Sopenharmony_ci 154e1051a39Sopenharmony_ci /* Access the cache which we now know exists */ 155e1051a39Sopenharmony_ci cache = ossl_policy_cache_set(x); 156e1051a39Sopenharmony_ci 157e1051a39Sopenharmony_ci if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL) 158e1051a39Sopenharmony_ci ret = X509_PCY_TREE_EMPTY; 159e1051a39Sopenharmony_ci if (explicit_policy > 0) { 160e1051a39Sopenharmony_ci if (!(ex_flags & EXFLAG_SI)) 161e1051a39Sopenharmony_ci explicit_policy--; 162e1051a39Sopenharmony_ci if ((cache->explicit_skip >= 0) 163e1051a39Sopenharmony_ci && (cache->explicit_skip < explicit_policy)) 164e1051a39Sopenharmony_ci explicit_policy = cache->explicit_skip; 165e1051a39Sopenharmony_ci } 166e1051a39Sopenharmony_ci } 167e1051a39Sopenharmony_ci 168e1051a39Sopenharmony_ci if (explicit_policy == 0) 169e1051a39Sopenharmony_ci ret |= X509_PCY_TREE_EXPLICIT; 170e1051a39Sopenharmony_ci if ((ret & X509_PCY_TREE_VALID) == 0) 171e1051a39Sopenharmony_ci return ret; 172e1051a39Sopenharmony_ci 173e1051a39Sopenharmony_ci /* If we get this far initialize the tree */ 174e1051a39Sopenharmony_ci if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) { 175e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE); 176e1051a39Sopenharmony_ci return X509_PCY_TREE_INTERNAL; 177e1051a39Sopenharmony_ci } 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ci /* Limit the growth of the tree to mitigate CVE-2023-0464 */ 180e1051a39Sopenharmony_ci tree->node_maximum = OPENSSL_POLICY_TREE_NODES_MAX; 181e1051a39Sopenharmony_ci 182e1051a39Sopenharmony_ci /* 183e1051a39Sopenharmony_ci * http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3. 184e1051a39Sopenharmony_ci * 185e1051a39Sopenharmony_ci * The top level is implicitly for the trust anchor with valid expected 186e1051a39Sopenharmony_ci * policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at 187e1051a39Sopenharmony_ci * depth n, we have the leaf at depth 0 and the TA at depth n). 188e1051a39Sopenharmony_ci */ 189e1051a39Sopenharmony_ci if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) { 190e1051a39Sopenharmony_ci OPENSSL_free(tree); 191e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_X509V3, ERR_R_MALLOC_FAILURE); 192e1051a39Sopenharmony_ci return X509_PCY_TREE_INTERNAL; 193e1051a39Sopenharmony_ci } 194e1051a39Sopenharmony_ci tree->nlevel = n+1; 195e1051a39Sopenharmony_ci level = tree->levels; 196e1051a39Sopenharmony_ci if ((data = ossl_policy_data_new(NULL, 197e1051a39Sopenharmony_ci OBJ_nid2obj(NID_any_policy), 0)) == NULL) 198e1051a39Sopenharmony_ci goto bad_tree; 199e1051a39Sopenharmony_ci if (ossl_policy_level_add_node(level, data, NULL, tree, 1) == NULL) { 200e1051a39Sopenharmony_ci ossl_policy_data_free(data); 201e1051a39Sopenharmony_ci goto bad_tree; 202e1051a39Sopenharmony_ci } 203e1051a39Sopenharmony_ci 204e1051a39Sopenharmony_ci /* 205e1051a39Sopenharmony_ci * In this pass initialize all the tree levels and whether anyPolicy and 206e1051a39Sopenharmony_ci * policy mapping are inhibited at each level. 207e1051a39Sopenharmony_ci */ 208e1051a39Sopenharmony_ci for (i = n - 1; i >= 0; i--) { 209e1051a39Sopenharmony_ci X509 *x = sk_X509_value(certs, i); 210e1051a39Sopenharmony_ci uint32_t ex_flags = X509_get_extension_flags(x); 211e1051a39Sopenharmony_ci 212e1051a39Sopenharmony_ci /* Access the cache which we now know exists */ 213e1051a39Sopenharmony_ci cache = ossl_policy_cache_set(x); 214e1051a39Sopenharmony_ci 215e1051a39Sopenharmony_ci X509_up_ref(x); 216e1051a39Sopenharmony_ci (++level)->cert = x; 217e1051a39Sopenharmony_ci 218e1051a39Sopenharmony_ci if (!cache->anyPolicy) 219e1051a39Sopenharmony_ci level->flags |= X509_V_FLAG_INHIBIT_ANY; 220e1051a39Sopenharmony_ci 221e1051a39Sopenharmony_ci /* Determine inhibit any and inhibit map flags */ 222e1051a39Sopenharmony_ci if (any_skip == 0) { 223e1051a39Sopenharmony_ci /* 224e1051a39Sopenharmony_ci * Any matching allowed only if certificate is self issued and not 225e1051a39Sopenharmony_ci * the last in the chain. 226e1051a39Sopenharmony_ci */ 227e1051a39Sopenharmony_ci if (!(ex_flags & EXFLAG_SI) || (i == 0)) 228e1051a39Sopenharmony_ci level->flags |= X509_V_FLAG_INHIBIT_ANY; 229e1051a39Sopenharmony_ci } else { 230e1051a39Sopenharmony_ci if (!(ex_flags & EXFLAG_SI)) 231e1051a39Sopenharmony_ci any_skip--; 232e1051a39Sopenharmony_ci if ((cache->any_skip >= 0) && (cache->any_skip < any_skip)) 233e1051a39Sopenharmony_ci any_skip = cache->any_skip; 234e1051a39Sopenharmony_ci } 235e1051a39Sopenharmony_ci 236e1051a39Sopenharmony_ci if (map_skip == 0) 237e1051a39Sopenharmony_ci level->flags |= X509_V_FLAG_INHIBIT_MAP; 238e1051a39Sopenharmony_ci else { 239e1051a39Sopenharmony_ci if (!(ex_flags & EXFLAG_SI)) 240e1051a39Sopenharmony_ci map_skip--; 241e1051a39Sopenharmony_ci if ((cache->map_skip >= 0) && (cache->map_skip < map_skip)) 242e1051a39Sopenharmony_ci map_skip = cache->map_skip; 243e1051a39Sopenharmony_ci } 244e1051a39Sopenharmony_ci } 245e1051a39Sopenharmony_ci 246e1051a39Sopenharmony_ci *ptree = tree; 247e1051a39Sopenharmony_ci return ret; 248e1051a39Sopenharmony_ci 249e1051a39Sopenharmony_ci bad_tree: 250e1051a39Sopenharmony_ci X509_policy_tree_free(tree); 251e1051a39Sopenharmony_ci return X509_PCY_TREE_INTERNAL; 252e1051a39Sopenharmony_ci} 253e1051a39Sopenharmony_ci 254e1051a39Sopenharmony_ci/* 255e1051a39Sopenharmony_ci * Return value: 1 on success, 0 otherwise 256e1051a39Sopenharmony_ci */ 257e1051a39Sopenharmony_cistatic int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, 258e1051a39Sopenharmony_ci X509_POLICY_DATA *data, 259e1051a39Sopenharmony_ci X509_POLICY_TREE *tree) 260e1051a39Sopenharmony_ci{ 261e1051a39Sopenharmony_ci X509_POLICY_LEVEL *last = curr - 1; 262e1051a39Sopenharmony_ci int i, matched = 0; 263e1051a39Sopenharmony_ci 264e1051a39Sopenharmony_ci /* Iterate through all in nodes linking matches */ 265e1051a39Sopenharmony_ci for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) { 266e1051a39Sopenharmony_ci X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i); 267e1051a39Sopenharmony_ci 268e1051a39Sopenharmony_ci if (ossl_policy_node_match(last, node, data->valid_policy)) { 269e1051a39Sopenharmony_ci if (ossl_policy_level_add_node(curr, data, node, tree, 0) == NULL) 270e1051a39Sopenharmony_ci return 0; 271e1051a39Sopenharmony_ci matched = 1; 272e1051a39Sopenharmony_ci } 273e1051a39Sopenharmony_ci } 274e1051a39Sopenharmony_ci if (!matched && last->anyPolicy) { 275e1051a39Sopenharmony_ci if (ossl_policy_level_add_node(curr, data, last->anyPolicy, tree, 0) == NULL) 276e1051a39Sopenharmony_ci return 0; 277e1051a39Sopenharmony_ci } 278e1051a39Sopenharmony_ci return 1; 279e1051a39Sopenharmony_ci} 280e1051a39Sopenharmony_ci 281e1051a39Sopenharmony_ci/* 282e1051a39Sopenharmony_ci * This corresponds to RFC3280 6.1.3(d)(1): link any data from 283e1051a39Sopenharmony_ci * CertificatePolicies onto matching parent or anyPolicy if no match. 284e1051a39Sopenharmony_ci * 285e1051a39Sopenharmony_ci * Return value: 1 on success, 0 otherwise. 286e1051a39Sopenharmony_ci */ 287e1051a39Sopenharmony_cistatic int tree_link_nodes(X509_POLICY_LEVEL *curr, 288e1051a39Sopenharmony_ci const X509_POLICY_CACHE *cache, 289e1051a39Sopenharmony_ci X509_POLICY_TREE *tree) 290e1051a39Sopenharmony_ci{ 291e1051a39Sopenharmony_ci int i; 292e1051a39Sopenharmony_ci 293e1051a39Sopenharmony_ci for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) { 294e1051a39Sopenharmony_ci X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i); 295e1051a39Sopenharmony_ci 296e1051a39Sopenharmony_ci /* Look for matching nodes in previous level */ 297e1051a39Sopenharmony_ci if (!tree_link_matching_nodes(curr, data, tree)) 298e1051a39Sopenharmony_ci return 0; 299e1051a39Sopenharmony_ci } 300e1051a39Sopenharmony_ci return 1; 301e1051a39Sopenharmony_ci} 302e1051a39Sopenharmony_ci 303e1051a39Sopenharmony_ci/* 304e1051a39Sopenharmony_ci * This corresponds to RFC3280 6.1.3(d)(2): Create new data for any unmatched 305e1051a39Sopenharmony_ci * policies in the parent and link to anyPolicy. 306e1051a39Sopenharmony_ci * 307e1051a39Sopenharmony_ci * Return value: 1 on success, 0 otherwise. 308e1051a39Sopenharmony_ci */ 309e1051a39Sopenharmony_cistatic int tree_add_unmatched(X509_POLICY_LEVEL *curr, 310e1051a39Sopenharmony_ci const X509_POLICY_CACHE *cache, 311e1051a39Sopenharmony_ci const ASN1_OBJECT *id, 312e1051a39Sopenharmony_ci X509_POLICY_NODE *node, X509_POLICY_TREE *tree) 313e1051a39Sopenharmony_ci{ 314e1051a39Sopenharmony_ci X509_POLICY_DATA *data; 315e1051a39Sopenharmony_ci 316e1051a39Sopenharmony_ci if (id == NULL) 317e1051a39Sopenharmony_ci id = node->data->valid_policy; 318e1051a39Sopenharmony_ci /* 319e1051a39Sopenharmony_ci * Create a new node with qualifiers from anyPolicy and id from unmatched 320e1051a39Sopenharmony_ci * node. 321e1051a39Sopenharmony_ci */ 322e1051a39Sopenharmony_ci if ((data = ossl_policy_data_new(NULL, id, node_critical(node))) == NULL) 323e1051a39Sopenharmony_ci return 0; 324e1051a39Sopenharmony_ci 325e1051a39Sopenharmony_ci /* Curr may not have anyPolicy */ 326e1051a39Sopenharmony_ci data->qualifier_set = cache->anyPolicy->qualifier_set; 327e1051a39Sopenharmony_ci data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; 328e1051a39Sopenharmony_ci if (ossl_policy_level_add_node(curr, data, node, tree, 1) == NULL) { 329e1051a39Sopenharmony_ci ossl_policy_data_free(data); 330e1051a39Sopenharmony_ci return 0; 331e1051a39Sopenharmony_ci } 332e1051a39Sopenharmony_ci return 1; 333e1051a39Sopenharmony_ci} 334e1051a39Sopenharmony_ci 335e1051a39Sopenharmony_ci/* 336e1051a39Sopenharmony_ci * Return value: 1 on success, 0 otherwise. 337e1051a39Sopenharmony_ci */ 338e1051a39Sopenharmony_cistatic int tree_link_unmatched(X509_POLICY_LEVEL *curr, 339e1051a39Sopenharmony_ci const X509_POLICY_CACHE *cache, 340e1051a39Sopenharmony_ci X509_POLICY_NODE *node, X509_POLICY_TREE *tree) 341e1051a39Sopenharmony_ci{ 342e1051a39Sopenharmony_ci const X509_POLICY_LEVEL *last = curr - 1; 343e1051a39Sopenharmony_ci int i; 344e1051a39Sopenharmony_ci 345e1051a39Sopenharmony_ci if ((last->flags & X509_V_FLAG_INHIBIT_MAP) 346e1051a39Sopenharmony_ci || !(node->data->flags & POLICY_DATA_FLAG_MAPPED)) { 347e1051a39Sopenharmony_ci /* If no policy mapping: matched if one child present */ 348e1051a39Sopenharmony_ci if (node->nchild) 349e1051a39Sopenharmony_ci return 1; 350e1051a39Sopenharmony_ci if (!tree_add_unmatched(curr, cache, NULL, node, tree)) 351e1051a39Sopenharmony_ci return 0; 352e1051a39Sopenharmony_ci /* Add it */ 353e1051a39Sopenharmony_ci } else { 354e1051a39Sopenharmony_ci /* If mapping: matched if one child per expected policy set */ 355e1051a39Sopenharmony_ci STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set; 356e1051a39Sopenharmony_ci if (node->nchild == sk_ASN1_OBJECT_num(expset)) 357e1051a39Sopenharmony_ci return 1; 358e1051a39Sopenharmony_ci /* Locate unmatched nodes */ 359e1051a39Sopenharmony_ci for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++) { 360e1051a39Sopenharmony_ci ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i); 361e1051a39Sopenharmony_ci if (ossl_policy_level_find_node(curr, node, oid)) 362e1051a39Sopenharmony_ci continue; 363e1051a39Sopenharmony_ci if (!tree_add_unmatched(curr, cache, oid, node, tree)) 364e1051a39Sopenharmony_ci return 0; 365e1051a39Sopenharmony_ci } 366e1051a39Sopenharmony_ci 367e1051a39Sopenharmony_ci } 368e1051a39Sopenharmony_ci return 1; 369e1051a39Sopenharmony_ci} 370e1051a39Sopenharmony_ci 371e1051a39Sopenharmony_ci/* 372e1051a39Sopenharmony_ci * Return value: 1 on success, 0 otherwise 373e1051a39Sopenharmony_ci */ 374e1051a39Sopenharmony_cistatic int tree_link_any(X509_POLICY_LEVEL *curr, 375e1051a39Sopenharmony_ci const X509_POLICY_CACHE *cache, 376e1051a39Sopenharmony_ci X509_POLICY_TREE *tree) 377e1051a39Sopenharmony_ci{ 378e1051a39Sopenharmony_ci int i; 379e1051a39Sopenharmony_ci X509_POLICY_NODE *node; 380e1051a39Sopenharmony_ci X509_POLICY_LEVEL *last = curr - 1; 381e1051a39Sopenharmony_ci 382e1051a39Sopenharmony_ci for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) { 383e1051a39Sopenharmony_ci node = sk_X509_POLICY_NODE_value(last->nodes, i); 384e1051a39Sopenharmony_ci 385e1051a39Sopenharmony_ci if (!tree_link_unmatched(curr, cache, node, tree)) 386e1051a39Sopenharmony_ci return 0; 387e1051a39Sopenharmony_ci } 388e1051a39Sopenharmony_ci /* Finally add link to anyPolicy */ 389e1051a39Sopenharmony_ci if (last->anyPolicy && 390e1051a39Sopenharmony_ci ossl_policy_level_add_node(curr, cache->anyPolicy, 391e1051a39Sopenharmony_ci last->anyPolicy, tree, 0) == NULL) 392e1051a39Sopenharmony_ci return 0; 393e1051a39Sopenharmony_ci return 1; 394e1051a39Sopenharmony_ci} 395e1051a39Sopenharmony_ci 396e1051a39Sopenharmony_ci/*- 397e1051a39Sopenharmony_ci * Prune the tree: delete any child mapped child data on the current level then 398e1051a39Sopenharmony_ci * proceed up the tree deleting any data with no children. If we ever have no 399e1051a39Sopenharmony_ci * data on a level we can halt because the tree will be empty. 400e1051a39Sopenharmony_ci * 401e1051a39Sopenharmony_ci * Return value: <= 0 error, otherwise one of: 402e1051a39Sopenharmony_ci * 403e1051a39Sopenharmony_ci * X509_PCY_TREE_VALID: valid tree 404e1051a39Sopenharmony_ci * X509_PCY_TREE_EMPTY: empty tree 405e1051a39Sopenharmony_ci */ 406e1051a39Sopenharmony_cistatic int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr) 407e1051a39Sopenharmony_ci{ 408e1051a39Sopenharmony_ci STACK_OF(X509_POLICY_NODE) *nodes; 409e1051a39Sopenharmony_ci X509_POLICY_NODE *node; 410e1051a39Sopenharmony_ci int i; 411e1051a39Sopenharmony_ci nodes = curr->nodes; 412e1051a39Sopenharmony_ci if (curr->flags & X509_V_FLAG_INHIBIT_MAP) { 413e1051a39Sopenharmony_ci for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) { 414e1051a39Sopenharmony_ci node = sk_X509_POLICY_NODE_value(nodes, i); 415e1051a39Sopenharmony_ci /* Delete any mapped data: see RFC3280 XXXX */ 416e1051a39Sopenharmony_ci if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) { 417e1051a39Sopenharmony_ci node->parent->nchild--; 418e1051a39Sopenharmony_ci OPENSSL_free(node); 419e1051a39Sopenharmony_ci (void)sk_X509_POLICY_NODE_delete(nodes, i); 420e1051a39Sopenharmony_ci } 421e1051a39Sopenharmony_ci } 422e1051a39Sopenharmony_ci } 423e1051a39Sopenharmony_ci 424e1051a39Sopenharmony_ci for (;;) { 425e1051a39Sopenharmony_ci --curr; 426e1051a39Sopenharmony_ci nodes = curr->nodes; 427e1051a39Sopenharmony_ci for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) { 428e1051a39Sopenharmony_ci node = sk_X509_POLICY_NODE_value(nodes, i); 429e1051a39Sopenharmony_ci if (node->nchild == 0) { 430e1051a39Sopenharmony_ci node->parent->nchild--; 431e1051a39Sopenharmony_ci OPENSSL_free(node); 432e1051a39Sopenharmony_ci (void)sk_X509_POLICY_NODE_delete(nodes, i); 433e1051a39Sopenharmony_ci } 434e1051a39Sopenharmony_ci } 435e1051a39Sopenharmony_ci if (curr->anyPolicy && !curr->anyPolicy->nchild) { 436e1051a39Sopenharmony_ci if (curr->anyPolicy->parent) 437e1051a39Sopenharmony_ci curr->anyPolicy->parent->nchild--; 438e1051a39Sopenharmony_ci OPENSSL_free(curr->anyPolicy); 439e1051a39Sopenharmony_ci curr->anyPolicy = NULL; 440e1051a39Sopenharmony_ci } 441e1051a39Sopenharmony_ci if (curr == tree->levels) { 442e1051a39Sopenharmony_ci /* If we zapped anyPolicy at top then tree is empty */ 443e1051a39Sopenharmony_ci if (!curr->anyPolicy) 444e1051a39Sopenharmony_ci return X509_PCY_TREE_EMPTY; 445e1051a39Sopenharmony_ci break; 446e1051a39Sopenharmony_ci } 447e1051a39Sopenharmony_ci } 448e1051a39Sopenharmony_ci return X509_PCY_TREE_VALID; 449e1051a39Sopenharmony_ci} 450e1051a39Sopenharmony_ci 451e1051a39Sopenharmony_ci/* 452e1051a39Sopenharmony_ci * Return value: 1 on success, 0 otherwise. 453e1051a39Sopenharmony_ci */ 454e1051a39Sopenharmony_cistatic int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes, 455e1051a39Sopenharmony_ci X509_POLICY_NODE *pcy) 456e1051a39Sopenharmony_ci{ 457e1051a39Sopenharmony_ci if (*pnodes == NULL && 458e1051a39Sopenharmony_ci (*pnodes = ossl_policy_node_cmp_new()) == NULL) 459e1051a39Sopenharmony_ci return 0; 460e1051a39Sopenharmony_ci if (sk_X509_POLICY_NODE_find(*pnodes, pcy) >= 0) 461e1051a39Sopenharmony_ci return 1; 462e1051a39Sopenharmony_ci return sk_X509_POLICY_NODE_push(*pnodes, pcy) != 0; 463e1051a39Sopenharmony_ci} 464e1051a39Sopenharmony_ci 465e1051a39Sopenharmony_ci#define TREE_CALC_FAILURE 0 466e1051a39Sopenharmony_ci#define TREE_CALC_OK_NOFREE 1 467e1051a39Sopenharmony_ci#define TREE_CALC_OK_DOFREE 2 468e1051a39Sopenharmony_ci 469e1051a39Sopenharmony_ci/*- 470e1051a39Sopenharmony_ci * Calculate the authority set based on policy tree. The 'pnodes' parameter is 471e1051a39Sopenharmony_ci * used as a store for the set of policy nodes used to calculate the user set. 472e1051a39Sopenharmony_ci * If the authority set is not anyPolicy then pnodes will just point to the 473e1051a39Sopenharmony_ci * authority set. If however the authority set is anyPolicy then the set of 474e1051a39Sopenharmony_ci * valid policies (other than anyPolicy) is store in pnodes. 475e1051a39Sopenharmony_ci * 476e1051a39Sopenharmony_ci * Return value: 477e1051a39Sopenharmony_ci * TREE_CALC_FAILURE on failure, 478e1051a39Sopenharmony_ci * TREE_CALC_OK_NOFREE on success and pnodes need not be freed, 479e1051a39Sopenharmony_ci * TREE_CALC_OK_DOFREE on success and pnodes needs to be freed 480e1051a39Sopenharmony_ci */ 481e1051a39Sopenharmony_cistatic int tree_calculate_authority_set(X509_POLICY_TREE *tree, 482e1051a39Sopenharmony_ci STACK_OF(X509_POLICY_NODE) **pnodes) 483e1051a39Sopenharmony_ci{ 484e1051a39Sopenharmony_ci X509_POLICY_LEVEL *curr; 485e1051a39Sopenharmony_ci X509_POLICY_NODE *node, *anyptr; 486e1051a39Sopenharmony_ci STACK_OF(X509_POLICY_NODE) **addnodes; 487e1051a39Sopenharmony_ci int i, j; 488e1051a39Sopenharmony_ci curr = tree->levels + tree->nlevel - 1; 489e1051a39Sopenharmony_ci 490e1051a39Sopenharmony_ci /* If last level contains anyPolicy set is anyPolicy */ 491e1051a39Sopenharmony_ci if (curr->anyPolicy) { 492e1051a39Sopenharmony_ci if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy)) 493e1051a39Sopenharmony_ci return TREE_CALC_FAILURE; 494e1051a39Sopenharmony_ci addnodes = pnodes; 495e1051a39Sopenharmony_ci } else 496e1051a39Sopenharmony_ci /* Add policies to authority set */ 497e1051a39Sopenharmony_ci addnodes = &tree->auth_policies; 498e1051a39Sopenharmony_ci 499e1051a39Sopenharmony_ci curr = tree->levels; 500e1051a39Sopenharmony_ci for (i = 1; i < tree->nlevel; i++) { 501e1051a39Sopenharmony_ci /* 502e1051a39Sopenharmony_ci * If no anyPolicy node on this level it can't appear on lower 503e1051a39Sopenharmony_ci * levels so end search. 504e1051a39Sopenharmony_ci */ 505e1051a39Sopenharmony_ci if ((anyptr = curr->anyPolicy) == NULL) 506e1051a39Sopenharmony_ci break; 507e1051a39Sopenharmony_ci curr++; 508e1051a39Sopenharmony_ci for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) { 509e1051a39Sopenharmony_ci node = sk_X509_POLICY_NODE_value(curr->nodes, j); 510e1051a39Sopenharmony_ci if ((node->parent == anyptr) 511e1051a39Sopenharmony_ci && !tree_add_auth_node(addnodes, node)) { 512e1051a39Sopenharmony_ci if (addnodes == pnodes) { 513e1051a39Sopenharmony_ci sk_X509_POLICY_NODE_free(*pnodes); 514e1051a39Sopenharmony_ci *pnodes = NULL; 515e1051a39Sopenharmony_ci } 516e1051a39Sopenharmony_ci return TREE_CALC_FAILURE; 517e1051a39Sopenharmony_ci } 518e1051a39Sopenharmony_ci } 519e1051a39Sopenharmony_ci } 520e1051a39Sopenharmony_ci if (addnodes == pnodes) 521e1051a39Sopenharmony_ci return TREE_CALC_OK_DOFREE; 522e1051a39Sopenharmony_ci 523e1051a39Sopenharmony_ci *pnodes = tree->auth_policies; 524e1051a39Sopenharmony_ci return TREE_CALC_OK_NOFREE; 525e1051a39Sopenharmony_ci} 526e1051a39Sopenharmony_ci 527e1051a39Sopenharmony_ci/* 528e1051a39Sopenharmony_ci * Return value: 1 on success, 0 otherwise. 529e1051a39Sopenharmony_ci */ 530e1051a39Sopenharmony_cistatic int tree_calculate_user_set(X509_POLICY_TREE *tree, 531e1051a39Sopenharmony_ci STACK_OF(ASN1_OBJECT) *policy_oids, 532e1051a39Sopenharmony_ci STACK_OF(X509_POLICY_NODE) *auth_nodes) 533e1051a39Sopenharmony_ci{ 534e1051a39Sopenharmony_ci int i; 535e1051a39Sopenharmony_ci X509_POLICY_NODE *node; 536e1051a39Sopenharmony_ci ASN1_OBJECT *oid; 537e1051a39Sopenharmony_ci X509_POLICY_NODE *anyPolicy; 538e1051a39Sopenharmony_ci X509_POLICY_DATA *extra; 539e1051a39Sopenharmony_ci 540e1051a39Sopenharmony_ci /* 541e1051a39Sopenharmony_ci * Check if anyPolicy present in authority constrained policy set: this 542e1051a39Sopenharmony_ci * will happen if it is a leaf node. 543e1051a39Sopenharmony_ci */ 544e1051a39Sopenharmony_ci if (sk_ASN1_OBJECT_num(policy_oids) <= 0) 545e1051a39Sopenharmony_ci return 1; 546e1051a39Sopenharmony_ci 547e1051a39Sopenharmony_ci anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy; 548e1051a39Sopenharmony_ci 549e1051a39Sopenharmony_ci for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) { 550e1051a39Sopenharmony_ci oid = sk_ASN1_OBJECT_value(policy_oids, i); 551e1051a39Sopenharmony_ci if (OBJ_obj2nid(oid) == NID_any_policy) { 552e1051a39Sopenharmony_ci tree->flags |= POLICY_FLAG_ANY_POLICY; 553e1051a39Sopenharmony_ci return 1; 554e1051a39Sopenharmony_ci } 555e1051a39Sopenharmony_ci } 556e1051a39Sopenharmony_ci 557e1051a39Sopenharmony_ci for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) { 558e1051a39Sopenharmony_ci oid = sk_ASN1_OBJECT_value(policy_oids, i); 559e1051a39Sopenharmony_ci node = ossl_policy_tree_find_sk(auth_nodes, oid); 560e1051a39Sopenharmony_ci if (!node) { 561e1051a39Sopenharmony_ci if (!anyPolicy) 562e1051a39Sopenharmony_ci continue; 563e1051a39Sopenharmony_ci /* 564e1051a39Sopenharmony_ci * Create a new node with policy ID from user set and qualifiers 565e1051a39Sopenharmony_ci * from anyPolicy. 566e1051a39Sopenharmony_ci */ 567e1051a39Sopenharmony_ci extra = ossl_policy_data_new(NULL, oid, node_critical(anyPolicy)); 568e1051a39Sopenharmony_ci if (extra == NULL) 569e1051a39Sopenharmony_ci return 0; 570e1051a39Sopenharmony_ci extra->qualifier_set = anyPolicy->data->qualifier_set; 571e1051a39Sopenharmony_ci extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS 572e1051a39Sopenharmony_ci | POLICY_DATA_FLAG_EXTRA_NODE; 573e1051a39Sopenharmony_ci node = ossl_policy_level_add_node(NULL, extra, anyPolicy->parent, 574e1051a39Sopenharmony_ci tree, 1); 575e1051a39Sopenharmony_ci if (node == NULL) { 576e1051a39Sopenharmony_ci ossl_policy_data_free(extra); 577e1051a39Sopenharmony_ci return 0; 578e1051a39Sopenharmony_ci } 579e1051a39Sopenharmony_ci } 580e1051a39Sopenharmony_ci if (!tree->user_policies) { 581e1051a39Sopenharmony_ci tree->user_policies = sk_X509_POLICY_NODE_new_null(); 582e1051a39Sopenharmony_ci if (!tree->user_policies) { 583e1051a39Sopenharmony_ci exnode_free(node); 584e1051a39Sopenharmony_ci return 0; 585e1051a39Sopenharmony_ci } 586e1051a39Sopenharmony_ci } 587e1051a39Sopenharmony_ci if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) { 588e1051a39Sopenharmony_ci exnode_free(node); 589e1051a39Sopenharmony_ci return 0; 590e1051a39Sopenharmony_ci } 591e1051a39Sopenharmony_ci } 592e1051a39Sopenharmony_ci return 1; 593e1051a39Sopenharmony_ci} 594e1051a39Sopenharmony_ci 595e1051a39Sopenharmony_ci/*- 596e1051a39Sopenharmony_ci * Return value: <= 0 error, otherwise one of: 597e1051a39Sopenharmony_ci * X509_PCY_TREE_VALID: valid tree 598e1051a39Sopenharmony_ci * X509_PCY_TREE_EMPTY: empty tree 599e1051a39Sopenharmony_ci * (see tree_prune()). 600e1051a39Sopenharmony_ci */ 601e1051a39Sopenharmony_cistatic int tree_evaluate(X509_POLICY_TREE *tree) 602e1051a39Sopenharmony_ci{ 603e1051a39Sopenharmony_ci int ret, i; 604e1051a39Sopenharmony_ci X509_POLICY_LEVEL *curr = tree->levels + 1; 605e1051a39Sopenharmony_ci const X509_POLICY_CACHE *cache; 606e1051a39Sopenharmony_ci 607e1051a39Sopenharmony_ci for (i = 1; i < tree->nlevel; i++, curr++) { 608e1051a39Sopenharmony_ci cache = ossl_policy_cache_set(curr->cert); 609e1051a39Sopenharmony_ci if (!tree_link_nodes(curr, cache, tree)) 610e1051a39Sopenharmony_ci return X509_PCY_TREE_INTERNAL; 611e1051a39Sopenharmony_ci 612e1051a39Sopenharmony_ci if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) 613e1051a39Sopenharmony_ci && !tree_link_any(curr, cache, tree)) 614e1051a39Sopenharmony_ci return X509_PCY_TREE_INTERNAL; 615e1051a39Sopenharmony_ci TREE_PRINT("before tree_prune()", tree, curr); 616e1051a39Sopenharmony_ci ret = tree_prune(tree, curr); 617e1051a39Sopenharmony_ci if (ret != X509_PCY_TREE_VALID) 618e1051a39Sopenharmony_ci return ret; 619e1051a39Sopenharmony_ci } 620e1051a39Sopenharmony_ci return X509_PCY_TREE_VALID; 621e1051a39Sopenharmony_ci} 622e1051a39Sopenharmony_ci 623e1051a39Sopenharmony_cistatic void exnode_free(X509_POLICY_NODE *node) 624e1051a39Sopenharmony_ci{ 625e1051a39Sopenharmony_ci if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE)) 626e1051a39Sopenharmony_ci OPENSSL_free(node); 627e1051a39Sopenharmony_ci} 628e1051a39Sopenharmony_ci 629e1051a39Sopenharmony_civoid X509_policy_tree_free(X509_POLICY_TREE *tree) 630e1051a39Sopenharmony_ci{ 631e1051a39Sopenharmony_ci X509_POLICY_LEVEL *curr; 632e1051a39Sopenharmony_ci int i; 633e1051a39Sopenharmony_ci 634e1051a39Sopenharmony_ci if (!tree) 635e1051a39Sopenharmony_ci return; 636e1051a39Sopenharmony_ci 637e1051a39Sopenharmony_ci sk_X509_POLICY_NODE_free(tree->auth_policies); 638e1051a39Sopenharmony_ci sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free); 639e1051a39Sopenharmony_ci 640e1051a39Sopenharmony_ci for (i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) { 641e1051a39Sopenharmony_ci X509_free(curr->cert); 642e1051a39Sopenharmony_ci sk_X509_POLICY_NODE_pop_free(curr->nodes, ossl_policy_node_free); 643e1051a39Sopenharmony_ci ossl_policy_node_free(curr->anyPolicy); 644e1051a39Sopenharmony_ci } 645e1051a39Sopenharmony_ci 646e1051a39Sopenharmony_ci sk_X509_POLICY_DATA_pop_free(tree->extra_data, ossl_policy_data_free); 647e1051a39Sopenharmony_ci OPENSSL_free(tree->levels); 648e1051a39Sopenharmony_ci OPENSSL_free(tree); 649e1051a39Sopenharmony_ci 650e1051a39Sopenharmony_ci} 651e1051a39Sopenharmony_ci 652e1051a39Sopenharmony_ci/*- 653e1051a39Sopenharmony_ci * Application policy checking function. 654e1051a39Sopenharmony_ci * Return codes: 655e1051a39Sopenharmony_ci * X509_PCY_TREE_FAILURE: Failure to satisfy explicit policy 656e1051a39Sopenharmony_ci * X509_PCY_TREE_INVALID: Inconsistent or invalid extensions 657e1051a39Sopenharmony_ci * X509_PCY_TREE_INTERNAL: Internal error, most likely malloc 658e1051a39Sopenharmony_ci * X509_PCY_TREE_VALID: Success (null tree if empty or bare TA) 659e1051a39Sopenharmony_ci */ 660e1051a39Sopenharmony_ciint X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, 661e1051a39Sopenharmony_ci STACK_OF(X509) *certs, 662e1051a39Sopenharmony_ci STACK_OF(ASN1_OBJECT) *policy_oids, unsigned int flags) 663e1051a39Sopenharmony_ci{ 664e1051a39Sopenharmony_ci int init_ret; 665e1051a39Sopenharmony_ci int ret; 666e1051a39Sopenharmony_ci int calc_ret; 667e1051a39Sopenharmony_ci X509_POLICY_TREE *tree = NULL; 668e1051a39Sopenharmony_ci STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL; 669e1051a39Sopenharmony_ci 670e1051a39Sopenharmony_ci *ptree = NULL; 671e1051a39Sopenharmony_ci *pexplicit_policy = 0; 672e1051a39Sopenharmony_ci init_ret = tree_init(&tree, certs, flags); 673e1051a39Sopenharmony_ci 674e1051a39Sopenharmony_ci if (init_ret <= 0) 675e1051a39Sopenharmony_ci return init_ret; 676e1051a39Sopenharmony_ci 677e1051a39Sopenharmony_ci if ((init_ret & X509_PCY_TREE_EXPLICIT) == 0) { 678e1051a39Sopenharmony_ci if (init_ret & X509_PCY_TREE_EMPTY) { 679e1051a39Sopenharmony_ci X509_policy_tree_free(tree); 680e1051a39Sopenharmony_ci return X509_PCY_TREE_VALID; 681e1051a39Sopenharmony_ci } 682e1051a39Sopenharmony_ci } else { 683e1051a39Sopenharmony_ci *pexplicit_policy = 1; 684e1051a39Sopenharmony_ci /* Tree empty and requireExplicit True: Error */ 685e1051a39Sopenharmony_ci if (init_ret & X509_PCY_TREE_EMPTY) 686e1051a39Sopenharmony_ci return X509_PCY_TREE_FAILURE; 687e1051a39Sopenharmony_ci } 688e1051a39Sopenharmony_ci 689e1051a39Sopenharmony_ci ret = tree_evaluate(tree); 690e1051a39Sopenharmony_ci TREE_PRINT("tree_evaluate()", tree, NULL); 691e1051a39Sopenharmony_ci if (ret <= 0) 692e1051a39Sopenharmony_ci goto error; 693e1051a39Sopenharmony_ci 694e1051a39Sopenharmony_ci if (ret == X509_PCY_TREE_EMPTY) { 695e1051a39Sopenharmony_ci X509_policy_tree_free(tree); 696e1051a39Sopenharmony_ci if (init_ret & X509_PCY_TREE_EXPLICIT) 697e1051a39Sopenharmony_ci return X509_PCY_TREE_FAILURE; 698e1051a39Sopenharmony_ci return X509_PCY_TREE_VALID; 699e1051a39Sopenharmony_ci } 700e1051a39Sopenharmony_ci 701e1051a39Sopenharmony_ci /* Tree is not empty: continue */ 702e1051a39Sopenharmony_ci 703e1051a39Sopenharmony_ci if ((calc_ret = tree_calculate_authority_set(tree, &auth_nodes)) == 0) 704e1051a39Sopenharmony_ci goto error; 705e1051a39Sopenharmony_ci ret = tree_calculate_user_set(tree, policy_oids, auth_nodes); 706e1051a39Sopenharmony_ci if (calc_ret == TREE_CALC_OK_DOFREE) 707e1051a39Sopenharmony_ci sk_X509_POLICY_NODE_free(auth_nodes); 708e1051a39Sopenharmony_ci if (!ret) 709e1051a39Sopenharmony_ci goto error; 710e1051a39Sopenharmony_ci 711e1051a39Sopenharmony_ci *ptree = tree; 712e1051a39Sopenharmony_ci 713e1051a39Sopenharmony_ci if (init_ret & X509_PCY_TREE_EXPLICIT) { 714e1051a39Sopenharmony_ci nodes = X509_policy_tree_get0_user_policies(tree); 715e1051a39Sopenharmony_ci if (sk_X509_POLICY_NODE_num(nodes) <= 0) 716e1051a39Sopenharmony_ci return X509_PCY_TREE_FAILURE; 717e1051a39Sopenharmony_ci } 718e1051a39Sopenharmony_ci return X509_PCY_TREE_VALID; 719e1051a39Sopenharmony_ci 720e1051a39Sopenharmony_ci error: 721e1051a39Sopenharmony_ci X509_policy_tree_free(tree); 722e1051a39Sopenharmony_ci return X509_PCY_TREE_INTERNAL; 723e1051a39Sopenharmony_ci} 724