1*169e56b9Stb /* $OpenBSD: x509_policy.c,v 1.29 2025/01/06 17:42:39 tb Exp $ */ 2e59b13feStb /* 3e59b13feStb * Copyright (c) 2022, Google Inc. 425478f03Sbeck * 525478f03Sbeck * Permission to use, copy, modify, and/or distribute this software for any 625478f03Sbeck * purpose with or without fee is hereby granted, provided that the above 725478f03Sbeck * copyright notice and this permission notice appear in all copies. 825478f03Sbeck * 925478f03Sbeck * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1025478f03Sbeck * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1125478f03Sbeck * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 1225478f03Sbeck * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1325478f03Sbeck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 1425478f03Sbeck * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 15e59b13feStb * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16e59b13feStb */ 1725478f03Sbeck 18224b605eSbeck #include <string.h> 1925478f03Sbeck 20e4817b8bSbeck #include <openssl/err.h> 21224b605eSbeck #include <openssl/objects.h> 2225478f03Sbeck #include <openssl/stack.h> 236290bf8cStb #include <openssl/x509.h> 2425478f03Sbeck #include <openssl/x509v3.h> 2525478f03Sbeck 26b9351927Stb #include "stack_local.h" 27224b605eSbeck #include "x509_internal.h" 28224b605eSbeck #include "x509_local.h" 2925478f03Sbeck 30e4817b8bSbeck /* XXX move to proper place */ 31e4817b8bSbeck #define X509_R_INVALID_POLICY_EXTENSION 201 3225478f03Sbeck 33e59b13feStb /* 3404337d59Stb * This file computes the X.509 policy tree, as described in RFC 5280, 3504337d59Stb * section 6.1 and RFC 9618. It differs in that: 36e59b13feStb * 37e59b13feStb * (1) It does not track "qualifier_set". This is not needed as it is not 38e59b13feStb * output by this implementation. 39e59b13feStb * 40e59b13feStb * (2) It builds a directed acyclic graph, rather than a tree. When a given 41e59b13feStb * policy matches multiple parents, RFC 5280 makes a separate node for 42e59b13feStb * each parent. This representation condenses them into one node with 43e59b13feStb * multiple parents. Thus we refer to this structure as a "policy graph", 44e59b13feStb * rather than a "policy tree". 45e59b13feStb * 46e59b13feStb * (3) "expected_policy_set" is not tracked explicitly and built temporarily 47e59b13feStb * as part of building the graph. 48e59b13feStb * 49e59b13feStb * (4) anyPolicy nodes are not tracked explicitly. 50e59b13feStb * 51e59b13feStb * (5) Some pruning steps are deferred to when policies are evaluated, as a 52e59b13feStb * reachability pass. 53e59b13feStb */ 5425478f03Sbeck 55e59b13feStb /* 56e59b13feStb * An X509_POLICY_NODE is a node in the policy graph. It corresponds to a node 57e59b13feStb * from RFC 5280, section 6.1.2, step (a), but we store some fields differently. 58e59b13feStb */ 5925478f03Sbeck typedef struct x509_policy_node_st { 60e59b13feStb /* policy is the "valid_policy" field from RFC 5280. */ 6125478f03Sbeck ASN1_OBJECT *policy; 6225478f03Sbeck 63e59b13feStb /* 64e59b13feStb * parent_policies, if non-empty, is the list of "valid_policy" values 65e59b13feStb * for all nodes which are a parent of this node. In this case, no entry 66e59b13feStb * in this list will be anyPolicy. This list is in no particular order 67e59b13feStb * and may contain duplicates if the corresponding certificate had 68e59b13feStb * duplicate mappings. 69e59b13feStb * 70e59b13feStb * If empty, this node has a single parent, anyPolicy. The node is then 71e59b13feStb * a root policies, and is in authorities-constrained-policy-set if it 72e59b13feStb * has a path to a leaf node. 73e59b13feStb * 74e59b13feStb * Note it is not possible for a policy to have both anyPolicy and a 75e59b13feStb * concrete policy as a parent. Section 6.1.3, step (d.1.ii) only runs 76e59b13feStb * if there was no match in step (d.1.i). We do not need to represent a 77e59b13feStb * parent list of, say, {anyPolicy, OID1, OID2}. 78e59b13feStb */ 7925478f03Sbeck STACK_OF(ASN1_OBJECT) *parent_policies; 8025478f03Sbeck 81e59b13feStb /* 82e59b13feStb * mapped is one if this node matches a policy mapping in the 83e59b13feStb * certificate and zero otherwise. 84e59b13feStb */ 8525478f03Sbeck int mapped; 8625478f03Sbeck 87e59b13feStb /* 88e59b13feStb * reachable is one if this node is reachable from some valid policy in 89e59b13feStb * the end-entity certificate. It is computed during |has_explicit_policy|. 90e59b13feStb */ 9125478f03Sbeck int reachable; 9225478f03Sbeck } X509_POLICY_NODE; 9325478f03Sbeck 94c9883637Sbeck DECLARE_STACK_OF(X509_POLICY_NODE) 95c9883637Sbeck 96c9883637Sbeck #define sk_X509_POLICY_NODE_new(cmp) SKM_sk_new(X509_POLICY_NODE, (cmp)) 97c9883637Sbeck #define sk_X509_POLICY_NODE_new_null() SKM_sk_new_null(X509_POLICY_NODE) 98c9883637Sbeck #define sk_X509_POLICY_NODE_free(st) SKM_sk_free(X509_POLICY_NODE, (st)) 99c9883637Sbeck #define sk_X509_POLICY_NODE_num(st) SKM_sk_num(X509_POLICY_NODE, (st)) 100c9883637Sbeck #define sk_X509_POLICY_NODE_value(st, i) SKM_sk_value(X509_POLICY_NODE, (st), (i)) 101c9883637Sbeck #define sk_X509_POLICY_NODE_set(st, i, val) SKM_sk_set(X509_POLICY_NODE, (st), (i), (val)) 102c9883637Sbeck #define sk_X509_POLICY_NODE_zero(st) SKM_sk_zero(X509_POLICY_NODE, (st)) 103c9883637Sbeck #define sk_X509_POLICY_NODE_push(st, val) SKM_sk_push(X509_POLICY_NODE, (st), (val)) 104c9883637Sbeck #define sk_X509_POLICY_NODE_unshift(st, val) SKM_sk_unshift(X509_POLICY_NODE, (st), (val)) 105c9883637Sbeck #define sk_X509_POLICY_NODE_find(st, val) SKM_sk_find(X509_POLICY_NODE, (st), (val)) 106c9883637Sbeck #define sk_X509_POLICY_NODE_delete(st, i) SKM_sk_delete(X509_POLICY_NODE, (st), (i)) 107c9883637Sbeck #define sk_X509_POLICY_NODE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_NODE, (st), (ptr)) 108c9883637Sbeck #define sk_X509_POLICY_NODE_insert(st, val, i) SKM_sk_insert(X509_POLICY_NODE, (st), (val), (i)) 109c9883637Sbeck #define sk_X509_POLICY_NODE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_NODE, (st), (cmp)) 110c9883637Sbeck #define sk_X509_POLICY_NODE_dup(st) SKM_sk_dup(X509_POLICY_NODE, st) 111c9883637Sbeck #define sk_X509_POLICY_NODE_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_NODE, (st), (free_func)) 112c9883637Sbeck #define sk_X509_POLICY_NODE_shift(st) SKM_sk_shift(X509_POLICY_NODE, (st)) 113c9883637Sbeck #define sk_X509_POLICY_NODE_pop(st) SKM_sk_pop(X509_POLICY_NODE, (st)) 114c9883637Sbeck #define sk_X509_POLICY_NODE_sort(st) SKM_sk_sort(X509_POLICY_NODE, (st)) 115c9883637Sbeck #define sk_X509_POLICY_NODE_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_NODE, (st)) 11625478f03Sbeck 117e59b13feStb /* 118e59b13feStb * An X509_POLICY_LEVEL is the collection of nodes at the same depth in the 119e59b13feStb * policy graph. This structure can also be used to represent a level's 120e59b13feStb * "expected_policy_set" values. See |process_policy_mappings|. 121e59b13feStb */ 12225478f03Sbeck typedef struct x509_policy_level_st { 123e59b13feStb /* 124e59b13feStb * nodes is the list of nodes at this depth, except for the anyPolicy 125e59b13feStb * node, if any. This list is sorted by policy OID for efficient lookup. 126e59b13feStb */ 12725478f03Sbeck STACK_OF(X509_POLICY_NODE) *nodes; 12825478f03Sbeck 129e59b13feStb /* 130e59b13feStb * has_any_policy is one if there is an anyPolicy node at this depth, 131e59b13feStb * and zero otherwise. 132e59b13feStb */ 13325478f03Sbeck int has_any_policy; 13425478f03Sbeck } X509_POLICY_LEVEL; 13525478f03Sbeck 136c9883637Sbeck DECLARE_STACK_OF(X509_POLICY_LEVEL) 137c9883637Sbeck 138c9883637Sbeck #define sk_X509_POLICY_LEVEL_new(cmp) SKM_sk_new(X509_POLICY_LEVEL, (cmp)) 139c9883637Sbeck #define sk_X509_POLICY_LEVEL_new_null() SKM_sk_new_null(X509_POLICY_LEVEL) 140c9883637Sbeck #define sk_X509_POLICY_LEVEL_free(st) SKM_sk_free(X509_POLICY_LEVEL, (st)) 141c9883637Sbeck #define sk_X509_POLICY_LEVEL_num(st) SKM_sk_num(X509_POLICY_LEVEL, (st)) 142c9883637Sbeck #define sk_X509_POLICY_LEVEL_value(st, i) SKM_sk_value(X509_POLICY_LEVEL, (st), (i)) 143c9883637Sbeck #define sk_X509_POLICY_LEVEL_set(st, i, val) SKM_sk_set(X509_POLICY_LEVEL, (st), (i), (val)) 144c9883637Sbeck #define sk_X509_POLICY_LEVEL_zero(st) SKM_sk_zero(X509_POLICY_LEVEL, (st)) 145c9883637Sbeck #define sk_X509_POLICY_LEVEL_push(st, val) SKM_sk_push(X509_POLICY_LEVEL, (st), (val)) 146c9883637Sbeck #define sk_X509_POLICY_LEVEL_unshift(st, val) SKM_sk_unshift(X509_POLICY_LEVEL, (st), (val)) 147c9883637Sbeck #define sk_X509_POLICY_LEVEL_find(st, val) SKM_sk_find(X509_POLICY_LEVEL, (st), (val)) 148c9883637Sbeck #define sk_X509_POLICY_LEVEL_delete(st, i) SKM_sk_delete(X509_POLICY_LEVEL, (st), (i)) 149c9883637Sbeck #define sk_X509_POLICY_LEVEL_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_LEVEL, (st), (ptr)) 150c9883637Sbeck #define sk_X509_POLICY_LEVEL_insert(st, val, i) SKM_sk_insert(X509_POLICY_LEVEL, (st), (val), (i)) 151c9883637Sbeck #define sk_X509_POLICY_LEVEL_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_LEVEL, (st), (cmp)) 152c9883637Sbeck #define sk_X509_POLICY_LEVEL_dup(st) SKM_sk_dup(X509_POLICY_LEVEL, st) 153c9883637Sbeck #define sk_X509_POLICY_LEVEL_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_LEVEL, (st), (free_func)) 154c9883637Sbeck #define sk_X509_POLICY_LEVEL_shift(st) SKM_sk_shift(X509_POLICY_LEVEL, (st)) 155c9883637Sbeck #define sk_X509_POLICY_LEVEL_pop(st) SKM_sk_pop(X509_POLICY_LEVEL, (st)) 156c9883637Sbeck #define sk_X509_POLICY_LEVEL_sort(st) SKM_sk_sort(X509_POLICY_LEVEL, (st)) 157c9883637Sbeck #define sk_X509_POLICY_LEVEL_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_LEVEL, (st)) 15825478f03Sbeck 1595e44526eSbeck /* 1605e44526eSbeck * Don't look Ethel, but you would really not want to look if we did 1615e44526eSbeck * this the OpenSSL way either, and we are not using this boringsslism 162ac13ea69Stb * anywhere else. Callers should ensure that the stack in data is sorted. 1635e44526eSbeck */ 1645e44526eSbeck void 1655e44526eSbeck sk_X509_POLICY_NODE_delete_if(STACK_OF(X509_POLICY_NODE) *nodes, 16678fe41cbStb int (*delete_if)(X509_POLICY_NODE *, void *), void *data) 1675e44526eSbeck { 1685e44526eSbeck _STACK *sk = (_STACK *)nodes; 1695e44526eSbeck X509_POLICY_NODE *node; 1705e44526eSbeck int new_num = 0; 1715e44526eSbeck int i; 1725e44526eSbeck 1735e44526eSbeck for (i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) { 1745e44526eSbeck node = sk_X509_POLICY_NODE_value(nodes, i); 1755e44526eSbeck if (!delete_if(node, data)) 1765e44526eSbeck sk->data[new_num++] = (char *)node; 1775e44526eSbeck } 1785e44526eSbeck sk->num = new_num; 1795e44526eSbeck } 1805e44526eSbeck 1812018f220Stb static int 1822018f220Stb is_any_policy(const ASN1_OBJECT *obj) 1832018f220Stb { 18425478f03Sbeck return OBJ_obj2nid(obj) == NID_any_policy; 18525478f03Sbeck } 18625478f03Sbeck 1872018f220Stb static void 1882018f220Stb x509_policy_node_free(X509_POLICY_NODE *node) 1892018f220Stb { 1905583d2a5Stb if (node == NULL) 1915583d2a5Stb return; 1925583d2a5Stb 19325478f03Sbeck ASN1_OBJECT_free(node->policy); 1945583d2a5Stb sk_ASN1_OBJECT_pop_free(node->parent_policies, ASN1_OBJECT_free); 195c4305e2eSbeck free(node); 19625478f03Sbeck } 19725478f03Sbeck 1982018f220Stb static X509_POLICY_NODE * 1992018f220Stb x509_policy_node_new(const ASN1_OBJECT *policy) 2002018f220Stb { 201e52ec74dStb X509_POLICY_NODE *node = NULL; 2025583d2a5Stb 203e52ec74dStb if (is_any_policy(policy)) 204e52ec74dStb goto err; 2055583d2a5Stb if ((node = calloc(1, sizeof(*node))) == NULL) 2065583d2a5Stb goto err; 2075583d2a5Stb if ((node->policy = OBJ_dup(policy)) == NULL) 2085583d2a5Stb goto err; 2095583d2a5Stb if ((node->parent_policies = sk_ASN1_OBJECT_new_null()) == NULL) 2105583d2a5Stb goto err; 2115583d2a5Stb 2125583d2a5Stb return node; 2135583d2a5Stb 2145583d2a5Stb err: 21525478f03Sbeck x509_policy_node_free(node); 21625478f03Sbeck return NULL; 21725478f03Sbeck } 21825478f03Sbeck 2192018f220Stb static int 2202018f220Stb x509_policy_node_cmp(const X509_POLICY_NODE *const *a, 2212018f220Stb const X509_POLICY_NODE *const *b) 2222018f220Stb { 22325478f03Sbeck return OBJ_cmp((*a)->policy, (*b)->policy); 22425478f03Sbeck } 22525478f03Sbeck 2262018f220Stb static void 2272018f220Stb x509_policy_level_free(X509_POLICY_LEVEL *level) 2282018f220Stb { 2295583d2a5Stb if (level == NULL) 2305583d2a5Stb return; 2315583d2a5Stb 2325583d2a5Stb sk_X509_POLICY_NODE_pop_free(level->nodes, x509_policy_node_free); 233c4305e2eSbeck free(level); 23425478f03Sbeck } 23525478f03Sbeck 2362018f220Stb static X509_POLICY_LEVEL * 2372018f220Stb x509_policy_level_new(void) 2382018f220Stb { 2395583d2a5Stb X509_POLICY_LEVEL *level; 2405583d2a5Stb 2415583d2a5Stb if ((level = calloc(1, sizeof(*level))) == NULL) 2425583d2a5Stb goto err; 24325478f03Sbeck level->nodes = sk_X509_POLICY_NODE_new(x509_policy_node_cmp); 2445583d2a5Stb if (level->nodes == NULL) 2455583d2a5Stb goto err; 2465583d2a5Stb 2475583d2a5Stb return level; 2485583d2a5Stb 2495583d2a5Stb err: 25025478f03Sbeck x509_policy_level_free(level); 25125478f03Sbeck return NULL; 25225478f03Sbeck } 25325478f03Sbeck 2542018f220Stb static int 2552018f220Stb x509_policy_level_is_empty(const X509_POLICY_LEVEL *level) 2562018f220Stb { 25778fe41cbStb if (level->has_any_policy) 25878fe41cbStb return 0; 25978fe41cbStb 26078fe41cbStb return sk_X509_POLICY_NODE_num(level->nodes) == 0; 26125478f03Sbeck } 26225478f03Sbeck 2632018f220Stb static void 2642018f220Stb x509_policy_level_clear(X509_POLICY_LEVEL *level) 2652018f220Stb { 26678fe41cbStb X509_POLICY_NODE *node; 2673b6f7f9fSbeck int i; 268ea2d6ca4Stb 26925478f03Sbeck level->has_any_policy = 0; 270ea2d6ca4Stb for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) { 27178fe41cbStb node = sk_X509_POLICY_NODE_value(level->nodes, i); 27278fe41cbStb x509_policy_node_free(node); 27325478f03Sbeck } 27425478f03Sbeck sk_X509_POLICY_NODE_zero(level->nodes); 27525478f03Sbeck } 27625478f03Sbeck 277e59b13feStb /* 278e59b13feStb * x509_policy_level_find returns the node in |level| corresponding to |policy|, 2795e6c7225Stb * or NULL if none exists. Callers should ensure that level->nodes is sorted 2805e6c7225Stb * to avoid the cost of sorting it in sk_find(). 281e59b13feStb */ 2822018f220Stb static X509_POLICY_NODE * 2835e6c7225Stb x509_policy_level_find(X509_POLICY_LEVEL *level, const ASN1_OBJECT *policy) 2842018f220Stb { 28525478f03Sbeck X509_POLICY_NODE node; 28625478f03Sbeck node.policy = (ASN1_OBJECT *)policy; 2870d1e3181Sbeck int idx; 2885e6c7225Stb 289a211c03aStb if ((idx = sk_X509_POLICY_NODE_find(level->nodes, &node)) < 0) 29025478f03Sbeck return NULL; 29125478f03Sbeck return sk_X509_POLICY_NODE_value(level->nodes, idx); 29225478f03Sbeck } 29325478f03Sbeck 294e59b13feStb /* 295e59b13feStb * x509_policy_level_add_nodes adds the nodes in |nodes| to |level|. It returns 296e59b13feStb * one on success and zero on error. No policy in |nodes| may already be present 297e59b13feStb * in |level|. This function modifies |nodes| to avoid making a copy, but the 298e59b13feStb * caller is still responsible for releasing |nodes| itself. 299e59b13feStb * 300e59b13feStb * This function is used to add nodes to |level| in bulk, and avoid resorting 301e59b13feStb * |level| after each addition. 302e59b13feStb */ 3032018f220Stb static int 3042018f220Stb x509_policy_level_add_nodes(X509_POLICY_LEVEL *level, 3052018f220Stb STACK_OF(X509_POLICY_NODE) *nodes) 3062018f220Stb { 3073b6f7f9fSbeck int i; 308ea2d6ca4Stb 309ea2d6ca4Stb for (i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) { 31025478f03Sbeck X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(nodes, i); 311a211c03aStb if (!sk_X509_POLICY_NODE_push(level->nodes, node)) 31225478f03Sbeck return 0; 31325478f03Sbeck sk_X509_POLICY_NODE_set(nodes, i, NULL); 31425478f03Sbeck } 31525478f03Sbeck sk_X509_POLICY_NODE_sort(level->nodes); 31625478f03Sbeck 31725478f03Sbeck return 1; 31825478f03Sbeck } 31925478f03Sbeck 3202018f220Stb static int 3212018f220Stb policyinfo_cmp(const POLICYINFO *const *a, 3222018f220Stb const POLICYINFO *const *b) 3232018f220Stb { 32425478f03Sbeck return OBJ_cmp((*a)->policyid, (*b)->policyid); 32525478f03Sbeck } 32625478f03Sbeck 3272018f220Stb static int 3282018f220Stb delete_if_not_in_policies(X509_POLICY_NODE *node, void *data) 3292018f220Stb { 33025478f03Sbeck const CERTIFICATEPOLICIES *policies = data; 33125478f03Sbeck POLICYINFO info; 33225478f03Sbeck info.policyid = node->policy; 333ac13ea69Stb 334a211c03aStb if (sk_POLICYINFO_find(policies, &info) >= 0) 33525478f03Sbeck return 0; 33625478f03Sbeck x509_policy_node_free(node); 33725478f03Sbeck return 1; 33825478f03Sbeck } 33925478f03Sbeck 340e59b13feStb /* 341e59b13feStb * process_certificate_policies updates |level| to incorporate |x509|'s 342e59b13feStb * certificate policies extension. This implements steps (d) and (e) of RFC 343e59b13feStb * 5280, section 6.1.3. |level| must contain the previous level's 344e59b13feStb * "expected_policy_set" information. For all but the top-most level, this is 345e59b13feStb * the output of |process_policy_mappings|. |any_policy_allowed| specifies 346e59b13feStb * whether anyPolicy is allowed or inhibited, taking into account the exception 347e59b13feStb * for self-issued certificates. 348e59b13feStb */ 3492018f220Stb static int 35078fe41cbStb process_certificate_policies(const X509 *x509, X509_POLICY_LEVEL *level, 3512018f220Stb int any_policy_allowed) 3522018f220Stb { 35325478f03Sbeck STACK_OF(X509_POLICY_NODE) *new_nodes = NULL; 35478fe41cbStb CERTIFICATEPOLICIES *policies; 35578fe41cbStb const POLICYINFO *policy; 35678fe41cbStb X509_POLICY_NODE *node; 35778fe41cbStb int cert_has_any_policy, critical, i, previous_level_has_any_policy; 35878fe41cbStb int ret = 0; 35978fe41cbStb 36078fe41cbStb policies = X509_get_ext_d2i(x509, NID_certificate_policies, &critical, 36178fe41cbStb NULL); 36225478f03Sbeck if (policies == NULL) { 363a211c03aStb if (critical != -1) 364e59b13feStb return 0; /* Syntax error in the extension. */ 36525478f03Sbeck 366e59b13feStb /* RFC 5280, section 6.1.3, step (e). */ 36725478f03Sbeck x509_policy_level_clear(level); 36825478f03Sbeck return 1; 36925478f03Sbeck } 37025478f03Sbeck 371e59b13feStb /* 372e59b13feStb * certificatePolicies may not be empty. See RFC 5280, section 4.2.1.4. 373e59b13feStb * TODO(https://crbug.com/boringssl/443): Move this check into the parser. 374e59b13feStb */ 37525478f03Sbeck if (sk_POLICYINFO_num(policies) == 0) { 376e4817b8bSbeck X509error(X509_R_INVALID_POLICY_EXTENSION); 37725478f03Sbeck goto err; 37825478f03Sbeck } 37925478f03Sbeck 3804ec1749bStb (void)sk_POLICYINFO_set_cmp_func(policies, policyinfo_cmp); 38125478f03Sbeck sk_POLICYINFO_sort(policies); 38278fe41cbStb cert_has_any_policy = 0; 383ea2d6ca4Stb for (i = 0; i < sk_POLICYINFO_num(policies); i++) { 38478fe41cbStb policy = sk_POLICYINFO_value(policies, i); 385a211c03aStb if (is_any_policy(policy->policyid)) 38625478f03Sbeck cert_has_any_policy = 1; 3872018f220Stb if (i > 0 && 3882018f220Stb OBJ_cmp(sk_POLICYINFO_value(policies, i - 1)->policyid, 38925478f03Sbeck policy->policyid) == 0) { 390e59b13feStb /* 391e59b13feStb * Per RFC 5280, section 4.2.1.4, |policies| may not 392e59b13feStb * have duplicates. 393e59b13feStb */ 394e4817b8bSbeck X509error(X509_R_INVALID_POLICY_EXTENSION); 39525478f03Sbeck goto err; 39625478f03Sbeck } 39725478f03Sbeck } 39825478f03Sbeck 399e59b13feStb /* 400e59b13feStb * This does the same thing as RFC 5280, section 6.1.3, step (d), 401*169e56b9Stb * though in a slightly different order. |level| currently contains 402e59b13feStb * "expected_policy_set" values of the previous level. 403e59b13feStb * See |process_policy_mappings| for details. 404e59b13feStb */ 40578fe41cbStb previous_level_has_any_policy = level->has_any_policy; 40625478f03Sbeck 407e59b13feStb /* 408e59b13feStb * First, we handle steps (d.1.i) and (d.2). The net effect of these 409e59b13feStb * two steps is to intersect |level| with |policies|, ignoring 410e59b13feStb * anyPolicy if it is inhibited. 411e59b13feStb */ 41225478f03Sbeck if (!cert_has_any_policy || !any_policy_allowed) { 413ac13ea69Stb if (!sk_POLICYINFO_is_sorted(policies)) 414ac13ea69Stb goto err; 4152018f220Stb sk_X509_POLICY_NODE_delete_if(level->nodes, 4162018f220Stb delete_if_not_in_policies, policies); 41725478f03Sbeck level->has_any_policy = 0; 41825478f03Sbeck } 41925478f03Sbeck 420e59b13feStb /* 421e59b13feStb * Step (d.1.ii) may attach new nodes to the previous level's anyPolicy 422e59b13feStb * node. 423e59b13feStb */ 42425478f03Sbeck if (previous_level_has_any_policy) { 42525478f03Sbeck new_nodes = sk_X509_POLICY_NODE_new_null(); 426a211c03aStb if (new_nodes == NULL) 42725478f03Sbeck goto err; 428ea2d6ca4Stb for (i = 0; i < sk_POLICYINFO_num(policies); i++) { 42978fe41cbStb policy = sk_POLICYINFO_value(policies, i); 430e59b13feStb /* 431e59b13feStb * Though we've reordered the steps slightly, |policy| 432e59b13feStb * is in |level| if and only if it would have been a 433e59b13feStb * match in step (d.1.ii). 434e59b13feStb */ 4355e6c7225Stb if (is_any_policy(policy->policyid)) 4365e6c7225Stb continue; 4375e6c7225Stb if (!sk_X509_POLICY_NODE_is_sorted(level->nodes)) 4385e6c7225Stb goto err; 4395e6c7225Stb if (x509_policy_level_find(level, policy->policyid) != NULL) 4405e6c7225Stb continue; 44178fe41cbStb node = x509_policy_node_new(policy->policyid); 442e59b13feStb if (node == NULL || 44378fe41cbStb !sk_X509_POLICY_NODE_push(new_nodes, node)) { 44425478f03Sbeck x509_policy_node_free(node); 44525478f03Sbeck goto err; 44625478f03Sbeck } 44725478f03Sbeck } 448a211c03aStb if (!x509_policy_level_add_nodes(level, new_nodes)) 44925478f03Sbeck goto err; 45025478f03Sbeck } 45125478f03Sbeck 45225478f03Sbeck ret = 1; 45325478f03Sbeck 45425478f03Sbeck err: 45525478f03Sbeck sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free); 45625478f03Sbeck CERTIFICATEPOLICIES_free(policies); 45725478f03Sbeck return ret; 45825478f03Sbeck } 45925478f03Sbeck 4602018f220Stb static int 4612018f220Stb compare_issuer_policy(const POLICY_MAPPING *const *a, 4622018f220Stb const POLICY_MAPPING *const *b) 4632018f220Stb { 46425478f03Sbeck return OBJ_cmp((*a)->issuerDomainPolicy, (*b)->issuerDomainPolicy); 46525478f03Sbeck } 46625478f03Sbeck 4672018f220Stb static int 4682018f220Stb compare_subject_policy(const POLICY_MAPPING *const *a, 4692018f220Stb const POLICY_MAPPING *const *b) 4702018f220Stb { 47125478f03Sbeck return OBJ_cmp((*a)->subjectDomainPolicy, (*b)->subjectDomainPolicy); 47225478f03Sbeck } 47325478f03Sbeck 4742018f220Stb static int 4752018f220Stb delete_if_mapped(X509_POLICY_NODE *node, void *data) 4762018f220Stb { 47725478f03Sbeck const POLICY_MAPPINGS *mappings = data; 47825478f03Sbeck POLICY_MAPPING mapping; 47925478f03Sbeck mapping.issuerDomainPolicy = node->policy; 480a211c03aStb if (sk_POLICY_MAPPING_find(mappings, &mapping) < 0) 48125478f03Sbeck return 0; 48225478f03Sbeck x509_policy_node_free(node); 48325478f03Sbeck return 1; 48425478f03Sbeck } 48525478f03Sbeck 486e59b13feStb /* 487e59b13feStb * process_policy_mappings processes the policy mappings extension of |cert|, 488e59b13feStb * whose corresponding graph level is |level|. |mapping_allowed| specifies 489e59b13feStb * whether policy mapping is inhibited at this point. On success, it returns an 490e59b13feStb * |X509_POLICY_LEVEL| containing the "expected_policy_set" for |level|. On 491e59b13feStb * error, it returns NULL. This implements steps (a) and (b) of RFC 5280, 492e59b13feStb * section 6.1.4. 493e59b13feStb * 494e59b13feStb * We represent the "expected_policy_set" as an |X509_POLICY_LEVEL|. 495e59b13feStb * |has_any_policy| indicates whether there is an anyPolicy node with 496e59b13feStb * "expected_policy_set" of {anyPolicy}. If a node with policy oid P1 contains 497e59b13feStb * P2 in its "expected_policy_set", the level will contain a node of policy P2 498e59b13feStb * with P1 in |parent_policies|. 499e59b13feStb * 500e59b13feStb * This is equivalent to the |X509_POLICY_LEVEL| that would result if the next 501e59b13feStb * certificats contained anyPolicy. |process_certificate_policies| will filter 502e59b13feStb * this result down to compute the actual level. 503e59b13feStb */ 5042018f220Stb static X509_POLICY_LEVEL * 5052018f220Stb process_policy_mappings(const X509 *cert, 50625478f03Sbeck X509_POLICY_LEVEL *level, 5072018f220Stb int mapping_allowed) 5082018f220Stb { 50925478f03Sbeck STACK_OF(X509_POLICY_NODE) *new_nodes = NULL; 51078fe41cbStb POLICY_MAPPINGS *mappings; 51178fe41cbStb const ASN1_OBJECT *last_policy; 51278fe41cbStb POLICY_MAPPING *mapping; 51325478f03Sbeck X509_POLICY_LEVEL *next = NULL; 51478fe41cbStb X509_POLICY_NODE *node; 51578fe41cbStb int critical, i; 51678fe41cbStb int ok = 0; 51778fe41cbStb 51878fe41cbStb mappings = X509_get_ext_d2i(cert, NID_policy_mappings, &critical, NULL); 51925478f03Sbeck if (mappings == NULL && critical != -1) { 520e59b13feStb /* Syntax error in the policy mappings extension. */ 52125478f03Sbeck goto err; 52225478f03Sbeck } 52325478f03Sbeck 52425478f03Sbeck if (mappings != NULL) { 525e59b13feStb /* 526e59b13feStb * PolicyMappings may not be empty. See RFC 5280, section 4.2.1.5. 527e59b13feStb * TODO(https://crbug.com/boringssl/443): Move this check into 528e59b13feStb * the parser. 529e59b13feStb */ 53025478f03Sbeck if (sk_POLICY_MAPPING_num(mappings) == 0) { 531e4817b8bSbeck X509error(X509_R_INVALID_POLICY_EXTENSION); 53225478f03Sbeck goto err; 53325478f03Sbeck } 53425478f03Sbeck 535e59b13feStb /* RFC 5280, section 6.1.4, step (a). */ 536ea2d6ca4Stb for (i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) { 53778fe41cbStb mapping = sk_POLICY_MAPPING_value(mappings, i); 53825478f03Sbeck if (is_any_policy(mapping->issuerDomainPolicy) || 539a211c03aStb is_any_policy(mapping->subjectDomainPolicy)) 54025478f03Sbeck goto err; 54125478f03Sbeck } 54225478f03Sbeck 543e59b13feStb /* Sort to group by issuerDomainPolicy. */ 5444ec1749bStb (void)sk_POLICY_MAPPING_set_cmp_func(mappings, 5454ec1749bStb compare_issuer_policy); 54625478f03Sbeck sk_POLICY_MAPPING_sort(mappings); 54725478f03Sbeck 54825478f03Sbeck if (mapping_allowed) { 549e59b13feStb /* 550e59b13feStb * Mark nodes as mapped, and add any nodes to |level| 551e59b13feStb * which may be needed as part of RFC 5280, 552e59b13feStb * section 6.1.4, step (b.1). 553e59b13feStb */ 55425478f03Sbeck new_nodes = sk_X509_POLICY_NODE_new_null(); 555a211c03aStb if (new_nodes == NULL) 55625478f03Sbeck goto err; 55778fe41cbStb last_policy = NULL; 55878fe41cbStb for (i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) { 55978fe41cbStb mapping = sk_POLICY_MAPPING_value(mappings, i); 560e59b13feStb /* 561e59b13feStb * There may be multiple mappings with the same 562e59b13feStb * |issuerDomainPolicy|. 563e59b13feStb */ 56425478f03Sbeck if (last_policy != NULL && 5652018f220Stb OBJ_cmp(mapping->issuerDomainPolicy, 566a211c03aStb last_policy) == 0) 56725478f03Sbeck continue; 56825478f03Sbeck last_policy = mapping->issuerDomainPolicy; 56925478f03Sbeck 5705e6c7225Stb if (!sk_X509_POLICY_NODE_is_sorted(level->nodes)) 5715e6c7225Stb goto err; 57278fe41cbStb node = x509_policy_level_find(level, 5732018f220Stb mapping->issuerDomainPolicy); 57425478f03Sbeck if (node == NULL) { 575a211c03aStb if (!level->has_any_policy) 57625478f03Sbeck continue; 5772018f220Stb node = x509_policy_node_new( 5782018f220Stb mapping->issuerDomainPolicy); 579e59b13feStb if (node == NULL || 5802018f220Stb !sk_X509_POLICY_NODE_push(new_nodes, 5812018f220Stb node)) { 58225478f03Sbeck x509_policy_node_free(node); 58325478f03Sbeck goto err; 58425478f03Sbeck } 58525478f03Sbeck } 58625478f03Sbeck node->mapped = 1; 58725478f03Sbeck } 588a211c03aStb if (!x509_policy_level_add_nodes(level, new_nodes)) 58925478f03Sbeck goto err; 59025478f03Sbeck } else { 591e59b13feStb /* 592e59b13feStb * RFC 5280, section 6.1.4, step (b.2). If mapping is 593e59b13feStb * inhibited, delete all mapped nodes. 594e59b13feStb */ 595ac13ea69Stb if (!sk_POLICY_MAPPING_is_sorted(mappings)) 596ac13ea69Stb goto err; 5972018f220Stb sk_X509_POLICY_NODE_delete_if(level->nodes, 5982018f220Stb delete_if_mapped, mappings); 5992018f220Stb sk_POLICY_MAPPING_pop_free(mappings, 6002018f220Stb POLICY_MAPPING_free); 60125478f03Sbeck mappings = NULL; 60225478f03Sbeck } 60325478f03Sbeck } 60425478f03Sbeck 605e59b13feStb /* 606e59b13feStb * If a node was not mapped, it retains the original "explicit_policy_set" 607e59b13feStb * value, itself. Add those to |mappings|. 608e59b13feStb */ 60925478f03Sbeck if (mappings == NULL) { 61025478f03Sbeck mappings = sk_POLICY_MAPPING_new_null(); 611a211c03aStb if (mappings == NULL) 61225478f03Sbeck goto err; 61325478f03Sbeck } 614ea2d6ca4Stb for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) { 61578fe41cbStb node = sk_X509_POLICY_NODE_value(level->nodes, i); 61625478f03Sbeck if (!node->mapped) { 61778fe41cbStb mapping = POLICY_MAPPING_new(); 618a211c03aStb if (mapping == NULL) 61925478f03Sbeck goto err; 62025478f03Sbeck mapping->issuerDomainPolicy = OBJ_dup(node->policy); 62125478f03Sbeck mapping->subjectDomainPolicy = OBJ_dup(node->policy); 62225478f03Sbeck if (mapping->issuerDomainPolicy == NULL || 62325478f03Sbeck mapping->subjectDomainPolicy == NULL || 62425478f03Sbeck !sk_POLICY_MAPPING_push(mappings, mapping)) { 62525478f03Sbeck POLICY_MAPPING_free(mapping); 62625478f03Sbeck goto err; 62725478f03Sbeck } 62825478f03Sbeck } 62925478f03Sbeck } 63025478f03Sbeck 631e59b13feStb /* Sort to group by subjectDomainPolicy. */ 6324ec1749bStb (void)sk_POLICY_MAPPING_set_cmp_func(mappings, compare_subject_policy); 63325478f03Sbeck sk_POLICY_MAPPING_sort(mappings); 63425478f03Sbeck 635e59b13feStb /* Convert |mappings| to our "expected_policy_set" representation. */ 63625478f03Sbeck next = x509_policy_level_new(); 637a211c03aStb if (next == NULL) 63825478f03Sbeck goto err; 63925478f03Sbeck next->has_any_policy = level->has_any_policy; 64025478f03Sbeck 64125478f03Sbeck X509_POLICY_NODE *last_node = NULL; 642ea2d6ca4Stb for (i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) { 64378fe41cbStb mapping = sk_POLICY_MAPPING_value(mappings, i); 644e59b13feStb /* 645e59b13feStb * Skip mappings where |issuerDomainPolicy| does not appear in 646e59b13feStb * the graph. 647e59b13feStb */ 6485e6c7225Stb if (!level->has_any_policy) { 6495e6c7225Stb if (!sk_X509_POLICY_NODE_is_sorted(level->nodes)) 6505e6c7225Stb goto err; 6515e6c7225Stb if (x509_policy_level_find(level, 652a211c03aStb mapping->issuerDomainPolicy) == NULL) 65325478f03Sbeck continue; 6545e6c7225Stb } 65525478f03Sbeck 65625478f03Sbeck if (last_node == NULL || 6572018f220Stb OBJ_cmp(last_node->policy, mapping->subjectDomainPolicy) != 6582018f220Stb 0) { 6592018f220Stb last_node = x509_policy_node_new( 6602018f220Stb mapping->subjectDomainPolicy); 66125478f03Sbeck if (last_node == NULL || 66225478f03Sbeck !sk_X509_POLICY_NODE_push(next->nodes, last_node)) { 66325478f03Sbeck x509_policy_node_free(last_node); 66425478f03Sbeck goto err; 66525478f03Sbeck } 66625478f03Sbeck } 66725478f03Sbeck 66825478f03Sbeck if (!sk_ASN1_OBJECT_push(last_node->parent_policies, 669a211c03aStb mapping->issuerDomainPolicy)) 67025478f03Sbeck goto err; 67125478f03Sbeck mapping->issuerDomainPolicy = NULL; 67225478f03Sbeck } 67325478f03Sbeck 67425478f03Sbeck sk_X509_POLICY_NODE_sort(next->nodes); 67525478f03Sbeck ok = 1; 67625478f03Sbeck 67725478f03Sbeck err: 67825478f03Sbeck if (!ok) { 67925478f03Sbeck x509_policy_level_free(next); 68025478f03Sbeck next = NULL; 68125478f03Sbeck } 68225478f03Sbeck 68325478f03Sbeck sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free); 68425478f03Sbeck sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free); 68525478f03Sbeck return next; 68625478f03Sbeck } 68725478f03Sbeck 688e59b13feStb /* 689e59b13feStb * apply_skip_certs, if |skip_certs| is non-NULL, sets |*value| to the minimum 690e59b13feStb * of its current value and |skip_certs|. It returns one on success and zero if 691e59b13feStb * |skip_certs| is negative. 692e59b13feStb */ 6932018f220Stb static int 6942018f220Stb apply_skip_certs(const ASN1_INTEGER *skip_certs, size_t *value) 6952018f220Stb { 696a211c03aStb if (skip_certs == NULL) 69725478f03Sbeck return 1; 69825478f03Sbeck 699e59b13feStb /* TODO(https://crbug.com/boringssl/443): Move this check into the parser. */ 70025478f03Sbeck if (skip_certs->type & V_ASN1_NEG) { 701e4817b8bSbeck X509error(X509_R_INVALID_POLICY_EXTENSION); 70225478f03Sbeck return 0; 70325478f03Sbeck } 70425478f03Sbeck 705e59b13feStb /* If |skip_certs| does not fit in |uint64_t|, it must exceed |*value|. */ 70625478f03Sbeck uint64_t u64; 707a211c03aStb if (ASN1_INTEGER_get_uint64(&u64, skip_certs) && u64 < *value) 70825478f03Sbeck *value = (size_t)u64; 70925478f03Sbeck ERR_clear_error(); 71025478f03Sbeck return 1; 71125478f03Sbeck } 71225478f03Sbeck 713e59b13feStb /* 714e59b13feStb * process_policy_constraints updates |*explicit_policy|, |*policy_mapping|, and 715e59b13feStb * |*inhibit_any_policy| according to |x509|'s policy constraints and inhibit 716e59b13feStb * anyPolicy extensions. It returns one on success and zero on error. This 717e59b13feStb * implements steps (i) and (j) of RFC 5280, section 6.1.4. 718e59b13feStb */ 7192018f220Stb static int 7202018f220Stb process_policy_constraints(const X509 *x509, size_t *explicit_policy, 72125478f03Sbeck size_t *policy_mapping, 7222018f220Stb size_t *inhibit_any_policy) 7232018f220Stb { 72478fe41cbStb ASN1_INTEGER *inhibit_any_policy_ext; 72578fe41cbStb POLICY_CONSTRAINTS *constraints; 72625478f03Sbeck int critical; 72778fe41cbStb int ok = 0; 72878fe41cbStb 72978fe41cbStb constraints = X509_get_ext_d2i(x509, NID_policy_constraints, &critical, 73078fe41cbStb NULL); 731a211c03aStb if (constraints == NULL && critical != -1) 73225478f03Sbeck return 0; 73325478f03Sbeck if (constraints != NULL) { 73425478f03Sbeck if (constraints->requireExplicitPolicy == NULL && 73525478f03Sbeck constraints->inhibitPolicyMapping == NULL) { 736e59b13feStb /* 737e59b13feStb * Per RFC 5280, section 4.2.1.11, at least one of the 738e59b13feStb * fields must be 739e59b13feStb */ 740e4817b8bSbeck X509error(X509_R_INVALID_POLICY_EXTENSION); 74125478f03Sbeck POLICY_CONSTRAINTS_free(constraints); 74225478f03Sbeck return 0; 74325478f03Sbeck } 74478fe41cbStb ok = apply_skip_certs(constraints->requireExplicitPolicy, 7452018f220Stb explicit_policy) && 7462018f220Stb apply_skip_certs(constraints->inhibitPolicyMapping, 7472018f220Stb policy_mapping); 74825478f03Sbeck POLICY_CONSTRAINTS_free(constraints); 749a211c03aStb if (!ok) 75025478f03Sbeck return 0; 75125478f03Sbeck } 75225478f03Sbeck 75378fe41cbStb inhibit_any_policy_ext = X509_get_ext_d2i(x509, NID_inhibit_any_policy, 75478fe41cbStb &critical, NULL); 755a211c03aStb if (inhibit_any_policy_ext == NULL && critical != -1) 75625478f03Sbeck return 0; 75778fe41cbStb ok = apply_skip_certs(inhibit_any_policy_ext, inhibit_any_policy); 75825478f03Sbeck ASN1_INTEGER_free(inhibit_any_policy_ext); 75925478f03Sbeck return ok; 76025478f03Sbeck } 76125478f03Sbeck 762e59b13feStb /* 763e59b13feStb * has_explicit_policy returns one if the set of authority-space policy OIDs 764e59b13feStb * |levels| has some non-empty intersection with |user_policies|, and zero 765e59b13feStb * otherwise. This mirrors the logic in RFC 5280, section 6.1.5, step (g). This 766e59b13feStb * function modifies |levels| and should only be called at the end of policy 767e59b13feStb * evaluation. 768e59b13feStb */ 7692018f220Stb static int 7702018f220Stb has_explicit_policy(STACK_OF(X509_POLICY_LEVEL) *levels, 7712018f220Stb const STACK_OF(ASN1_OBJECT) *user_policies) 7722018f220Stb { 77378fe41cbStb X509_POLICY_LEVEL *level, *prev; 77478fe41cbStb X509_POLICY_NODE *node, *parent; 77578fe41cbStb int num_levels, user_has_any_policy; 7763b6f7f9fSbeck int i, j, k; 777f2b8a29eStb 778f2b8a29eStb if (!sk_ASN1_OBJECT_is_sorted(user_policies)) 779f2b8a29eStb return 0; 78025478f03Sbeck 781e59b13feStb /* Step (g.i). If the policy graph is empty, the intersection is empty. */ 78278fe41cbStb num_levels = sk_X509_POLICY_LEVEL_num(levels); 78378fe41cbStb level = sk_X509_POLICY_LEVEL_value(levels, num_levels - 1); 784a211c03aStb if (x509_policy_level_is_empty(level)) 78525478f03Sbeck return 0; 78625478f03Sbeck 787e59b13feStb /* 788e59b13feStb * If |user_policies| is empty, we interpret it as having a single 789e59b13feStb * anyPolicy value. The caller may also have supplied anyPolicy 790e59b13feStb * explicitly. 791e59b13feStb */ 79278fe41cbStb user_has_any_policy = sk_ASN1_OBJECT_num(user_policies) <= 0; 793ea2d6ca4Stb for (i = 0; i < sk_ASN1_OBJECT_num(user_policies); i++) { 79425478f03Sbeck if (is_any_policy(sk_ASN1_OBJECT_value(user_policies, i))) { 79525478f03Sbeck user_has_any_policy = 1; 79625478f03Sbeck break; 79725478f03Sbeck } 79825478f03Sbeck } 79925478f03Sbeck 800e59b13feStb /* 801e59b13feStb * Step (g.ii). If the policy graph is not empty and the user set 802e59b13feStb * contains anyPolicy, the intersection is the entire (non-empty) graph. 803e59b13feStb */ 804a211c03aStb if (user_has_any_policy) 80525478f03Sbeck return 1; 80625478f03Sbeck 807e59b13feStb /* 808e59b13feStb * Step (g.iii) does not delete anyPolicy nodes, so if the graph has 809e59b13feStb * anyPolicy, some explicit policy will survive. The actual intersection 810e59b13feStb * may synthesize some nodes in step (g.iii.3), but we do not return the 811e59b13feStb * policy list itself, so we skip actually computing this. 812e59b13feStb */ 813a211c03aStb if (level->has_any_policy) 81425478f03Sbeck return 1; 81525478f03Sbeck 816e59b13feStb /* 817e59b13feStb * We defer pruning the tree, so as we look for nodes with parent 818e59b13feStb * anyPolicy, step (g.iii.1), we must limit to nodes reachable from the 819e59b13feStb * bottommost level. Start by marking each of those nodes as reachable. 820e59b13feStb */ 821a211c03aStb for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) 82225478f03Sbeck sk_X509_POLICY_NODE_value(level->nodes, i)->reachable = 1; 82325478f03Sbeck 8243b6f7f9fSbeck for (i = num_levels - 1; i >= 0; i--) { 82525478f03Sbeck level = sk_X509_POLICY_LEVEL_value(levels, i); 82678fe41cbStb for (j = 0; j < sk_X509_POLICY_NODE_num(level->nodes); j++) { 82778fe41cbStb node = sk_X509_POLICY_NODE_value(level->nodes, j); 828a211c03aStb if (!node->reachable) 82925478f03Sbeck continue; 83025478f03Sbeck if (sk_ASN1_OBJECT_num(node->parent_policies) == 0) { 831e59b13feStb /* 832e59b13feStb * |node|'s parent is anyPolicy and is part of 833e59b13feStb * "valid_policy_node_set". If it exists in 834e59b13feStb * |user_policies|, the intersection is 835e59b13feStb * non-empty and we * can return immediately. 836e59b13feStb */ 8372018f220Stb if (sk_ASN1_OBJECT_find(user_policies, 838a211c03aStb node->policy) >= 0) 83925478f03Sbeck return 1; 84025478f03Sbeck } else if (i > 0) { 84178fe41cbStb int num_parent_policies = 84278fe41cbStb sk_ASN1_OBJECT_num(node->parent_policies); 84378fe41cbStb /* 84478fe41cbStb * |node|'s parents are concrete policies. Mark 845e59b13feStb * the parents reachable, to be inspected by the 846e59b13feStb * next loop iteration. 847e59b13feStb */ 84878fe41cbStb prev = sk_X509_POLICY_LEVEL_value(levels, i - 1); 84978fe41cbStb for (k = 0; k < num_parent_policies; k++) { 8505e6c7225Stb if (!sk_X509_POLICY_NODE_is_sorted(prev->nodes)) 8515e6c7225Stb return 0; 85278fe41cbStb parent = x509_policy_level_find(prev, 853a211c03aStb sk_ASN1_OBJECT_value(node->parent_policies, 854a211c03aStb k)); 855a211c03aStb if (parent != NULL) 85625478f03Sbeck parent->reachable = 1; 85725478f03Sbeck } 85825478f03Sbeck } 85925478f03Sbeck } 86025478f03Sbeck } 86125478f03Sbeck 86225478f03Sbeck return 0; 86325478f03Sbeck } 86425478f03Sbeck 8652018f220Stb static int 86678fe41cbStb asn1_object_cmp(const ASN1_OBJECT *const *a, const ASN1_OBJECT *const *b) 8672018f220Stb { 86825478f03Sbeck return OBJ_cmp(*a, *b); 86925478f03Sbeck } 87025478f03Sbeck 8712018f220Stb int 8722018f220Stb X509_policy_check(const STACK_OF(X509) *certs, 87325478f03Sbeck const STACK_OF(ASN1_OBJECT) *user_policies, 8742018f220Stb unsigned long flags, X509 **out_current_cert) 8752018f220Stb { 87625478f03Sbeck *out_current_cert = NULL; 87725478f03Sbeck int ret = X509_V_ERR_OUT_OF_MEM; 87878fe41cbStb X509 *cert; 87925478f03Sbeck X509_POLICY_LEVEL *level = NULL; 88078fe41cbStb X509_POLICY_LEVEL *current_level; 88125478f03Sbeck STACK_OF(X509_POLICY_LEVEL) *levels = NULL; 88225478f03Sbeck STACK_OF(ASN1_OBJECT) *user_policies_sorted = NULL; 8833b6f7f9fSbeck int num_certs = sk_X509_num(certs); 88478fe41cbStb int is_self_issued, any_policy_allowed; 8853b6f7f9fSbeck int i; 88625478f03Sbeck 887e59b13feStb /* Skip policy checking if the chain is just the trust anchor. */ 888a211c03aStb if (num_certs <= 1) 88925478f03Sbeck return X509_V_OK; 89025478f03Sbeck 891e59b13feStb /* See RFC 5280, section 6.1.2, steps (d) through (f). */ 89225478f03Sbeck size_t explicit_policy = 89325478f03Sbeck (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : num_certs + 1; 89425478f03Sbeck size_t inhibit_any_policy = 89525478f03Sbeck (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : num_certs + 1; 89625478f03Sbeck size_t policy_mapping = 89725478f03Sbeck (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : num_certs + 1; 89825478f03Sbeck 89925478f03Sbeck levels = sk_X509_POLICY_LEVEL_new_null(); 900a211c03aStb if (levels == NULL) 90125478f03Sbeck goto err; 90225478f03Sbeck 9033b6f7f9fSbeck for (i = num_certs - 2; i >= 0; i--) { 90478fe41cbStb cert = sk_X509_value(certs, i); 905a211c03aStb if (!x509v3_cache_extensions(cert)) 90625478f03Sbeck goto err; 90778fe41cbStb is_self_issued = (cert->ex_flags & EXFLAG_SI) != 0; 90825478f03Sbeck 90925478f03Sbeck if (level == NULL) { 9108f89bdfaStb if (i != num_certs - 2) 9118f89bdfaStb goto err; 91225478f03Sbeck level = x509_policy_level_new(); 913a211c03aStb if (level == NULL) 91425478f03Sbeck goto err; 91525478f03Sbeck level->has_any_policy = 1; 91625478f03Sbeck } 91725478f03Sbeck 918e59b13feStb /* 919e59b13feStb * RFC 5280, section 6.1.3, steps (d) and (e). |any_policy_allowed| 920e59b13feStb * is computed as in step (d.2). 921e59b13feStb */ 92278fe41cbStb any_policy_allowed = 92325478f03Sbeck inhibit_any_policy > 0 || (i > 0 && is_self_issued); 9242018f220Stb if (!process_certificate_policies(cert, level, 9252018f220Stb any_policy_allowed)) { 92625478f03Sbeck ret = X509_V_ERR_INVALID_POLICY_EXTENSION; 92725478f03Sbeck *out_current_cert = cert; 92825478f03Sbeck goto err; 92925478f03Sbeck } 93025478f03Sbeck 931e59b13feStb /* RFC 5280, section 6.1.3, step (f). */ 93225478f03Sbeck if (explicit_policy == 0 && x509_policy_level_is_empty(level)) { 93325478f03Sbeck ret = X509_V_ERR_NO_EXPLICIT_POLICY; 93425478f03Sbeck goto err; 93525478f03Sbeck } 93625478f03Sbeck 937e59b13feStb /* Insert into the list. */ 938a211c03aStb if (!sk_X509_POLICY_LEVEL_push(levels, level)) 93925478f03Sbeck goto err; 94078fe41cbStb current_level = level; 94125478f03Sbeck level = NULL; 94225478f03Sbeck 943e59b13feStb /* 944e59b13feStb * If this is not the leaf certificate, we go to section 6.1.4. 945e59b13feStb * If it is the leaf certificate, we go to section 6.1.5 instead. 946e59b13feStb */ 94725478f03Sbeck if (i != 0) { 948e59b13feStb /* RFC 5280, section 6.1.4, steps (a) and (b). */ 9492018f220Stb level = process_policy_mappings(cert, current_level, 9502018f220Stb policy_mapping > 0); 95125478f03Sbeck if (level == NULL) { 95225478f03Sbeck ret = X509_V_ERR_INVALID_POLICY_EXTENSION; 95325478f03Sbeck *out_current_cert = cert; 95425478f03Sbeck goto err; 95525478f03Sbeck } 95625478f03Sbeck } 95725478f03Sbeck 958e59b13feStb /* 959e59b13feStb * RFC 5280, section 6.1.4, step (h-j) for non-leaves, and 960e59b13feStb * section 6.1.5, step (a-b) for leaves. In the leaf case, 961e59b13feStb * RFC 5280 says only to update |explicit_policy|, but 962e59b13feStb * |policy_mapping| and |inhibit_any_policy| are no 963e59b13feStb * longer read at this point, so we use the same process. 964e59b13feStb */ 96525478f03Sbeck if (i == 0 || !is_self_issued) { 966a211c03aStb if (explicit_policy > 0) 96725478f03Sbeck explicit_policy--; 968a211c03aStb if (policy_mapping > 0) 96925478f03Sbeck policy_mapping--; 970a211c03aStb if (inhibit_any_policy > 0) 97125478f03Sbeck inhibit_any_policy--; 97225478f03Sbeck } 9732018f220Stb if (!process_policy_constraints(cert, &explicit_policy, 9742018f220Stb &policy_mapping, &inhibit_any_policy)) { 97525478f03Sbeck ret = X509_V_ERR_INVALID_POLICY_EXTENSION; 97625478f03Sbeck *out_current_cert = cert; 97725478f03Sbeck goto err; 97825478f03Sbeck } 97925478f03Sbeck } 98025478f03Sbeck 981e59b13feStb /* 982e59b13feStb * RFC 5280, section 6.1.5, step (g). We do not output the policy set, 983e59b13feStb * so it is only necessary to check if the user-constrained-policy-set 984e59b13feStb * is not empty. 985e59b13feStb */ 98625478f03Sbeck if (explicit_policy == 0) { 987e59b13feStb /* 988e59b13feStb * Build a sorted copy of |user_policies| for more efficient 989e59b13feStb * lookup. 990e59b13feStb */ 99125478f03Sbeck if (user_policies != NULL) { 9922018f220Stb user_policies_sorted = sk_ASN1_OBJECT_dup( 9932018f220Stb user_policies); 994a211c03aStb if (user_policies_sorted == NULL) 99525478f03Sbeck goto err; 9964ec1749bStb (void)sk_ASN1_OBJECT_set_cmp_func(user_policies_sorted, 9972018f220Stb asn1_object_cmp); 99825478f03Sbeck sk_ASN1_OBJECT_sort(user_policies_sorted); 99925478f03Sbeck } 100025478f03Sbeck 100125478f03Sbeck if (!has_explicit_policy(levels, user_policies_sorted)) { 100225478f03Sbeck ret = X509_V_ERR_NO_EXPLICIT_POLICY; 100325478f03Sbeck goto err; 100425478f03Sbeck } 100525478f03Sbeck } 100625478f03Sbeck 100725478f03Sbeck ret = X509_V_OK; 100825478f03Sbeck 100925478f03Sbeck err: 101025478f03Sbeck x509_policy_level_free(level); 1011e59b13feStb /* 1012e59b13feStb * |user_policies_sorted|'s contents are owned by |user_policies|, so 1013e59b13feStb * we do not use |sk_ASN1_OBJECT_pop_free|. 1014e59b13feStb */ 101525478f03Sbeck sk_ASN1_OBJECT_free(user_policies_sorted); 101625478f03Sbeck sk_X509_POLICY_LEVEL_pop_free(levels, x509_policy_level_free); 101725478f03Sbeck return ret; 101825478f03Sbeck } 1019