1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ssl/libcrypto/src/crypto/x509v3/pcy_tree.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,695 @@
1.4 +/* pcy_tree.c */
1.5 +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
1.6 + * project 2004.
1.7 + */
1.8 +/* ====================================================================
1.9 + * Copyright (c) 2004 The OpenSSL Project. All rights reserved.
1.10 + *
1.11 + * Redistribution and use in source and binary forms, with or without
1.12 + * modification, are permitted provided that the following conditions
1.13 + * are met:
1.14 + *
1.15 + * 1. Redistributions of source code must retain the above copyright
1.16 + * notice, this list of conditions and the following disclaimer.
1.17 + *
1.18 + * 2. Redistributions in binary form must reproduce the above copyright
1.19 + * notice, this list of conditions and the following disclaimer in
1.20 + * the documentation and/or other materials provided with the
1.21 + * distribution.
1.22 + *
1.23 + * 3. All advertising materials mentioning features or use of this
1.24 + * software must display the following acknowledgment:
1.25 + * "This product includes software developed by the OpenSSL Project
1.26 + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
1.27 + *
1.28 + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
1.29 + * endorse or promote products derived from this software without
1.30 + * prior written permission. For written permission, please contact
1.31 + * licensing@OpenSSL.org.
1.32 + *
1.33 + * 5. Products derived from this software may not be called "OpenSSL"
1.34 + * nor may "OpenSSL" appear in their names without prior written
1.35 + * permission of the OpenSSL Project.
1.36 + *
1.37 + * 6. Redistributions of any form whatsoever must retain the following
1.38 + * acknowledgment:
1.39 + * "This product includes software developed by the OpenSSL Project
1.40 + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
1.41 + *
1.42 + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
1.43 + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1.44 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1.45 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
1.46 + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1.47 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1.48 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1.49 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1.50 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
1.51 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1.52 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
1.53 + * OF THE POSSIBILITY OF SUCH DAMAGE.
1.54 + * ====================================================================
1.55 + *
1.56 + * This product includes cryptographic software written by Eric Young
1.57 + * (eay@cryptsoft.com). This product includes software written by Tim
1.58 + * Hudson (tjh@cryptsoft.com).
1.59 + *
1.60 + */
1.61 +
1.62 +#include "cryptlib.h"
1.63 +#include <openssl/x509.h>
1.64 +#include <openssl/x509v3.h>
1.65 +
1.66 +#include "pcy_int.h"
1.67 +
1.68 +/* Initialize policy tree. Return values:
1.69 + * 0 Some internal error occured.
1.70 + * -1 Inconsistent or invalid extensions in certificates.
1.71 + * 1 Tree initialized OK.
1.72 + * 2 Policy tree is empty.
1.73 + * 5 Tree OK and requireExplicitPolicy true.
1.74 + * 6 Tree empty and requireExplicitPolicy true.
1.75 + */
1.76 +
1.77 +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
1.78 + unsigned int flags)
1.79 + {
1.80 + X509_POLICY_TREE *tree;
1.81 + X509_POLICY_LEVEL *level;
1.82 + const X509_POLICY_CACHE *cache;
1.83 + X509_POLICY_DATA *data = NULL;
1.84 + X509 *x;
1.85 + int ret = 1;
1.86 + int i, n;
1.87 + int explicit_policy;
1.88 + int any_skip;
1.89 + int map_skip;
1.90 + *ptree = NULL;
1.91 + n = sk_X509_num(certs);
1.92 +
1.93 + /* Disable policy mapping for now... */
1.94 + flags |= X509_V_FLAG_INHIBIT_MAP;
1.95 +
1.96 + if (flags & X509_V_FLAG_EXPLICIT_POLICY)
1.97 + explicit_policy = 0;
1.98 + else
1.99 + explicit_policy = n + 1;
1.100 +
1.101 + if (flags & X509_V_FLAG_INHIBIT_ANY)
1.102 + any_skip = 0;
1.103 + else
1.104 + any_skip = n + 1;
1.105 +
1.106 + if (flags & X509_V_FLAG_INHIBIT_MAP)
1.107 + map_skip = 0;
1.108 + else
1.109 + map_skip = n + 1;
1.110 +
1.111 + /* Can't do anything with just a trust anchor */
1.112 + if (n == 1)
1.113 + return 1;
1.114 + /* First setup policy cache in all certificates apart from the
1.115 + * trust anchor. Note any bad cache results on the way. Also can
1.116 + * calculate explicit_policy value at this point.
1.117 + */
1.118 + for (i = n - 2; i >= 0; i--)
1.119 + {
1.120 + x = sk_X509_value(certs, i);
1.121 + X509_check_purpose(x, -1, -1);
1.122 + cache = policy_cache_set(x);
1.123 + /* If cache NULL something bad happened: return immediately */
1.124 + if (cache == NULL)
1.125 + return 0;
1.126 + /* If inconsistent extensions keep a note of it but continue */
1.127 + if (x->ex_flags & EXFLAG_INVALID_POLICY)
1.128 + ret = -1;
1.129 + /* Otherwise if we have no data (hence no CertificatePolicies)
1.130 + * and haven't already set an inconsistent code note it.
1.131 + */
1.132 + else if ((ret == 1) && !cache->data)
1.133 + ret = 2;
1.134 + if (explicit_policy > 0)
1.135 + {
1.136 + explicit_policy--;
1.137 + if (!(x->ex_flags & EXFLAG_SS)
1.138 + && (cache->explicit_skip != -1)
1.139 + && (cache->explicit_skip < explicit_policy))
1.140 + explicit_policy = cache->explicit_skip;
1.141 + }
1.142 + }
1.143 +
1.144 + if (ret != 1)
1.145 + {
1.146 + if (ret == 2 && !explicit_policy)
1.147 + return 6;
1.148 + return ret;
1.149 + }
1.150 +
1.151 +
1.152 + /* If we get this far initialize the tree */
1.153 +
1.154 + tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE));
1.155 +
1.156 + if (!tree)
1.157 + return 0;
1.158 +
1.159 + tree->flags = 0;
1.160 + tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n);
1.161 +#ifdef SYMBIAN
1.162 + if (!tree->levels)
1.163 + return 0;
1.164 +#endif
1.165 + tree->nlevel = 0;
1.166 + tree->extra_data = NULL;
1.167 + tree->auth_policies = NULL;
1.168 + tree->user_policies = NULL;
1.169 +
1.170 + if (!tree)
1.171 + {
1.172 + OPENSSL_free(tree);
1.173 + return 0;
1.174 + }
1.175 +
1.176 + memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL));
1.177 +
1.178 + tree->nlevel = n;
1.179 +
1.180 + level = tree->levels;
1.181 +
1.182 + /* Root data: initialize to anyPolicy */
1.183 +
1.184 + data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0);
1.185 +
1.186 + if (!data || !level_add_node(level, data, NULL, tree))
1.187 + goto bad_tree;
1.188 +
1.189 + for (i = n - 2; i >= 0; i--)
1.190 + {
1.191 + level++;
1.192 + x = sk_X509_value(certs, i);
1.193 + cache = policy_cache_set(x);
1.194 +
1.195 + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
1.196 + level->cert = x;
1.197 +
1.198 + if (!cache->anyPolicy)
1.199 + level->flags |= X509_V_FLAG_INHIBIT_ANY;
1.200 +
1.201 + /* Determine inhibit any and inhibit map flags */
1.202 + if (any_skip == 0)
1.203 + {
1.204 + /* Any matching allowed if certificate is self
1.205 + * issued and not the last in the chain.
1.206 + */
1.207 + if (!(x->ex_flags & EXFLAG_SS) || (i == 0))
1.208 + level->flags |= X509_V_FLAG_INHIBIT_ANY;
1.209 + }
1.210 + else
1.211 + {
1.212 + any_skip--;
1.213 + if ((cache->any_skip > 0)
1.214 + && (cache->any_skip < any_skip))
1.215 + any_skip = cache->any_skip;
1.216 + }
1.217 +
1.218 + if (map_skip == 0)
1.219 + level->flags |= X509_V_FLAG_INHIBIT_MAP;
1.220 + else
1.221 + {
1.222 + map_skip--;
1.223 + if ((cache->map_skip > 0)
1.224 + && (cache->map_skip < map_skip))
1.225 + map_skip = cache->map_skip;
1.226 + }
1.227 +
1.228 +
1.229 + }
1.230 +
1.231 + *ptree = tree;
1.232 +
1.233 + if (explicit_policy)
1.234 + return 1;
1.235 + else
1.236 + return 5;
1.237 +
1.238 + bad_tree:
1.239 +
1.240 + X509_policy_tree_free(tree);
1.241 +
1.242 + return 0;
1.243 +
1.244 + }
1.245 +
1.246 +/* This corresponds to RFC3280 XXXX XXXXX:
1.247 + * link any data from CertificatePolicies onto matching parent
1.248 + * or anyPolicy if no match.
1.249 + */
1.250 +
1.251 +static int tree_link_nodes(X509_POLICY_LEVEL *curr,
1.252 + const X509_POLICY_CACHE *cache)
1.253 + {
1.254 + int i;
1.255 + X509_POLICY_LEVEL *last;
1.256 + X509_POLICY_DATA *data;
1.257 + X509_POLICY_NODE *parent;
1.258 + last = curr - 1;
1.259 + for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++)
1.260 + {
1.261 + data = sk_X509_POLICY_DATA_value(cache->data, i);
1.262 + /* If a node is mapped any it doesn't have a corresponding
1.263 + * CertificatePolicies entry.
1.264 + * However such an identical node would be created
1.265 + * if anyPolicy matching is enabled because there would be
1.266 + * no match with the parent valid_policy_set. So we create
1.267 + * link because then it will have the mapping flags
1.268 + * right and we can prune it later.
1.269 + */
1.270 + if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY)
1.271 + && !(curr->flags & X509_V_FLAG_INHIBIT_ANY))
1.272 + continue;
1.273 + /* Look for matching node in parent */
1.274 + parent = level_find_node(last, data->valid_policy);
1.275 + /* If no match link to anyPolicy */
1.276 + if (!parent)
1.277 + parent = last->anyPolicy;
1.278 + if (parent && !level_add_node(curr, data, parent, NULL))
1.279 + return 0;
1.280 + }
1.281 + return 1;
1.282 + }
1.283 +
1.284 +/* This corresponds to RFC3280 XXXX XXXXX:
1.285 + * Create new data for any unmatched policies in the parent and link
1.286 + * to anyPolicy.
1.287 + */
1.288 +
1.289 +static int tree_link_any(X509_POLICY_LEVEL *curr,
1.290 + const X509_POLICY_CACHE *cache,
1.291 + X509_POLICY_TREE *tree)
1.292 + {
1.293 + int i;
1.294 + X509_POLICY_DATA *data;
1.295 + X509_POLICY_NODE *node;
1.296 + X509_POLICY_LEVEL *last;
1.297 +
1.298 + last = curr - 1;
1.299 +
1.300 + for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++)
1.301 + {
1.302 + node = sk_X509_POLICY_NODE_value(last->nodes, i);
1.303 +
1.304 + /* Skip any node with any children: we only want unmathced
1.305 + * nodes.
1.306 + *
1.307 + * Note: need something better for policy mapping
1.308 + * because each node may have multiple children
1.309 + */
1.310 + if (node->nchild)
1.311 + continue;
1.312 + /* Create a new node with qualifiers from anyPolicy and
1.313 + * id from unmatched node.
1.314 + */
1.315 + data = policy_data_new(NULL, node->data->valid_policy,
1.316 + node_critical(node));
1.317 +
1.318 + if (data == NULL)
1.319 + return 0;
1.320 + data->qualifier_set = curr->anyPolicy->data->qualifier_set;
1.321 + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
1.322 + if (!level_add_node(curr, data, node, tree))
1.323 + {
1.324 + policy_data_free(data);
1.325 + return 0;
1.326 + }
1.327 + }
1.328 + /* Finally add link to anyPolicy */
1.329 + if (last->anyPolicy)
1.330 + {
1.331 + if (!level_add_node(curr, cache->anyPolicy,
1.332 + last->anyPolicy, NULL))
1.333 + return 0;
1.334 + }
1.335 + return 1;
1.336 + }
1.337 +
1.338 +/* Prune the tree: delete any child mapped child data on the current level
1.339 + * then proceed up the tree deleting any data with no children. If we ever
1.340 + * have no data on a level we can halt because the tree will be empty.
1.341 + */
1.342 +
1.343 +static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
1.344 + {
1.345 + X509_POLICY_NODE *node;
1.346 + int i;
1.347 + for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
1.348 + {
1.349 + node = sk_X509_POLICY_NODE_value(curr->nodes, i);
1.350 + /* Delete any mapped data: see RFC3280 XXXX */
1.351 + if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK)
1.352 + {
1.353 + node->parent->nchild--;
1.354 + OPENSSL_free(node);
1.355 + (void)sk_X509_POLICY_NODE_delete(curr->nodes, i);
1.356 + }
1.357 + }
1.358 +
1.359 + for(;;) {
1.360 + --curr;
1.361 + for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
1.362 + {
1.363 + node = sk_X509_POLICY_NODE_value(curr->nodes, i);
1.364 + if (node->nchild == 0)
1.365 + {
1.366 + node->parent->nchild--;
1.367 + OPENSSL_free(node);
1.368 + (void)sk_X509_POLICY_NODE_delete(curr->nodes, i);
1.369 + }
1.370 + }
1.371 + if (curr->anyPolicy && !curr->anyPolicy->nchild)
1.372 + {
1.373 + if (curr->anyPolicy->parent)
1.374 + curr->anyPolicy->parent->nchild--;
1.375 + OPENSSL_free(curr->anyPolicy);
1.376 + curr->anyPolicy = NULL;
1.377 + }
1.378 + if (curr == tree->levels)
1.379 + {
1.380 + /* If we zapped anyPolicy at top then tree is empty */
1.381 + if (!curr->anyPolicy)
1.382 + return 2;
1.383 + return 1;
1.384 + }
1.385 + }
1.386 +
1.387 + return 1;
1.388 +
1.389 + }
1.390 +
1.391 +static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes,
1.392 + X509_POLICY_NODE *pcy)
1.393 + {
1.394 + if (!*pnodes)
1.395 + {
1.396 + *pnodes = policy_node_cmp_new();
1.397 + if (!*pnodes)
1.398 + return 0;
1.399 + }
1.400 + else if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1)
1.401 + return 1;
1.402 +
1.403 + if (!sk_X509_POLICY_NODE_push(*pnodes, pcy))
1.404 + return 0;
1.405 +
1.406 + return 1;
1.407 +
1.408 + }
1.409 +
1.410 +/* Calculate the authority set based on policy tree.
1.411 + * The 'pnodes' parameter is used as a store for the set of policy nodes
1.412 + * used to calculate the user set. If the authority set is not anyPolicy
1.413 + * then pnodes will just point to the authority set. If however the authority
1.414 + * set is anyPolicy then the set of valid policies (other than anyPolicy)
1.415 + * is store in pnodes. The return value of '2' is used in this case to indicate
1.416 + * that pnodes should be freed.
1.417 + */
1.418 +
1.419 +static int tree_calculate_authority_set(X509_POLICY_TREE *tree,
1.420 + STACK_OF(X509_POLICY_NODE) **pnodes)
1.421 + {
1.422 + X509_POLICY_LEVEL *curr;
1.423 + X509_POLICY_NODE *node, *anyptr;
1.424 + STACK_OF(X509_POLICY_NODE) **addnodes;
1.425 + int i, j;
1.426 + curr = tree->levels + tree->nlevel - 1;
1.427 +
1.428 + /* If last level contains anyPolicy set is anyPolicy */
1.429 + if (curr->anyPolicy)
1.430 + {
1.431 + if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy))
1.432 + return 0;
1.433 + addnodes = pnodes;
1.434 + }
1.435 + else
1.436 + /* Add policies to authority set */
1.437 + addnodes = &tree->auth_policies;
1.438 +
1.439 + curr = tree->levels;
1.440 + for (i = 1; i < tree->nlevel; i++)
1.441 + {
1.442 + /* If no anyPolicy node on this this level it can't
1.443 + * appear on lower levels so end search.
1.444 + */
1.445 + if (!(anyptr = curr->anyPolicy))
1.446 + break;
1.447 + curr++;
1.448 + for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++)
1.449 + {
1.450 + node = sk_X509_POLICY_NODE_value(curr->nodes, j);
1.451 + if ((node->parent == anyptr)
1.452 + && !tree_add_auth_node(addnodes, node))
1.453 + return 0;
1.454 + }
1.455 + }
1.456 +
1.457 + if (addnodes == pnodes)
1.458 + return 2;
1.459 +
1.460 + *pnodes = tree->auth_policies;
1.461 +
1.462 + return 1;
1.463 + }
1.464 +
1.465 +static int tree_calculate_user_set(X509_POLICY_TREE *tree,
1.466 + STACK_OF(ASN1_OBJECT) *policy_oids,
1.467 + STACK_OF(X509_POLICY_NODE) *auth_nodes)
1.468 + {
1.469 + int i;
1.470 + X509_POLICY_NODE *node;
1.471 + ASN1_OBJECT *oid;
1.472 +
1.473 + X509_POLICY_NODE *anyPolicy;
1.474 + X509_POLICY_DATA *extra;
1.475 +
1.476 + /* Check if anyPolicy present in authority constrained policy set:
1.477 + * this will happen if it is a leaf node.
1.478 + */
1.479 +
1.480 + if (sk_ASN1_OBJECT_num(policy_oids) <= 0)
1.481 + return 1;
1.482 +
1.483 + anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy;
1.484 +
1.485 + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
1.486 + {
1.487 + oid = sk_ASN1_OBJECT_value(policy_oids, i);
1.488 + if (OBJ_obj2nid(oid) == NID_any_policy)
1.489 + {
1.490 + tree->flags |= POLICY_FLAG_ANY_POLICY;
1.491 + return 1;
1.492 + }
1.493 + }
1.494 +
1.495 + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
1.496 + {
1.497 + oid = sk_ASN1_OBJECT_value(policy_oids, i);
1.498 + node = tree_find_sk(auth_nodes, oid);
1.499 + if (!node)
1.500 + {
1.501 + if (!anyPolicy)
1.502 + continue;
1.503 + /* Create a new node with policy ID from user set
1.504 + * and qualifiers from anyPolicy.
1.505 + */
1.506 + extra = policy_data_new(NULL, oid,
1.507 + node_critical(anyPolicy));
1.508 + if (!extra)
1.509 + return 0;
1.510 + extra->qualifier_set = anyPolicy->data->qualifier_set;
1.511 + extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
1.512 + | POLICY_DATA_FLAG_EXTRA_NODE;
1.513 + node = level_add_node(NULL, extra, anyPolicy->parent,
1.514 + tree);
1.515 + }
1.516 + if (!tree->user_policies)
1.517 + {
1.518 + tree->user_policies = sk_X509_POLICY_NODE_new_null();
1.519 + if (!tree->user_policies)
1.520 + return 1;
1.521 + }
1.522 + if (!sk_X509_POLICY_NODE_push(tree->user_policies, node))
1.523 + return 0;
1.524 + }
1.525 + return 1;
1.526 +
1.527 + }
1.528 +
1.529 +static int tree_evaluate(X509_POLICY_TREE *tree)
1.530 + {
1.531 + int ret, i;
1.532 + X509_POLICY_LEVEL *curr = tree->levels + 1;
1.533 + const X509_POLICY_CACHE *cache;
1.534 +
1.535 + for(i = 1; i < tree->nlevel; i++, curr++)
1.536 + {
1.537 + cache = policy_cache_set(curr->cert);
1.538 + if (!tree_link_nodes(curr, cache))
1.539 + return 0;
1.540 +
1.541 + if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
1.542 + && !tree_link_any(curr, cache, tree))
1.543 + return 0;
1.544 + ret = tree_prune(tree, curr);
1.545 + if (ret != 1)
1.546 + return ret;
1.547 + }
1.548 +
1.549 + return 1;
1.550 +
1.551 + }
1.552 +
1.553 +static void exnode_free(X509_POLICY_NODE *node)
1.554 + {
1.555 + if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE))
1.556 + OPENSSL_free(node);
1.557 + }
1.558 +
1.559 +
1.560 +EXPORT_C void X509_policy_tree_free(X509_POLICY_TREE *tree)
1.561 + {
1.562 + X509_POLICY_LEVEL *curr;
1.563 + int i;
1.564 +
1.565 + if (!tree)
1.566 + return;
1.567 +
1.568 + sk_X509_POLICY_NODE_free(tree->auth_policies);
1.569 + sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free);
1.570 +
1.571 + for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++)
1.572 + {
1.573 + if (curr->cert)
1.574 + X509_free(curr->cert);
1.575 + if (curr->nodes)
1.576 + sk_X509_POLICY_NODE_pop_free(curr->nodes,
1.577 + policy_node_free);
1.578 + if (curr->anyPolicy)
1.579 + policy_node_free(curr->anyPolicy);
1.580 + }
1.581 +
1.582 + if (tree->extra_data)
1.583 + sk_X509_POLICY_DATA_pop_free(tree->extra_data,
1.584 + policy_data_free);
1.585 +
1.586 + OPENSSL_free(tree->levels);
1.587 + OPENSSL_free(tree);
1.588 +
1.589 + }
1.590 +
1.591 +/* Application policy checking function.
1.592 + * Return codes:
1.593 + * 0 Internal Error.
1.594 + * 1 Successful.
1.595 + * -1 One or more certificates contain invalid or inconsistent extensions
1.596 + * -2 User constrained policy set empty and requireExplicit true.
1.597 + */
1.598 +
1.599 +EXPORT_C int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
1.600 + STACK_OF(X509) *certs,
1.601 + STACK_OF(ASN1_OBJECT) *policy_oids,
1.602 + unsigned int flags)
1.603 + {
1.604 + int ret;
1.605 + X509_POLICY_TREE *tree = NULL;
1.606 + STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL;
1.607 + *ptree = NULL;
1.608 +
1.609 + *pexplicit_policy = 0;
1.610 + ret = tree_init(&tree, certs, flags);
1.611 +
1.612 +
1.613 + switch (ret)
1.614 + {
1.615 +
1.616 + /* Tree empty requireExplicit False: OK */
1.617 + case 2:
1.618 + return 1;
1.619 +
1.620 + /* Some internal error */
1.621 + case 0:
1.622 + return 0;
1.623 +
1.624 + /* Tree empty requireExplicit True: Error */
1.625 +
1.626 + case 6:
1.627 + *pexplicit_policy = 1;
1.628 + return -2;
1.629 +
1.630 + /* Tree OK requireExplicit True: OK and continue */
1.631 + case 5:
1.632 + *pexplicit_policy = 1;
1.633 + break;
1.634 +
1.635 + /* Tree OK: continue */
1.636 +
1.637 + case 1:
1.638 + if (!tree)
1.639 + /*
1.640 + * tree_init() returns success and a null tree
1.641 + * if it's just looking at a trust anchor.
1.642 + * I'm not sure that returning success here is
1.643 + * correct, but I'm sure that reporting this
1.644 + * as an internal error which our caller
1.645 + * interprets as a malloc failure is wrong.
1.646 + */
1.647 + return 1;
1.648 + break;
1.649 + }
1.650 + if (!tree) goto error;
1.651 + ret = tree_evaluate(tree);
1.652 +
1.653 + if (ret <= 0)
1.654 + goto error;
1.655 +
1.656 + /* Return value 2 means tree empty */
1.657 + if (ret == 2)
1.658 + {
1.659 + X509_policy_tree_free(tree);
1.660 + if (*pexplicit_policy)
1.661 + return -2;
1.662 + else
1.663 + return 1;
1.664 + }
1.665 +
1.666 + /* Tree is not empty: continue */
1.667 +
1.668 + ret = tree_calculate_authority_set(tree, &auth_nodes);
1.669 +
1.670 + if (!ret)
1.671 + goto error;
1.672 +
1.673 + if (!tree_calculate_user_set(tree, policy_oids, auth_nodes))
1.674 + goto error;
1.675 +
1.676 + if (ret == 2)
1.677 + sk_X509_POLICY_NODE_free(auth_nodes);
1.678 +
1.679 + if (tree)
1.680 + *ptree = tree;
1.681 +
1.682 + if (*pexplicit_policy)
1.683 + {
1.684 + nodes = X509_policy_tree_get0_user_policies(tree);
1.685 + if (sk_X509_POLICY_NODE_num(nodes) <= 0)
1.686 + return -2;
1.687 + }
1.688 +
1.689 + return 1;
1.690 +
1.691 + error:
1.692 +
1.693 + X509_policy_tree_free(tree);
1.694 +
1.695 + return 0;
1.696 +
1.697 + }
1.698 +