sl@0: /* pcy_tree.c */ sl@0: /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL sl@0: * project 2004. sl@0: */ sl@0: /* ==================================================================== sl@0: * Copyright (c) 2004 The OpenSSL Project. All rights reserved. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * sl@0: * 1. Redistributions of source code must retain the above copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in sl@0: * the documentation and/or other materials provided with the sl@0: * distribution. sl@0: * sl@0: * 3. All advertising materials mentioning features or use of this sl@0: * software must display the following acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" sl@0: * sl@0: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to sl@0: * endorse or promote products derived from this software without sl@0: * prior written permission. For written permission, please contact sl@0: * licensing@OpenSSL.org. sl@0: * sl@0: * 5. Products derived from this software may not be called "OpenSSL" sl@0: * nor may "OpenSSL" appear in their names without prior written sl@0: * permission of the OpenSSL Project. sl@0: * sl@0: * 6. Redistributions of any form whatsoever must retain the following sl@0: * acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY sl@0: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR sl@0: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR sl@0: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, sl@0: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT sl@0: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; sl@0: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, sl@0: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) sl@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED sl@0: * OF THE POSSIBILITY OF SUCH DAMAGE. sl@0: * ==================================================================== sl@0: * sl@0: * This product includes cryptographic software written by Eric Young sl@0: * (eay@cryptsoft.com). This product includes software written by Tim sl@0: * Hudson (tjh@cryptsoft.com). sl@0: * sl@0: */ sl@0: sl@0: #include "cryptlib.h" sl@0: #include sl@0: #include sl@0: sl@0: #include "pcy_int.h" sl@0: sl@0: /* Initialize policy tree. Return values: sl@0: * 0 Some internal error occured. sl@0: * -1 Inconsistent or invalid extensions in certificates. sl@0: * 1 Tree initialized OK. sl@0: * 2 Policy tree is empty. sl@0: * 5 Tree OK and requireExplicitPolicy true. sl@0: * 6 Tree empty and requireExplicitPolicy true. sl@0: */ sl@0: sl@0: static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, sl@0: unsigned int flags) sl@0: { sl@0: X509_POLICY_TREE *tree; sl@0: X509_POLICY_LEVEL *level; sl@0: const X509_POLICY_CACHE *cache; sl@0: X509_POLICY_DATA *data = NULL; sl@0: X509 *x; sl@0: int ret = 1; sl@0: int i, n; sl@0: int explicit_policy; sl@0: int any_skip; sl@0: int map_skip; sl@0: *ptree = NULL; sl@0: n = sk_X509_num(certs); sl@0: sl@0: /* Disable policy mapping for now... */ sl@0: flags |= X509_V_FLAG_INHIBIT_MAP; sl@0: sl@0: if (flags & X509_V_FLAG_EXPLICIT_POLICY) sl@0: explicit_policy = 0; sl@0: else sl@0: explicit_policy = n + 1; sl@0: sl@0: if (flags & X509_V_FLAG_INHIBIT_ANY) sl@0: any_skip = 0; sl@0: else sl@0: any_skip = n + 1; sl@0: sl@0: if (flags & X509_V_FLAG_INHIBIT_MAP) sl@0: map_skip = 0; sl@0: else sl@0: map_skip = n + 1; sl@0: sl@0: /* Can't do anything with just a trust anchor */ sl@0: if (n == 1) sl@0: return 1; sl@0: /* First setup policy cache in all certificates apart from the sl@0: * trust anchor. Note any bad cache results on the way. Also can sl@0: * calculate explicit_policy value at this point. sl@0: */ sl@0: for (i = n - 2; i >= 0; i--) sl@0: { sl@0: x = sk_X509_value(certs, i); sl@0: X509_check_purpose(x, -1, -1); sl@0: cache = policy_cache_set(x); sl@0: /* If cache NULL something bad happened: return immediately */ sl@0: if (cache == NULL) sl@0: return 0; sl@0: /* If inconsistent extensions keep a note of it but continue */ sl@0: if (x->ex_flags & EXFLAG_INVALID_POLICY) sl@0: ret = -1; sl@0: /* Otherwise if we have no data (hence no CertificatePolicies) sl@0: * and haven't already set an inconsistent code note it. sl@0: */ sl@0: else if ((ret == 1) && !cache->data) sl@0: ret = 2; sl@0: if (explicit_policy > 0) sl@0: { sl@0: explicit_policy--; sl@0: if (!(x->ex_flags & EXFLAG_SS) sl@0: && (cache->explicit_skip != -1) sl@0: && (cache->explicit_skip < explicit_policy)) sl@0: explicit_policy = cache->explicit_skip; sl@0: } sl@0: } sl@0: sl@0: if (ret != 1) sl@0: { sl@0: if (ret == 2 && !explicit_policy) sl@0: return 6; sl@0: return ret; sl@0: } sl@0: sl@0: sl@0: /* If we get this far initialize the tree */ sl@0: sl@0: tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE)); sl@0: sl@0: if (!tree) sl@0: return 0; sl@0: sl@0: tree->flags = 0; sl@0: tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n); sl@0: #ifdef SYMBIAN sl@0: if (!tree->levels) sl@0: return 0; sl@0: #endif sl@0: tree->nlevel = 0; sl@0: tree->extra_data = NULL; sl@0: tree->auth_policies = NULL; sl@0: tree->user_policies = NULL; sl@0: sl@0: if (!tree) sl@0: { sl@0: OPENSSL_free(tree); sl@0: return 0; sl@0: } sl@0: sl@0: memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL)); sl@0: sl@0: tree->nlevel = n; sl@0: sl@0: level = tree->levels; sl@0: sl@0: /* Root data: initialize to anyPolicy */ sl@0: sl@0: data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0); sl@0: sl@0: if (!data || !level_add_node(level, data, NULL, tree)) sl@0: goto bad_tree; sl@0: sl@0: for (i = n - 2; i >= 0; i--) sl@0: { sl@0: level++; sl@0: x = sk_X509_value(certs, i); sl@0: cache = policy_cache_set(x); sl@0: sl@0: CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); sl@0: level->cert = x; sl@0: sl@0: if (!cache->anyPolicy) sl@0: level->flags |= X509_V_FLAG_INHIBIT_ANY; sl@0: sl@0: /* Determine inhibit any and inhibit map flags */ sl@0: if (any_skip == 0) sl@0: { sl@0: /* Any matching allowed if certificate is self sl@0: * issued and not the last in the chain. sl@0: */ sl@0: if (!(x->ex_flags & EXFLAG_SS) || (i == 0)) sl@0: level->flags |= X509_V_FLAG_INHIBIT_ANY; sl@0: } sl@0: else sl@0: { sl@0: any_skip--; sl@0: if ((cache->any_skip > 0) sl@0: && (cache->any_skip < any_skip)) sl@0: any_skip = cache->any_skip; sl@0: } sl@0: sl@0: if (map_skip == 0) sl@0: level->flags |= X509_V_FLAG_INHIBIT_MAP; sl@0: else sl@0: { sl@0: map_skip--; sl@0: if ((cache->map_skip > 0) sl@0: && (cache->map_skip < map_skip)) sl@0: map_skip = cache->map_skip; sl@0: } sl@0: sl@0: sl@0: } sl@0: sl@0: *ptree = tree; sl@0: sl@0: if (explicit_policy) sl@0: return 1; sl@0: else sl@0: return 5; sl@0: sl@0: bad_tree: sl@0: sl@0: X509_policy_tree_free(tree); sl@0: sl@0: return 0; sl@0: sl@0: } sl@0: sl@0: /* This corresponds to RFC3280 XXXX XXXXX: sl@0: * link any data from CertificatePolicies onto matching parent sl@0: * or anyPolicy if no match. sl@0: */ sl@0: sl@0: static int tree_link_nodes(X509_POLICY_LEVEL *curr, sl@0: const X509_POLICY_CACHE *cache) sl@0: { sl@0: int i; sl@0: X509_POLICY_LEVEL *last; sl@0: X509_POLICY_DATA *data; sl@0: X509_POLICY_NODE *parent; sl@0: last = curr - 1; sl@0: for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) sl@0: { sl@0: data = sk_X509_POLICY_DATA_value(cache->data, i); sl@0: /* If a node is mapped any it doesn't have a corresponding sl@0: * CertificatePolicies entry. sl@0: * However such an identical node would be created sl@0: * if anyPolicy matching is enabled because there would be sl@0: * no match with the parent valid_policy_set. So we create sl@0: * link because then it will have the mapping flags sl@0: * right and we can prune it later. sl@0: */ sl@0: if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY) sl@0: && !(curr->flags & X509_V_FLAG_INHIBIT_ANY)) sl@0: continue; sl@0: /* Look for matching node in parent */ sl@0: parent = level_find_node(last, data->valid_policy); sl@0: /* If no match link to anyPolicy */ sl@0: if (!parent) sl@0: parent = last->anyPolicy; sl@0: if (parent && !level_add_node(curr, data, parent, NULL)) sl@0: return 0; sl@0: } sl@0: return 1; sl@0: } sl@0: sl@0: /* This corresponds to RFC3280 XXXX XXXXX: sl@0: * Create new data for any unmatched policies in the parent and link sl@0: * to anyPolicy. sl@0: */ sl@0: sl@0: static int tree_link_any(X509_POLICY_LEVEL *curr, sl@0: const X509_POLICY_CACHE *cache, sl@0: X509_POLICY_TREE *tree) sl@0: { sl@0: int i; sl@0: X509_POLICY_DATA *data; sl@0: X509_POLICY_NODE *node; sl@0: X509_POLICY_LEVEL *last; sl@0: sl@0: last = curr - 1; sl@0: sl@0: for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) sl@0: { sl@0: node = sk_X509_POLICY_NODE_value(last->nodes, i); sl@0: sl@0: /* Skip any node with any children: we only want unmathced sl@0: * nodes. sl@0: * sl@0: * Note: need something better for policy mapping sl@0: * because each node may have multiple children sl@0: */ sl@0: if (node->nchild) sl@0: continue; sl@0: /* Create a new node with qualifiers from anyPolicy and sl@0: * id from unmatched node. sl@0: */ sl@0: data = policy_data_new(NULL, node->data->valid_policy, sl@0: node_critical(node)); sl@0: sl@0: if (data == NULL) sl@0: return 0; sl@0: data->qualifier_set = curr->anyPolicy->data->qualifier_set; sl@0: data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; sl@0: if (!level_add_node(curr, data, node, tree)) sl@0: { sl@0: policy_data_free(data); sl@0: return 0; sl@0: } sl@0: } sl@0: /* Finally add link to anyPolicy */ sl@0: if (last->anyPolicy) sl@0: { sl@0: if (!level_add_node(curr, cache->anyPolicy, sl@0: last->anyPolicy, NULL)) sl@0: return 0; sl@0: } sl@0: return 1; sl@0: } sl@0: sl@0: /* Prune the tree: delete any child mapped child data on the current level sl@0: * then proceed up the tree deleting any data with no children. If we ever sl@0: * have no data on a level we can halt because the tree will be empty. sl@0: */ sl@0: sl@0: static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr) sl@0: { sl@0: X509_POLICY_NODE *node; sl@0: int i; sl@0: for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--) sl@0: { sl@0: node = sk_X509_POLICY_NODE_value(curr->nodes, i); sl@0: /* Delete any mapped data: see RFC3280 XXXX */ sl@0: if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) sl@0: { sl@0: node->parent->nchild--; sl@0: OPENSSL_free(node); sl@0: (void)sk_X509_POLICY_NODE_delete(curr->nodes, i); sl@0: } sl@0: } sl@0: sl@0: for(;;) { sl@0: --curr; sl@0: for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--) sl@0: { sl@0: node = sk_X509_POLICY_NODE_value(curr->nodes, i); sl@0: if (node->nchild == 0) sl@0: { sl@0: node->parent->nchild--; sl@0: OPENSSL_free(node); sl@0: (void)sk_X509_POLICY_NODE_delete(curr->nodes, i); sl@0: } sl@0: } sl@0: if (curr->anyPolicy && !curr->anyPolicy->nchild) sl@0: { sl@0: if (curr->anyPolicy->parent) sl@0: curr->anyPolicy->parent->nchild--; sl@0: OPENSSL_free(curr->anyPolicy); sl@0: curr->anyPolicy = NULL; sl@0: } sl@0: if (curr == tree->levels) sl@0: { sl@0: /* If we zapped anyPolicy at top then tree is empty */ sl@0: if (!curr->anyPolicy) sl@0: return 2; sl@0: return 1; sl@0: } sl@0: } sl@0: sl@0: return 1; sl@0: sl@0: } sl@0: sl@0: static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes, sl@0: X509_POLICY_NODE *pcy) sl@0: { sl@0: if (!*pnodes) sl@0: { sl@0: *pnodes = policy_node_cmp_new(); sl@0: if (!*pnodes) sl@0: return 0; sl@0: } sl@0: else if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1) sl@0: return 1; sl@0: sl@0: if (!sk_X509_POLICY_NODE_push(*pnodes, pcy)) sl@0: return 0; sl@0: sl@0: return 1; sl@0: sl@0: } sl@0: sl@0: /* Calculate the authority set based on policy tree. sl@0: * The 'pnodes' parameter is used as a store for the set of policy nodes sl@0: * used to calculate the user set. If the authority set is not anyPolicy sl@0: * then pnodes will just point to the authority set. If however the authority sl@0: * set is anyPolicy then the set of valid policies (other than anyPolicy) sl@0: * is store in pnodes. The return value of '2' is used in this case to indicate sl@0: * that pnodes should be freed. sl@0: */ sl@0: sl@0: static int tree_calculate_authority_set(X509_POLICY_TREE *tree, sl@0: STACK_OF(X509_POLICY_NODE) **pnodes) sl@0: { sl@0: X509_POLICY_LEVEL *curr; sl@0: X509_POLICY_NODE *node, *anyptr; sl@0: STACK_OF(X509_POLICY_NODE) **addnodes; sl@0: int i, j; sl@0: curr = tree->levels + tree->nlevel - 1; sl@0: sl@0: /* If last level contains anyPolicy set is anyPolicy */ sl@0: if (curr->anyPolicy) sl@0: { sl@0: if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy)) sl@0: return 0; sl@0: addnodes = pnodes; sl@0: } sl@0: else sl@0: /* Add policies to authority set */ sl@0: addnodes = &tree->auth_policies; sl@0: sl@0: curr = tree->levels; sl@0: for (i = 1; i < tree->nlevel; i++) sl@0: { sl@0: /* If no anyPolicy node on this this level it can't sl@0: * appear on lower levels so end search. sl@0: */ sl@0: if (!(anyptr = curr->anyPolicy)) sl@0: break; sl@0: curr++; sl@0: for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) sl@0: { sl@0: node = sk_X509_POLICY_NODE_value(curr->nodes, j); sl@0: if ((node->parent == anyptr) sl@0: && !tree_add_auth_node(addnodes, node)) sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: if (addnodes == pnodes) sl@0: return 2; sl@0: sl@0: *pnodes = tree->auth_policies; sl@0: sl@0: return 1; sl@0: } sl@0: sl@0: static int tree_calculate_user_set(X509_POLICY_TREE *tree, sl@0: STACK_OF(ASN1_OBJECT) *policy_oids, sl@0: STACK_OF(X509_POLICY_NODE) *auth_nodes) sl@0: { sl@0: int i; sl@0: X509_POLICY_NODE *node; sl@0: ASN1_OBJECT *oid; sl@0: sl@0: X509_POLICY_NODE *anyPolicy; sl@0: X509_POLICY_DATA *extra; sl@0: sl@0: /* Check if anyPolicy present in authority constrained policy set: sl@0: * this will happen if it is a leaf node. sl@0: */ sl@0: sl@0: if (sk_ASN1_OBJECT_num(policy_oids) <= 0) sl@0: return 1; sl@0: sl@0: anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy; sl@0: sl@0: for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) sl@0: { sl@0: oid = sk_ASN1_OBJECT_value(policy_oids, i); sl@0: if (OBJ_obj2nid(oid) == NID_any_policy) sl@0: { sl@0: tree->flags |= POLICY_FLAG_ANY_POLICY; sl@0: return 1; sl@0: } sl@0: } sl@0: sl@0: for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) sl@0: { sl@0: oid = sk_ASN1_OBJECT_value(policy_oids, i); sl@0: node = tree_find_sk(auth_nodes, oid); sl@0: if (!node) sl@0: { sl@0: if (!anyPolicy) sl@0: continue; sl@0: /* Create a new node with policy ID from user set sl@0: * and qualifiers from anyPolicy. sl@0: */ sl@0: extra = policy_data_new(NULL, oid, sl@0: node_critical(anyPolicy)); sl@0: if (!extra) sl@0: return 0; sl@0: extra->qualifier_set = anyPolicy->data->qualifier_set; sl@0: extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS sl@0: | POLICY_DATA_FLAG_EXTRA_NODE; sl@0: node = level_add_node(NULL, extra, anyPolicy->parent, sl@0: tree); sl@0: } sl@0: if (!tree->user_policies) sl@0: { sl@0: tree->user_policies = sk_X509_POLICY_NODE_new_null(); sl@0: if (!tree->user_policies) sl@0: return 1; sl@0: } sl@0: if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) sl@0: return 0; sl@0: } sl@0: return 1; sl@0: sl@0: } sl@0: sl@0: static int tree_evaluate(X509_POLICY_TREE *tree) sl@0: { sl@0: int ret, i; sl@0: X509_POLICY_LEVEL *curr = tree->levels + 1; sl@0: const X509_POLICY_CACHE *cache; sl@0: sl@0: for(i = 1; i < tree->nlevel; i++, curr++) sl@0: { sl@0: cache = policy_cache_set(curr->cert); sl@0: if (!tree_link_nodes(curr, cache)) sl@0: return 0; sl@0: sl@0: if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) sl@0: && !tree_link_any(curr, cache, tree)) sl@0: return 0; sl@0: ret = tree_prune(tree, curr); sl@0: if (ret != 1) sl@0: return ret; sl@0: } sl@0: sl@0: return 1; sl@0: sl@0: } sl@0: sl@0: static void exnode_free(X509_POLICY_NODE *node) sl@0: { sl@0: if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE)) sl@0: OPENSSL_free(node); sl@0: } sl@0: sl@0: sl@0: EXPORT_C void X509_policy_tree_free(X509_POLICY_TREE *tree) sl@0: { sl@0: X509_POLICY_LEVEL *curr; sl@0: int i; sl@0: sl@0: if (!tree) sl@0: return; sl@0: sl@0: sk_X509_POLICY_NODE_free(tree->auth_policies); sl@0: sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free); sl@0: sl@0: for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) sl@0: { sl@0: if (curr->cert) sl@0: X509_free(curr->cert); sl@0: if (curr->nodes) sl@0: sk_X509_POLICY_NODE_pop_free(curr->nodes, sl@0: policy_node_free); sl@0: if (curr->anyPolicy) sl@0: policy_node_free(curr->anyPolicy); sl@0: } sl@0: sl@0: if (tree->extra_data) sl@0: sk_X509_POLICY_DATA_pop_free(tree->extra_data, sl@0: policy_data_free); sl@0: sl@0: OPENSSL_free(tree->levels); sl@0: OPENSSL_free(tree); sl@0: sl@0: } sl@0: sl@0: /* Application policy checking function. sl@0: * Return codes: sl@0: * 0 Internal Error. sl@0: * 1 Successful. sl@0: * -1 One or more certificates contain invalid or inconsistent extensions sl@0: * -2 User constrained policy set empty and requireExplicit true. sl@0: */ sl@0: sl@0: EXPORT_C int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, sl@0: STACK_OF(X509) *certs, sl@0: STACK_OF(ASN1_OBJECT) *policy_oids, sl@0: unsigned int flags) sl@0: { sl@0: int ret; sl@0: X509_POLICY_TREE *tree = NULL; sl@0: STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL; sl@0: *ptree = NULL; sl@0: sl@0: *pexplicit_policy = 0; sl@0: ret = tree_init(&tree, certs, flags); sl@0: sl@0: sl@0: switch (ret) sl@0: { sl@0: sl@0: /* Tree empty requireExplicit False: OK */ sl@0: case 2: sl@0: return 1; sl@0: sl@0: /* Some internal error */ sl@0: case 0: sl@0: return 0; sl@0: sl@0: /* Tree empty requireExplicit True: Error */ sl@0: sl@0: case 6: sl@0: *pexplicit_policy = 1; sl@0: return -2; sl@0: sl@0: /* Tree OK requireExplicit True: OK and continue */ sl@0: case 5: sl@0: *pexplicit_policy = 1; sl@0: break; sl@0: sl@0: /* Tree OK: continue */ sl@0: sl@0: case 1: sl@0: if (!tree) sl@0: /* sl@0: * tree_init() returns success and a null tree sl@0: * if it's just looking at a trust anchor. sl@0: * I'm not sure that returning success here is sl@0: * correct, but I'm sure that reporting this sl@0: * as an internal error which our caller sl@0: * interprets as a malloc failure is wrong. sl@0: */ sl@0: return 1; sl@0: break; sl@0: } sl@0: if (!tree) goto error; sl@0: ret = tree_evaluate(tree); sl@0: sl@0: if (ret <= 0) sl@0: goto error; sl@0: sl@0: /* Return value 2 means tree empty */ sl@0: if (ret == 2) sl@0: { sl@0: X509_policy_tree_free(tree); sl@0: if (*pexplicit_policy) sl@0: return -2; sl@0: else sl@0: return 1; sl@0: } sl@0: sl@0: /* Tree is not empty: continue */ sl@0: sl@0: ret = tree_calculate_authority_set(tree, &auth_nodes); sl@0: sl@0: if (!ret) sl@0: goto error; sl@0: sl@0: if (!tree_calculate_user_set(tree, policy_oids, auth_nodes)) sl@0: goto error; sl@0: sl@0: if (ret == 2) sl@0: sk_X509_POLICY_NODE_free(auth_nodes); sl@0: sl@0: if (tree) sl@0: *ptree = tree; sl@0: sl@0: if (*pexplicit_policy) sl@0: { sl@0: nodes = X509_policy_tree_get0_user_policies(tree); sl@0: if (sk_X509_POLICY_NODE_num(nodes) <= 0) sl@0: return -2; sl@0: } sl@0: sl@0: return 1; sl@0: sl@0: error: sl@0: sl@0: X509_policy_tree_free(tree); sl@0: sl@0: return 0; sl@0: sl@0: } sl@0: