xref: /freebsd/crypto/openssl/crypto/x509/pcy_tree.c (revision b077aed3)
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