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