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