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