Line data Source code
1 : /* pcy_tree.c */
2 : /*
3 : * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4 : * 2004.
5 : */
6 : /* ====================================================================
7 : * Copyright (c) 2004 The OpenSSL Project. All rights reserved.
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions
11 : * are met:
12 : *
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer.
15 : *
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in
18 : * the documentation and/or other materials provided with the
19 : * distribution.
20 : *
21 : * 3. All advertising materials mentioning features or use of this
22 : * software must display the following acknowledgment:
23 : * "This product includes software developed by the OpenSSL Project
24 : * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 : *
26 : * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 : * endorse or promote products derived from this software without
28 : * prior written permission. For written permission, please contact
29 : * licensing@OpenSSL.org.
30 : *
31 : * 5. Products derived from this software may not be called "OpenSSL"
32 : * nor may "OpenSSL" appear in their names without prior written
33 : * permission of the OpenSSL Project.
34 : *
35 : * 6. Redistributions of any form whatsoever must retain the following
36 : * acknowledgment:
37 : * "This product includes software developed by the OpenSSL Project
38 : * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 : *
40 : * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 : * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 : * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 : * OF THE POSSIBILITY OF SUCH DAMAGE.
52 : * ====================================================================
53 : *
54 : * This product includes cryptographic software written by Eric Young
55 : * (eay@cryptsoft.com). This product includes software written by Tim
56 : * Hudson (tjh@cryptsoft.com).
57 : *
58 : */
59 :
60 : #include "cryptlib.h"
61 : #include <openssl/x509.h>
62 : #include <openssl/x509v3.h>
63 :
64 : #include "pcy_int.h"
65 :
66 : /*
67 : * Enable this to print out the complete policy tree at various point during
68 : * evaluation.
69 : */
70 :
71 : /*
72 : * #define OPENSSL_POLICY_DEBUG
73 : */
74 :
75 : #ifdef OPENSSL_POLICY_DEBUG
76 :
77 : static void expected_print(BIO *err, X509_POLICY_LEVEL *lev,
78 : X509_POLICY_NODE *node, int indent)
79 : {
80 : if ((lev->flags & X509_V_FLAG_INHIBIT_MAP)
81 : || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK))
82 : BIO_puts(err, " Not Mapped\n");
83 : else {
84 : int i;
85 : STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set;
86 : ASN1_OBJECT *oid;
87 : BIO_puts(err, " Expected: ");
88 : for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) {
89 : oid = sk_ASN1_OBJECT_value(pset, i);
90 : if (i)
91 : BIO_puts(err, ", ");
92 : i2a_ASN1_OBJECT(err, oid);
93 : }
94 : BIO_puts(err, "\n");
95 : }
96 : }
97 :
98 : static void tree_print(char *str, X509_POLICY_TREE *tree,
99 : X509_POLICY_LEVEL *curr)
100 : {
101 : X509_POLICY_LEVEL *plev;
102 : X509_POLICY_NODE *node;
103 : int i;
104 : BIO *err;
105 : err = BIO_new_fp(stderr, BIO_NOCLOSE);
106 : if (!curr)
107 : curr = tree->levels + tree->nlevel;
108 : else
109 : curr++;
110 : BIO_printf(err, "Level print after %s\n", str);
111 : BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels);
112 : for (plev = tree->levels; plev != curr; plev++) {
113 : BIO_printf(err, "Level %ld, flags = %x\n",
114 : plev - tree->levels, plev->flags);
115 : for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) {
116 : node = sk_X509_POLICY_NODE_value(plev->nodes, i);
117 : X509_POLICY_NODE_print(err, node, 2);
118 : expected_print(err, plev, node, 2);
119 : BIO_printf(err, " Flags: %x\n", node->data->flags);
120 : }
121 : if (plev->anyPolicy)
122 : X509_POLICY_NODE_print(err, plev->anyPolicy, 2);
123 : }
124 :
125 : BIO_free(err);
126 :
127 : }
128 : #else
129 :
130 : # define tree_print(a,b,c) /* */
131 :
132 : #endif
133 :
134 : /*-
135 : * Initialize policy tree. Return values:
136 : * 0 Some internal error occurred.
137 : * -1 Inconsistent or invalid extensions in certificates.
138 : * 1 Tree initialized OK.
139 : * 2 Policy tree is empty.
140 : * 5 Tree OK and requireExplicitPolicy true.
141 : * 6 Tree empty and requireExplicitPolicy true.
142 : */
143 :
144 0 : static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
145 : unsigned int flags)
146 : {
147 : X509_POLICY_TREE *tree;
148 : X509_POLICY_LEVEL *level;
149 : const X509_POLICY_CACHE *cache;
150 : X509_POLICY_DATA *data = NULL;
151 : X509 *x;
152 : int ret = 1;
153 : int i, n;
154 : int explicit_policy;
155 : int any_skip;
156 : int map_skip;
157 0 : *ptree = NULL;
158 0 : n = sk_X509_num(certs);
159 :
160 : #if 0
161 : /* Disable policy mapping for now... */
162 : flags |= X509_V_FLAG_INHIBIT_MAP;
163 : #endif
164 :
165 0 : if (flags & X509_V_FLAG_EXPLICIT_POLICY)
166 : explicit_policy = 0;
167 : else
168 0 : explicit_policy = n + 1;
169 :
170 0 : if (flags & X509_V_FLAG_INHIBIT_ANY)
171 : any_skip = 0;
172 : else
173 0 : any_skip = n + 1;
174 :
175 0 : if (flags & X509_V_FLAG_INHIBIT_MAP)
176 : map_skip = 0;
177 : else
178 0 : map_skip = n + 1;
179 :
180 : /* Can't do anything with just a trust anchor */
181 0 : if (n == 1)
182 : return 1;
183 : /*
184 : * First setup policy cache in all certificates apart from the trust
185 : * anchor. Note any bad cache results on the way. Also can calculate
186 : * explicit_policy value at this point.
187 : */
188 0 : for (i = n - 2; i >= 0; i--) {
189 0 : x = sk_X509_value(certs, i);
190 0 : X509_check_purpose(x, -1, -1);
191 0 : cache = policy_cache_set(x);
192 : /* If cache NULL something bad happened: return immediately */
193 0 : if (cache == NULL)
194 : return 0;
195 : /*
196 : * If inconsistent extensions keep a note of it but continue
197 : */
198 0 : if (x->ex_flags & EXFLAG_INVALID_POLICY)
199 : ret = -1;
200 : /*
201 : * Otherwise if we have no data (hence no CertificatePolicies) and
202 : * haven't already set an inconsistent code note it.
203 : */
204 0 : else if ((ret == 1) && !cache->data)
205 : ret = 2;
206 0 : if (explicit_policy > 0) {
207 0 : if (!(x->ex_flags & EXFLAG_SI))
208 0 : explicit_policy--;
209 0 : if ((cache->explicit_skip != -1)
210 0 : && (cache->explicit_skip < explicit_policy))
211 0 : explicit_policy = cache->explicit_skip;
212 : }
213 : }
214 :
215 0 : if (ret != 1) {
216 0 : if (ret == 2 && !explicit_policy)
217 : return 6;
218 0 : return ret;
219 : }
220 :
221 : /* If we get this far initialize the tree */
222 :
223 0 : tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE));
224 :
225 0 : if (!tree)
226 : return 0;
227 :
228 0 : tree->flags = 0;
229 0 : tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n);
230 0 : tree->nlevel = 0;
231 0 : tree->extra_data = NULL;
232 0 : tree->auth_policies = NULL;
233 0 : tree->user_policies = NULL;
234 :
235 0 : if (!tree->levels) {
236 0 : OPENSSL_free(tree);
237 0 : return 0;
238 : }
239 :
240 0 : memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL));
241 :
242 0 : tree->nlevel = n;
243 :
244 0 : level = tree->levels;
245 :
246 : /* Root data: initialize to anyPolicy */
247 :
248 0 : data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0);
249 :
250 0 : if (!data || !level_add_node(level, data, NULL, tree))
251 : goto bad_tree;
252 :
253 0 : for (i = n - 2; i >= 0; i--) {
254 0 : level++;
255 0 : x = sk_X509_value(certs, i);
256 0 : cache = policy_cache_set(x);
257 0 : CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
258 0 : level->cert = x;
259 :
260 0 : if (!cache->anyPolicy)
261 0 : level->flags |= X509_V_FLAG_INHIBIT_ANY;
262 :
263 : /* Determine inhibit any and inhibit map flags */
264 0 : if (any_skip == 0) {
265 : /*
266 : * Any matching allowed if certificate is self issued and not the
267 : * last in the chain.
268 : */
269 0 : if (!(x->ex_flags & EXFLAG_SI) || (i == 0))
270 0 : level->flags |= X509_V_FLAG_INHIBIT_ANY;
271 : } else {
272 0 : if (!(x->ex_flags & EXFLAG_SI))
273 0 : any_skip--;
274 0 : if ((cache->any_skip >= 0)
275 0 : && (cache->any_skip < any_skip))
276 0 : any_skip = cache->any_skip;
277 : }
278 :
279 0 : if (map_skip == 0)
280 0 : level->flags |= X509_V_FLAG_INHIBIT_MAP;
281 : else {
282 0 : if (!(x->ex_flags & EXFLAG_SI))
283 0 : map_skip--;
284 0 : if ((cache->map_skip >= 0)
285 0 : && (cache->map_skip < map_skip))
286 0 : map_skip = cache->map_skip;
287 : }
288 :
289 : }
290 :
291 0 : *ptree = tree;
292 :
293 0 : if (explicit_policy)
294 : return 1;
295 : else
296 0 : return 5;
297 :
298 : bad_tree:
299 :
300 0 : X509_policy_tree_free(tree);
301 :
302 0 : return 0;
303 :
304 : }
305 :
306 0 : static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
307 : const X509_POLICY_DATA *data)
308 : {
309 0 : X509_POLICY_LEVEL *last = curr - 1;
310 : X509_POLICY_NODE *node;
311 : int i, matched = 0;
312 : /* Iterate through all in nodes linking matches */
313 0 : for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) {
314 0 : node = sk_X509_POLICY_NODE_value(last->nodes, i);
315 0 : if (policy_node_match(last, node, data->valid_policy)) {
316 0 : if (!level_add_node(curr, data, node, NULL))
317 : return 0;
318 : matched = 1;
319 : }
320 : }
321 0 : if (!matched && last->anyPolicy) {
322 0 : if (!level_add_node(curr, data, last->anyPolicy, NULL))
323 : return 0;
324 : }
325 : return 1;
326 : }
327 :
328 : /*
329 : * This corresponds to RFC3280 6.1.3(d)(1): link any data from
330 : * CertificatePolicies onto matching parent or anyPolicy if no match.
331 : */
332 :
333 0 : static int tree_link_nodes(X509_POLICY_LEVEL *curr,
334 : const X509_POLICY_CACHE *cache)
335 : {
336 : int i;
337 : X509_POLICY_DATA *data;
338 :
339 0 : for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) {
340 0 : data = sk_X509_POLICY_DATA_value(cache->data, i);
341 : /*
342 : * If a node is mapped any it doesn't have a corresponding
343 : * CertificatePolicies entry. However such an identical node would
344 : * be created if anyPolicy matching is enabled because there would be
345 : * no match with the parent valid_policy_set. So we create link
346 : * because then it will have the mapping flags right and we can prune
347 : * it later.
348 : */
349 : #if 0
350 : if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY)
351 : && !(curr->flags & X509_V_FLAG_INHIBIT_ANY))
352 : continue;
353 : #endif
354 : /* Look for matching nodes in previous level */
355 0 : if (!tree_link_matching_nodes(curr, data))
356 : return 0;
357 : }
358 : return 1;
359 : }
360 :
361 : /*
362 : * This corresponds to RFC3280 6.1.3(d)(2): Create new data for any unmatched
363 : * policies in the parent and link to anyPolicy.
364 : */
365 :
366 0 : static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
367 : const X509_POLICY_CACHE *cache,
368 : const ASN1_OBJECT *id,
369 : X509_POLICY_NODE *node, X509_POLICY_TREE *tree)
370 : {
371 : X509_POLICY_DATA *data;
372 0 : if (id == NULL)
373 0 : id = node->data->valid_policy;
374 : /*
375 : * Create a new node with qualifiers from anyPolicy and id from unmatched
376 : * node.
377 : */
378 0 : data = policy_data_new(NULL, id, node_critical(node));
379 :
380 0 : if (data == NULL)
381 : return 0;
382 : /* Curr may not have anyPolicy */
383 0 : data->qualifier_set = cache->anyPolicy->qualifier_set;
384 0 : data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
385 0 : if (!level_add_node(curr, data, node, tree)) {
386 0 : policy_data_free(data);
387 : return 0;
388 : }
389 :
390 : return 1;
391 : }
392 :
393 0 : static int tree_link_unmatched(X509_POLICY_LEVEL *curr,
394 : const X509_POLICY_CACHE *cache,
395 : X509_POLICY_NODE *node, X509_POLICY_TREE *tree)
396 : {
397 : const X509_POLICY_LEVEL *last = curr - 1;
398 : int i;
399 :
400 0 : if ((last->flags & X509_V_FLAG_INHIBIT_MAP)
401 0 : || !(node->data->flags & POLICY_DATA_FLAG_MAPPED)) {
402 : /* If no policy mapping: matched if one child present */
403 0 : if (node->nchild)
404 : return 1;
405 0 : if (!tree_add_unmatched(curr, cache, NULL, node, tree))
406 : return 0;
407 : /* Add it */
408 : } else {
409 : /* If mapping: matched if one child per expected policy set */
410 0 : STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set;
411 0 : if (node->nchild == sk_ASN1_OBJECT_num(expset))
412 : return 1;
413 : /* Locate unmatched nodes */
414 0 : for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++) {
415 0 : ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i);
416 0 : if (level_find_node(curr, node, oid))
417 0 : continue;
418 0 : if (!tree_add_unmatched(curr, cache, oid, node, tree))
419 : return 0;
420 : }
421 :
422 : }
423 :
424 : return 1;
425 :
426 : }
427 :
428 0 : static int tree_link_any(X509_POLICY_LEVEL *curr,
429 : const X509_POLICY_CACHE *cache,
430 : X509_POLICY_TREE *tree)
431 : {
432 : int i;
433 : /*
434 : * X509_POLICY_DATA *data;
435 : */
436 : X509_POLICY_NODE *node;
437 : X509_POLICY_LEVEL *last = curr - 1;
438 :
439 0 : for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) {
440 0 : node = sk_X509_POLICY_NODE_value(last->nodes, i);
441 :
442 0 : if (!tree_link_unmatched(curr, cache, node, tree))
443 : return 0;
444 :
445 : #if 0
446 :
447 : /*
448 : * Skip any node with any children: we only want unmathced nodes.
449 : * Note: need something better for policy mapping because each node
450 : * may have multiple children
451 : */
452 : if (node->nchild)
453 : continue;
454 :
455 : /*
456 : * Create a new node with qualifiers from anyPolicy and id from
457 : * unmatched node.
458 : */
459 : data = policy_data_new(NULL, node->data->valid_policy,
460 : node_critical(node));
461 :
462 : if (data == NULL)
463 : return 0;
464 : /* Curr may not have anyPolicy */
465 : data->qualifier_set = cache->anyPolicy->qualifier_set;
466 : data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
467 : if (!level_add_node(curr, data, node, tree)) {
468 : policy_data_free(data);
469 : return 0;
470 : }
471 : #endif
472 :
473 : }
474 : /* Finally add link to anyPolicy */
475 0 : if (last->anyPolicy) {
476 0 : if (!level_add_node(curr, cache->anyPolicy, last->anyPolicy, NULL))
477 : return 0;
478 : }
479 : return 1;
480 : }
481 :
482 : /*
483 : * Prune the tree: delete any child mapped child data on the current level
484 : * then proceed up the tree deleting any data with no children. If we ever
485 : * have no data on a level we can halt because the tree will be empty.
486 : */
487 :
488 0 : static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
489 : {
490 : STACK_OF(X509_POLICY_NODE) *nodes;
491 : X509_POLICY_NODE *node;
492 : int i;
493 0 : nodes = curr->nodes;
494 0 : if (curr->flags & X509_V_FLAG_INHIBIT_MAP) {
495 0 : for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) {
496 0 : node = sk_X509_POLICY_NODE_value(nodes, i);
497 : /* Delete any mapped data: see RFC3280 XXXX */
498 0 : if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) {
499 0 : node->parent->nchild--;
500 0 : OPENSSL_free(node);
501 0 : (void)sk_X509_POLICY_NODE_delete(nodes, i);
502 : }
503 : }
504 : }
505 :
506 : for (;;) {
507 0 : --curr;
508 0 : nodes = curr->nodes;
509 0 : for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) {
510 0 : node = sk_X509_POLICY_NODE_value(nodes, i);
511 0 : if (node->nchild == 0) {
512 0 : node->parent->nchild--;
513 0 : OPENSSL_free(node);
514 0 : (void)sk_X509_POLICY_NODE_delete(nodes, i);
515 : }
516 : }
517 0 : if (curr->anyPolicy && !curr->anyPolicy->nchild) {
518 0 : if (curr->anyPolicy->parent)
519 0 : curr->anyPolicy->parent->nchild--;
520 0 : OPENSSL_free(curr->anyPolicy);
521 0 : curr->anyPolicy = NULL;
522 : }
523 0 : if (curr == tree->levels) {
524 : /* If we zapped anyPolicy at top then tree is empty */
525 0 : if (!curr->anyPolicy)
526 : return 2;
527 : return 1;
528 : }
529 : }
530 :
531 : return 1;
532 :
533 : }
534 :
535 0 : static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes,
536 : X509_POLICY_NODE *pcy)
537 : {
538 0 : if (!*pnodes) {
539 0 : *pnodes = policy_node_cmp_new();
540 0 : if (!*pnodes)
541 : return 0;
542 0 : } else if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1)
543 : return 1;
544 :
545 0 : if (!sk_X509_POLICY_NODE_push(*pnodes, pcy))
546 : return 0;
547 :
548 0 : return 1;
549 :
550 : }
551 :
552 : /*
553 : * Calculate the authority set based on policy tree. The 'pnodes' parameter
554 : * is used as a store for the set of policy nodes used to calculate the user
555 : * set. If the authority set is not anyPolicy then pnodes will just point to
556 : * the authority set. If however the authority set is anyPolicy then the set
557 : * of valid policies (other than anyPolicy) is store in pnodes. The return
558 : * value of '2' is used in this case to indicate that pnodes should be freed.
559 : */
560 :
561 0 : static int tree_calculate_authority_set(X509_POLICY_TREE *tree,
562 : STACK_OF(X509_POLICY_NODE) **pnodes)
563 : {
564 : X509_POLICY_LEVEL *curr;
565 : X509_POLICY_NODE *node, *anyptr;
566 : STACK_OF(X509_POLICY_NODE) **addnodes;
567 : int i, j;
568 0 : curr = tree->levels + tree->nlevel - 1;
569 :
570 : /* If last level contains anyPolicy set is anyPolicy */
571 0 : if (curr->anyPolicy) {
572 0 : if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy))
573 : return 0;
574 : addnodes = pnodes;
575 : } else
576 : /* Add policies to authority set */
577 0 : addnodes = &tree->auth_policies;
578 :
579 0 : curr = tree->levels;
580 0 : for (i = 1; i < tree->nlevel; i++) {
581 : /*
582 : * If no anyPolicy node on this this level it can't appear on lower
583 : * levels so end search.
584 : */
585 0 : if (!(anyptr = curr->anyPolicy))
586 : break;
587 0 : curr++;
588 0 : for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) {
589 0 : node = sk_X509_POLICY_NODE_value(curr->nodes, j);
590 0 : if ((node->parent == anyptr)
591 0 : && !tree_add_auth_node(addnodes, node))
592 : return 0;
593 : }
594 : }
595 :
596 0 : if (addnodes == pnodes)
597 : return 2;
598 :
599 0 : *pnodes = tree->auth_policies;
600 :
601 0 : return 1;
602 : }
603 :
604 0 : static int tree_calculate_user_set(X509_POLICY_TREE *tree,
605 : STACK_OF(ASN1_OBJECT) *policy_oids,
606 : STACK_OF(X509_POLICY_NODE) *auth_nodes)
607 : {
608 : int i;
609 : X509_POLICY_NODE *node;
610 : ASN1_OBJECT *oid;
611 :
612 : X509_POLICY_NODE *anyPolicy;
613 : X509_POLICY_DATA *extra;
614 :
615 : /*
616 : * Check if anyPolicy present in authority constrained policy set: this
617 : * will happen if it is a leaf node.
618 : */
619 :
620 0 : if (sk_ASN1_OBJECT_num(policy_oids) <= 0)
621 : return 1;
622 :
623 0 : anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy;
624 :
625 0 : for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) {
626 0 : oid = sk_ASN1_OBJECT_value(policy_oids, i);
627 0 : if (OBJ_obj2nid(oid) == NID_any_policy) {
628 0 : tree->flags |= POLICY_FLAG_ANY_POLICY;
629 0 : return 1;
630 : }
631 : }
632 :
633 0 : for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) {
634 0 : oid = sk_ASN1_OBJECT_value(policy_oids, i);
635 0 : node = tree_find_sk(auth_nodes, oid);
636 0 : if (!node) {
637 0 : if (!anyPolicy)
638 0 : continue;
639 : /*
640 : * Create a new node with policy ID from user set and qualifiers
641 : * from anyPolicy.
642 : */
643 0 : extra = policy_data_new(NULL, oid, node_critical(anyPolicy));
644 0 : if (!extra)
645 : return 0;
646 0 : extra->qualifier_set = anyPolicy->data->qualifier_set;
647 0 : extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
648 : | POLICY_DATA_FLAG_EXTRA_NODE;
649 0 : node = level_add_node(NULL, extra, anyPolicy->parent, tree);
650 : }
651 0 : if (!tree->user_policies) {
652 0 : tree->user_policies = sk_X509_POLICY_NODE_new_null();
653 0 : if (!tree->user_policies)
654 : return 1;
655 : }
656 0 : if (!sk_X509_POLICY_NODE_push(tree->user_policies, node))
657 : return 0;
658 : }
659 : return 1;
660 :
661 : }
662 :
663 0 : static int tree_evaluate(X509_POLICY_TREE *tree)
664 : {
665 : int ret, i;
666 0 : X509_POLICY_LEVEL *curr = tree->levels + 1;
667 : const X509_POLICY_CACHE *cache;
668 :
669 0 : for (i = 1; i < tree->nlevel; i++, curr++) {
670 0 : cache = policy_cache_set(curr->cert);
671 0 : if (!tree_link_nodes(curr, cache))
672 : return 0;
673 :
674 0 : if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
675 0 : && !tree_link_any(curr, cache, tree))
676 : return 0;
677 : tree_print("before tree_prune()", tree, curr);
678 0 : ret = tree_prune(tree, curr);
679 0 : if (ret != 1)
680 : return ret;
681 : }
682 :
683 : return 1;
684 :
685 : }
686 :
687 0 : static void exnode_free(X509_POLICY_NODE *node)
688 : {
689 0 : if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE))
690 0 : OPENSSL_free(node);
691 0 : }
692 :
693 0 : void X509_policy_tree_free(X509_POLICY_TREE *tree)
694 : {
695 : X509_POLICY_LEVEL *curr;
696 : int i;
697 :
698 0 : if (!tree)
699 0 : return;
700 :
701 0 : sk_X509_POLICY_NODE_free(tree->auth_policies);
702 0 : sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free);
703 :
704 0 : for (i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) {
705 0 : if (curr->cert)
706 0 : X509_free(curr->cert);
707 0 : if (curr->nodes)
708 0 : sk_X509_POLICY_NODE_pop_free(curr->nodes, policy_node_free);
709 0 : if (curr->anyPolicy)
710 0 : policy_node_free(curr->anyPolicy);
711 : }
712 :
713 0 : if (tree->extra_data)
714 0 : sk_X509_POLICY_DATA_pop_free(tree->extra_data, policy_data_free);
715 :
716 0 : OPENSSL_free(tree->levels);
717 0 : OPENSSL_free(tree);
718 :
719 : }
720 :
721 : /*-
722 : * Application policy checking function.
723 : * Return codes:
724 : * 0 Internal Error.
725 : * 1 Successful.
726 : * -1 One or more certificates contain invalid or inconsistent extensions
727 : * -2 User constrained policy set empty and requireExplicit true.
728 : */
729 :
730 0 : int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
731 : STACK_OF(X509) *certs,
732 : STACK_OF(ASN1_OBJECT) *policy_oids, unsigned int flags)
733 : {
734 : int ret;
735 0 : X509_POLICY_TREE *tree = NULL;
736 0 : STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL;
737 0 : *ptree = NULL;
738 :
739 0 : *pexplicit_policy = 0;
740 0 : ret = tree_init(&tree, certs, flags);
741 :
742 0 : switch (ret) {
743 :
744 : /* Tree empty requireExplicit False: OK */
745 : case 2:
746 : return 1;
747 :
748 : /* Some internal error */
749 : case -1:
750 0 : return -1;
751 :
752 : /* Some internal error */
753 : case 0:
754 0 : return 0;
755 :
756 : /* Tree empty requireExplicit True: Error */
757 :
758 : case 6:
759 0 : *pexplicit_policy = 1;
760 0 : return -2;
761 :
762 : /* Tree OK requireExplicit True: OK and continue */
763 : case 5:
764 0 : *pexplicit_policy = 1;
765 0 : break;
766 :
767 : /* Tree OK: continue */
768 :
769 : case 1:
770 0 : if (!tree)
771 : /*
772 : * tree_init() returns success and a null tree
773 : * if it's just looking at a trust anchor.
774 : * I'm not sure that returning success here is
775 : * correct, but I'm sure that reporting this
776 : * as an internal error which our caller
777 : * interprets as a malloc failure is wrong.
778 : */
779 : return 1;
780 : break;
781 : }
782 :
783 0 : if (!tree)
784 : goto error;
785 0 : ret = tree_evaluate(tree);
786 :
787 : tree_print("tree_evaluate()", tree, NULL);
788 :
789 0 : if (ret <= 0)
790 : goto error;
791 :
792 : /* Return value 2 means tree empty */
793 0 : if (ret == 2) {
794 0 : X509_policy_tree_free(tree);
795 0 : if (*pexplicit_policy)
796 : return -2;
797 : else
798 0 : return 1;
799 : }
800 :
801 : /* Tree is not empty: continue */
802 :
803 0 : ret = tree_calculate_authority_set(tree, &auth_nodes);
804 :
805 0 : if (!ret)
806 : goto error;
807 :
808 0 : if (!tree_calculate_user_set(tree, policy_oids, auth_nodes))
809 : goto error;
810 :
811 0 : if (ret == 2)
812 0 : sk_X509_POLICY_NODE_free(auth_nodes);
813 :
814 0 : if (tree)
815 0 : *ptree = tree;
816 :
817 0 : if (*pexplicit_policy) {
818 0 : nodes = X509_policy_tree_get0_user_policies(tree);
819 0 : if (sk_X509_POLICY_NODE_num(nodes) <= 0)
820 : return -2;
821 : }
822 :
823 : return 1;
824 :
825 : error:
826 :
827 0 : X509_policy_tree_free(tree);
828 :
829 0 : return 0;
830 :
831 : }
|