xref: /openbsd-src/lib/libcrypto/x509/x509_policy.c (revision 169e56b9b7e09eb65b9f7760e25cad4b06e3ba2d)
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