summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbeck <>2023-04-26 18:56:52 +0000
committerbeck <>2023-04-26 18:56:52 +0000
commit5d33a39634fbeff69c05d501973a5ade98d9759b (patch)
tree3ec50699739f85815763e8998406870d94386a23 /src
parent563a58f0e6fc039507a215038ba3eab4873d0c9f (diff)
downloadopenbsd-5d33a39634fbeff69c05d501973a5ade98d9759b.tar.gz
openbsd-5d33a39634fbeff69c05d501973a5ade98d9759b.tar.bz2
openbsd-5d33a39634fbeff69c05d501973a5ade98d9759b.zip
Import policy.c from BoringSSL as x509_policy.c
This is an implementation of the X509 policy processing using a DAG instead of a tree to avoid the problem of exponential expansion of the policy tree as specified in RFC 5280 For details see: https://boringssl-review.googlesource.com/c/boringssl/+/55762 ok tb@ jsing@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/x509/x509_policy.c790
1 files changed, 790 insertions, 0 deletions
diff --git a/src/lib/libcrypto/x509/x509_policy.c b/src/lib/libcrypto/x509/x509_policy.c
new file mode 100644
index 0000000000..b0c27126c4
--- /dev/null
+++ b/src/lib/libcrypto/x509/x509_policy.c
@@ -0,0 +1,790 @@
1/* Copyright (c) 2022, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <openssl/x509.h>
16
17#include <assert.h>
18
19#include <openssl/mem.h>
20#include <openssl/obj.h>
21#include <openssl/stack.h>
22#include <openssl/x509v3.h>
23
24#include "../internal.h"
25#include "../x509v3/internal.h"
26#include "internal.h"
27
28
29// This file computes the X.509 policy tree, as described in RFC 5280, section
30// 6.1. It differs in that:
31//
32// (1) It does not track "qualifier_set". This is not needed as it is not
33// output by this implementation.
34//
35// (2) It builds a directed acyclic graph, rather than a tree. When a given
36// policy matches multiple parents, RFC 5280 makes a separate node for
37// each parent. This representation condenses them into one node with
38// multiple parents. Thus we refer to this structure as a "policy graph",
39// rather than a "policy tree".
40//
41// (3) "expected_policy_set" is not tracked explicitly and built temporarily
42// as part of building the graph.
43//
44// (4) anyPolicy nodes are not tracked explicitly.
45//
46// (5) Some pruning steps are deferred to when policies are evaluated, as a
47// reachability pass.
48
49// An X509_POLICY_NODE is a node in the policy graph. It corresponds to a node
50// from RFC 5280, section 6.1.2, step (a), but we store some fields differently.
51typedef struct x509_policy_node_st {
52 // policy is the "valid_policy" field from RFC 5280.
53 ASN1_OBJECT *policy;
54
55 // parent_policies, if non-empty, is the list of "valid_policy" values for all
56 // nodes which are a parent of this node. In this case, no entry in this list
57 // will be anyPolicy. This list is in no particular order and may contain
58 // duplicates if the corresponding certificate had duplicate mappings.
59 //
60 // If empty, this node has a single parent, anyPolicy. The node is then a root
61 // policies, and is in authorities-constrained-policy-set if it has a path to
62 // a leaf node.
63 //
64 // Note it is not possible for a policy to have both anyPolicy and a
65 // concrete policy as a parent. Section 6.1.3, step (d.1.ii) only runs if
66 // there was no match in step (d.1.i). We do not need to represent a parent
67 // list of, say, {anyPolicy, OID1, OID2}.
68 STACK_OF(ASN1_OBJECT) *parent_policies;
69
70 // mapped is one if this node matches a policy mapping in the certificate and
71 // zero otherwise.
72 int mapped;
73
74 // reachable is one if this node is reachable from some valid policy in the
75 // end-entity certificate. It is computed during |has_explicit_policy|.
76 int reachable;
77} X509_POLICY_NODE;
78
79DEFINE_STACK_OF(X509_POLICY_NODE)
80
81// An X509_POLICY_LEVEL is the collection of nodes at the same depth in the
82// policy graph. This structure can also be used to represent a level's
83// "expected_policy_set" values. See |process_policy_mappings|.
84typedef struct x509_policy_level_st {
85 // nodes is the list of nodes at this depth, except for the anyPolicy node, if
86 // any. This list is sorted by policy OID for efficient lookup.
87 STACK_OF(X509_POLICY_NODE) *nodes;
88
89 // has_any_policy is one if there is an anyPolicy node at this depth, and zero
90 // otherwise.
91 int has_any_policy;
92} X509_POLICY_LEVEL;
93
94DEFINE_STACK_OF(X509_POLICY_LEVEL)
95
96static int is_any_policy(const ASN1_OBJECT *obj) {
97 return OBJ_obj2nid(obj) == NID_any_policy;
98}
99
100static void x509_policy_node_free(X509_POLICY_NODE *node) {
101 if (node != NULL) {
102 ASN1_OBJECT_free(node->policy);
103 sk_ASN1_OBJECT_pop_free(node->parent_policies, ASN1_OBJECT_free);
104 OPENSSL_free(node);
105 }
106}
107
108static X509_POLICY_NODE *x509_policy_node_new(const ASN1_OBJECT *policy) {
109 assert(!is_any_policy(policy));
110 X509_POLICY_NODE *node = OPENSSL_malloc(sizeof(X509_POLICY_NODE));
111 if (node == NULL) {
112 return NULL;
113 }
114 OPENSSL_memset(node, 0, sizeof(X509_POLICY_NODE));
115 node->policy = OBJ_dup(policy);
116 node->parent_policies = sk_ASN1_OBJECT_new_null();
117 if (node->policy == NULL || node->parent_policies == NULL) {
118 x509_policy_node_free(node);
119 return NULL;
120 }
121 return node;
122}
123
124static int x509_policy_node_cmp(const X509_POLICY_NODE *const *a,
125 const X509_POLICY_NODE *const *b) {
126 return OBJ_cmp((*a)->policy, (*b)->policy);
127}
128
129static void x509_policy_level_free(X509_POLICY_LEVEL *level) {
130 if (level != NULL) {
131 sk_X509_POLICY_NODE_pop_free(level->nodes, x509_policy_node_free);
132 OPENSSL_free(level);
133 }
134}
135
136static X509_POLICY_LEVEL *x509_policy_level_new(void) {
137 X509_POLICY_LEVEL *level = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL));
138 if (level == NULL) {
139 return NULL;
140 }
141 OPENSSL_memset(level, 0, sizeof(X509_POLICY_LEVEL));
142 level->nodes = sk_X509_POLICY_NODE_new(x509_policy_node_cmp);
143 if (level->nodes == NULL) {
144 x509_policy_level_free(level);
145 return NULL;
146 }
147 return level;
148}
149
150static int x509_policy_level_is_empty(const X509_POLICY_LEVEL *level) {
151 return !level->has_any_policy && sk_X509_POLICY_NODE_num(level->nodes) == 0;
152}
153
154static void x509_policy_level_clear(X509_POLICY_LEVEL *level) {
155 level->has_any_policy = 0;
156 for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
157 x509_policy_node_free(sk_X509_POLICY_NODE_value(level->nodes, i));
158 }
159 sk_X509_POLICY_NODE_zero(level->nodes);
160}
161
162// x509_policy_level_find returns the node in |level| corresponding to |policy|,
163// or NULL if none exists.
164static X509_POLICY_NODE *x509_policy_level_find(X509_POLICY_LEVEL *level,
165 const ASN1_OBJECT *policy) {
166 assert(sk_X509_POLICY_NODE_is_sorted(level->nodes));
167 X509_POLICY_NODE node;
168 node.policy = (ASN1_OBJECT *)policy;
169 size_t idx;
170 if (!sk_X509_POLICY_NODE_find(level->nodes, &idx, &node)) {
171 return NULL;
172 }
173 return sk_X509_POLICY_NODE_value(level->nodes, idx);
174}
175
176// x509_policy_level_add_nodes adds the nodes in |nodes| to |level|. It returns
177// one on success and zero on error. No policy in |nodes| may already be present
178// in |level|. This function modifies |nodes| to avoid making a copy, but the
179// caller is still responsible for releasing |nodes| itself.
180//
181// This function is used to add nodes to |level| in bulk, and avoid resorting
182// |level| after each addition.
183static int x509_policy_level_add_nodes(X509_POLICY_LEVEL *level,
184 STACK_OF(X509_POLICY_NODE) *nodes) {
185 for (size_t i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) {
186 X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(nodes, i);
187 if (!sk_X509_POLICY_NODE_push(level->nodes, node)) {
188 return 0;
189 }
190 sk_X509_POLICY_NODE_set(nodes, i, NULL);
191 }
192 sk_X509_POLICY_NODE_sort(level->nodes);
193
194#if !defined(NDEBUG)
195 // There should be no duplicate nodes.
196 for (size_t i = 1; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
197 assert(OBJ_cmp(sk_X509_POLICY_NODE_value(level->nodes, i - 1)->policy,
198 sk_X509_POLICY_NODE_value(level->nodes, i)->policy) != 0);
199 }
200#endif
201 return 1;
202}
203
204static int policyinfo_cmp(const POLICYINFO *const *a,
205 const POLICYINFO *const *b) {
206 return OBJ_cmp((*a)->policyid, (*b)->policyid);
207}
208
209static int delete_if_not_in_policies(X509_POLICY_NODE *node, void *data) {
210 const CERTIFICATEPOLICIES *policies = data;
211 assert(sk_POLICYINFO_is_sorted(policies));
212 POLICYINFO info;
213 info.policyid = node->policy;
214 if (sk_POLICYINFO_find(policies, NULL, &info)) {
215 return 0;
216 }
217 x509_policy_node_free(node);
218 return 1;
219}
220
221// process_certificate_policies updates |level| to incorporate |x509|'s
222// certificate policies extension. This implements steps (d) and (e) of RFC
223// 5280, section 6.1.3. |level| must contain the previous level's
224// "expected_policy_set" information. For all but the top-most level, this is
225// the output of |process_policy_mappings|. |any_policy_allowed| specifies
226// whether anyPolicy is allowed or inhibited, taking into account the exception
227// for self-issued certificates.
228static int process_certificate_policies(const X509 *x509,
229 X509_POLICY_LEVEL *level,
230 int any_policy_allowed) {
231 int ret = 0;
232 int critical;
233 STACK_OF(X509_POLICY_NODE) *new_nodes = NULL;
234 CERTIFICATEPOLICIES *policies =
235 X509_get_ext_d2i(x509, NID_certificate_policies, &critical, NULL);
236 if (policies == NULL) {
237 if (critical != -1) {
238 return 0; // Syntax error in the extension.
239 }
240
241 // RFC 5280, section 6.1.3, step (e).
242 x509_policy_level_clear(level);
243 return 1;
244 }
245
246 // certificatePolicies may not be empty. See RFC 5280, section 4.2.1.4.
247 // TODO(https://crbug.com/boringssl/443): Move this check into the parser.
248 if (sk_POLICYINFO_num(policies) == 0) {
249 OPENSSL_PUT_ERROR(X509, X509_R_INVALID_POLICY_EXTENSION);
250 goto err;
251 }
252
253 sk_POLICYINFO_set_cmp_func(policies, policyinfo_cmp);
254 sk_POLICYINFO_sort(policies);
255 int cert_has_any_policy = 0;
256 for (size_t i = 0; i < sk_POLICYINFO_num(policies); i++) {
257 const POLICYINFO *policy = sk_POLICYINFO_value(policies, i);
258 if (is_any_policy(policy->policyid)) {
259 cert_has_any_policy = 1;
260 }
261 if (i > 0 && OBJ_cmp(sk_POLICYINFO_value(policies, i - 1)->policyid,
262 policy->policyid) == 0) {
263 // Per RFC 5280, section 4.2.1.4, |policies| may not have duplicates.
264 OPENSSL_PUT_ERROR(X509, X509_R_INVALID_POLICY_EXTENSION);
265 goto err;
266 }
267 }
268
269 // This does the same thing as RFC 5280, section 6.1.3, step (d), though in
270 // a slighty different order. |level| currently contains "expected_policy_set"
271 // values of the previous level. See |process_policy_mappings| for details.
272 const int previous_level_has_any_policy = level->has_any_policy;
273
274 // First, we handle steps (d.1.i) and (d.2). The net effect of these two steps
275 // is to intersect |level| with |policies|, ignoring anyPolicy if it is
276 // inhibited.
277 if (!cert_has_any_policy || !any_policy_allowed) {
278 sk_X509_POLICY_NODE_delete_if(level->nodes, delete_if_not_in_policies,
279 policies);
280 level->has_any_policy = 0;
281 }
282
283 // Step (d.1.ii) may attach new nodes to the previous level's anyPolicy node.
284 if (previous_level_has_any_policy) {
285 new_nodes = sk_X509_POLICY_NODE_new_null();
286 if (new_nodes == NULL) {
287 goto err;
288 }
289 for (size_t i = 0; i < sk_POLICYINFO_num(policies); i++) {
290 const POLICYINFO *policy = sk_POLICYINFO_value(policies, i);
291 // Though we've reordered the steps slightly, |policy| is in |level| if
292 // and only if it would have been a match in step (d.1.ii).
293 if (!is_any_policy(policy->policyid) &&
294 x509_policy_level_find(level, policy->policyid) == NULL) {
295 X509_POLICY_NODE *node = x509_policy_node_new(policy->policyid);
296 if (node == NULL || //
297 !sk_X509_POLICY_NODE_push(new_nodes, node)) {
298 x509_policy_node_free(node);
299 goto err;
300 }
301 }
302 }
303 if (!x509_policy_level_add_nodes(level, new_nodes)) {
304 goto err;
305 }
306 }
307
308 ret = 1;
309
310err:
311 sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free);
312 CERTIFICATEPOLICIES_free(policies);
313 return ret;
314}
315
316static int compare_issuer_policy(const POLICY_MAPPING *const *a,
317 const POLICY_MAPPING *const *b) {
318 return OBJ_cmp((*a)->issuerDomainPolicy, (*b)->issuerDomainPolicy);
319}
320
321static int compare_subject_policy(const POLICY_MAPPING *const *a,
322 const POLICY_MAPPING *const *b) {
323 return OBJ_cmp((*a)->subjectDomainPolicy, (*b)->subjectDomainPolicy);
324}
325
326static int delete_if_mapped(X509_POLICY_NODE *node, void *data) {
327 const POLICY_MAPPINGS *mappings = data;
328 // |mappings| must have been sorted by |compare_issuer_policy|.
329 assert(sk_POLICY_MAPPING_is_sorted(mappings));
330 POLICY_MAPPING mapping;
331 mapping.issuerDomainPolicy = node->policy;
332 if (!sk_POLICY_MAPPING_find(mappings, /*out_index=*/NULL, &mapping)) {
333 return 0;
334 }
335 x509_policy_node_free(node);
336 return 1;
337}
338
339// process_policy_mappings processes the policy mappings extension of |cert|,
340// whose corresponding graph level is |level|. |mapping_allowed| specifies
341// whether policy mapping is inhibited at this point. On success, it returns an
342// |X509_POLICY_LEVEL| containing the "expected_policy_set" for |level|. On
343// error, it returns NULL. This implements steps (a) and (b) of RFC 5280,
344// section 6.1.4.
345//
346// We represent the "expected_policy_set" as an |X509_POLICY_LEVEL|.
347// |has_any_policy| indicates whether there is an anyPolicy node with
348// "expected_policy_set" of {anyPolicy}. If a node with policy oid P1 contains
349// P2 in its "expected_policy_set", the level will contain a node of policy P2
350// with P1 in |parent_policies|.
351//
352// This is equivalent to the |X509_POLICY_LEVEL| that would result if the next
353// certificats contained anyPolicy. |process_certificate_policies| will filter
354// this result down to compute the actual level.
355static X509_POLICY_LEVEL *process_policy_mappings(const X509 *cert,
356 X509_POLICY_LEVEL *level,
357 int mapping_allowed) {
358 int ok = 0;
359 STACK_OF(X509_POLICY_NODE) *new_nodes = NULL;
360 X509_POLICY_LEVEL *next = NULL;
361 int critical;
362 POLICY_MAPPINGS *mappings =
363 X509_get_ext_d2i(cert, NID_policy_mappings, &critical, NULL);
364 if (mappings == NULL && critical != -1) {
365 // Syntax error in the policy mappings extension.
366 goto err;
367 }
368
369 if (mappings != NULL) {
370 // PolicyMappings may not be empty. See RFC 5280, section 4.2.1.5.
371 // TODO(https://crbug.com/boringssl/443): Move this check into the parser.
372 if (sk_POLICY_MAPPING_num(mappings) == 0) {
373 OPENSSL_PUT_ERROR(X509, X509_R_INVALID_POLICY_EXTENSION);
374 goto err;
375 }
376
377 // RFC 5280, section 6.1.4, step (a).
378 for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
379 POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings, i);
380 if (is_any_policy(mapping->issuerDomainPolicy) ||
381 is_any_policy(mapping->subjectDomainPolicy)) {
382 goto err;
383 }
384 }
385
386 // Sort to group by issuerDomainPolicy.
387 sk_POLICY_MAPPING_set_cmp_func(mappings, compare_issuer_policy);
388 sk_POLICY_MAPPING_sort(mappings);
389
390 if (mapping_allowed) {
391 // Mark nodes as mapped, and add any nodes to |level| which may be needed
392 // as part of RFC 5280, section 6.1.4, step (b.1).
393 new_nodes = sk_X509_POLICY_NODE_new_null();
394 if (new_nodes == NULL) {
395 goto err;
396 }
397 const ASN1_OBJECT *last_policy = NULL;
398 for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
399 const POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings, i);
400 // There may be multiple mappings with the same |issuerDomainPolicy|.
401 if (last_policy != NULL &&
402 OBJ_cmp(mapping->issuerDomainPolicy, last_policy) == 0) {
403 continue;
404 }
405 last_policy = mapping->issuerDomainPolicy;
406
407 X509_POLICY_NODE *node =
408 x509_policy_level_find(level, mapping->issuerDomainPolicy);
409 if (node == NULL) {
410 if (!level->has_any_policy) {
411 continue;
412 }
413 node = x509_policy_node_new(mapping->issuerDomainPolicy);
414 if (node == NULL || //
415 !sk_X509_POLICY_NODE_push(new_nodes, node)) {
416 x509_policy_node_free(node);
417 goto err;
418 }
419 }
420 node->mapped = 1;
421 }
422 if (!x509_policy_level_add_nodes(level, new_nodes)) {
423 goto err;
424 }
425 } else {
426 // RFC 5280, section 6.1.4, step (b.2). If mapping is inhibited, delete
427 // all mapped nodes.
428 sk_X509_POLICY_NODE_delete_if(level->nodes, delete_if_mapped, mappings);
429 sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
430 mappings = NULL;
431 }
432 }
433
434 // If a node was not mapped, it retains the original "explicit_policy_set"
435 // value, itself. Add those to |mappings|.
436 if (mappings == NULL) {
437 mappings = sk_POLICY_MAPPING_new_null();
438 if (mappings == NULL) {
439 goto err;
440 }
441 }
442 for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
443 X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(level->nodes, i);
444 if (!node->mapped) {
445 POLICY_MAPPING *mapping = POLICY_MAPPING_new();
446 if (mapping == NULL) {
447 goto err;
448 }
449 mapping->issuerDomainPolicy = OBJ_dup(node->policy);
450 mapping->subjectDomainPolicy = OBJ_dup(node->policy);
451 if (mapping->issuerDomainPolicy == NULL ||
452 mapping->subjectDomainPolicy == NULL ||
453 !sk_POLICY_MAPPING_push(mappings, mapping)) {
454 POLICY_MAPPING_free(mapping);
455 goto err;
456 }
457 }
458 }
459
460 // Sort to group by subjectDomainPolicy.
461 sk_POLICY_MAPPING_set_cmp_func(mappings, compare_subject_policy);
462 sk_POLICY_MAPPING_sort(mappings);
463
464 // Convert |mappings| to our "expected_policy_set" representation.
465 next = x509_policy_level_new();
466 if (next == NULL) {
467 goto err;
468 }
469 next->has_any_policy = level->has_any_policy;
470
471 X509_POLICY_NODE *last_node = NULL;
472 for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
473 POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings, i);
474 // Skip mappings where |issuerDomainPolicy| does not appear in the graph.
475 if (!level->has_any_policy &&
476 x509_policy_level_find(level, mapping->issuerDomainPolicy) == NULL) {
477 continue;
478 }
479
480 if (last_node == NULL ||
481 OBJ_cmp(last_node->policy, mapping->subjectDomainPolicy) != 0) {
482 last_node = x509_policy_node_new(mapping->subjectDomainPolicy);
483 if (last_node == NULL ||
484 !sk_X509_POLICY_NODE_push(next->nodes, last_node)) {
485 x509_policy_node_free(last_node);
486 goto err;
487 }
488 }
489
490 if (!sk_ASN1_OBJECT_push(last_node->parent_policies,
491 mapping->issuerDomainPolicy)) {
492 goto err;
493 }
494 mapping->issuerDomainPolicy = NULL;
495 }
496
497 sk_X509_POLICY_NODE_sort(next->nodes);
498 ok = 1;
499
500err:
501 if (!ok) {
502 x509_policy_level_free(next);
503 next = NULL;
504 }
505
506 sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
507 sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free);
508 return next;
509}
510
511// apply_skip_certs, if |skip_certs| is non-NULL, sets |*value| to the minimum
512// of its current value and |skip_certs|. It returns one on success and zero if
513// |skip_certs| is negative.
514static int apply_skip_certs(const ASN1_INTEGER *skip_certs, size_t *value) {
515 if (skip_certs == NULL) {
516 return 1;
517 }
518
519 // TODO(https://crbug.com/boringssl/443): Move this check into the parser.
520 if (skip_certs->type & V_ASN1_NEG) {
521 OPENSSL_PUT_ERROR(X509, X509_R_INVALID_POLICY_EXTENSION);
522 return 0;
523 }
524
525 // If |skip_certs| does not fit in |uint64_t|, it must exceed |*value|.
526 uint64_t u64;
527 if (ASN1_INTEGER_get_uint64(&u64, skip_certs) && u64 < *value) {
528 *value = (size_t)u64;
529 }
530 ERR_clear_error();
531 return 1;
532}
533
534// process_policy_constraints updates |*explicit_policy|, |*policy_mapping|, and
535// |*inhibit_any_policy| according to |x509|'s policy constraints and inhibit
536// anyPolicy extensions. It returns one on success and zero on error. This
537// implements steps (i) and (j) of RFC 5280, section 6.1.4.
538static int process_policy_constraints(const X509 *x509, size_t *explicit_policy,
539 size_t *policy_mapping,
540 size_t *inhibit_any_policy) {
541 int critical;
542 POLICY_CONSTRAINTS *constraints =
543 X509_get_ext_d2i(x509, NID_policy_constraints, &critical, NULL);
544 if (constraints == NULL && critical != -1) {
545 return 0;
546 }
547 if (constraints != NULL) {
548 if (constraints->requireExplicitPolicy == NULL &&
549 constraints->inhibitPolicyMapping == NULL) {
550 // Per RFC 5280, section 4.2.1.11, at least one of the fields must be
551 // present.
552 OPENSSL_PUT_ERROR(X509, X509_R_INVALID_POLICY_EXTENSION);
553 POLICY_CONSTRAINTS_free(constraints);
554 return 0;
555 }
556 int ok =
557 apply_skip_certs(constraints->requireExplicitPolicy, explicit_policy) &&
558 apply_skip_certs(constraints->inhibitPolicyMapping, policy_mapping);
559 POLICY_CONSTRAINTS_free(constraints);
560 if (!ok) {
561 return 0;
562 }
563 }
564
565 ASN1_INTEGER *inhibit_any_policy_ext =
566 X509_get_ext_d2i(x509, NID_inhibit_any_policy, &critical, NULL);
567 if (inhibit_any_policy_ext == NULL && critical != -1) {
568 return 0;
569 }
570 int ok = apply_skip_certs(inhibit_any_policy_ext, inhibit_any_policy);
571 ASN1_INTEGER_free(inhibit_any_policy_ext);
572 return ok;
573}
574
575// has_explicit_policy returns one if the set of authority-space policy OIDs
576// |levels| has some non-empty intersection with |user_policies|, and zero
577// otherwise. This mirrors the logic in RFC 5280, section 6.1.5, step (g). This
578// function modifies |levels| and should only be called at the end of policy
579// evaluation.
580static int has_explicit_policy(STACK_OF(X509_POLICY_LEVEL) *levels,
581 const STACK_OF(ASN1_OBJECT) *user_policies) {
582 assert(user_policies == NULL || sk_ASN1_OBJECT_is_sorted(user_policies));
583
584 // Step (g.i). If the policy graph is empty, the intersection is empty.
585 size_t num_levels = sk_X509_POLICY_LEVEL_num(levels);
586 X509_POLICY_LEVEL *level = sk_X509_POLICY_LEVEL_value(levels, num_levels - 1);
587 if (x509_policy_level_is_empty(level)) {
588 return 0;
589 }
590
591 // If |user_policies| is empty, we interpret it as having a single anyPolicy
592 // value. The caller may also have supplied anyPolicy explicitly.
593 int user_has_any_policy = sk_ASN1_OBJECT_num(user_policies) == 0;
594 for (size_t i = 0; i < sk_ASN1_OBJECT_num(user_policies); i++) {
595 if (is_any_policy(sk_ASN1_OBJECT_value(user_policies, i))) {
596 user_has_any_policy = 1;
597 break;
598 }
599 }
600
601 // Step (g.ii). If the policy graph is not empty and the user set contains
602 // anyPolicy, the intersection is the entire (non-empty) graph.
603 if (user_has_any_policy) {
604 return 1;
605 }
606
607 // Step (g.iii) does not delete anyPolicy nodes, so if the graph has
608 // anyPolicy, some explicit policy will survive. The actual intersection may
609 // synthesize some nodes in step (g.iii.3), but we do not return the policy
610 // list itself, so we skip actually computing this.
611 if (level->has_any_policy) {
612 return 1;
613 }
614
615 // We defer pruning the tree, so as we look for nodes with parent anyPolicy,
616 // step (g.iii.1), we must limit to nodes reachable from the bottommost level.
617 // Start by marking each of those nodes as reachable.
618 for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
619 sk_X509_POLICY_NODE_value(level->nodes, i)->reachable = 1;
620 }
621
622 for (size_t i = num_levels - 1; i < num_levels; i--) {
623 level = sk_X509_POLICY_LEVEL_value(levels, i);
624 for (size_t j = 0; j < sk_X509_POLICY_NODE_num(level->nodes); j++) {
625 X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(level->nodes, j);
626 if (!node->reachable) {
627 continue;
628 }
629 if (sk_ASN1_OBJECT_num(node->parent_policies) == 0) {
630 // |node|'s parent is anyPolicy and is part of "valid_policy_node_set".
631 // If it exists in |user_policies|, the intersection is non-empty and we
632 // can return immediately.
633 if (sk_ASN1_OBJECT_find(user_policies, /*out_index=*/NULL,
634 node->policy)) {
635 return 1;
636 }
637 } else if (i > 0) {
638 // |node|'s parents are concrete policies. Mark the parents reachable,
639 // to be inspected by the next loop iteration.
640 X509_POLICY_LEVEL *prev = sk_X509_POLICY_LEVEL_value(levels, i - 1);
641 for (size_t k = 0; k < sk_ASN1_OBJECT_num(node->parent_policies); k++) {
642 X509_POLICY_NODE *parent = x509_policy_level_find(
643 prev, sk_ASN1_OBJECT_value(node->parent_policies, k));
644 if (parent != NULL) {
645 parent->reachable = 1;
646 }
647 }
648 }
649 }
650 }
651
652 return 0;
653}
654
655static int asn1_object_cmp(const ASN1_OBJECT *const *a,
656 const ASN1_OBJECT *const *b) {
657 return OBJ_cmp(*a, *b);
658}
659
660int X509_policy_check(const STACK_OF(X509) *certs,
661 const STACK_OF(ASN1_OBJECT) *user_policies,
662 unsigned long flags, X509 **out_current_cert) {
663 *out_current_cert = NULL;
664 int ret = X509_V_ERR_OUT_OF_MEM;
665 X509_POLICY_LEVEL *level = NULL;
666 STACK_OF(X509_POLICY_LEVEL) *levels = NULL;
667 STACK_OF(ASN1_OBJECT) *user_policies_sorted = NULL;
668 size_t num_certs = sk_X509_num(certs);
669
670 // Skip policy checking if the chain is just the trust anchor.
671 if (num_certs <= 1) {
672 return X509_V_OK;
673 }
674
675 // See RFC 5280, section 6.1.2, steps (d) through (f).
676 size_t explicit_policy =
677 (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : num_certs + 1;
678 size_t inhibit_any_policy =
679 (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : num_certs + 1;
680 size_t policy_mapping =
681 (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : num_certs + 1;
682
683 levels = sk_X509_POLICY_LEVEL_new_null();
684 if (levels == NULL) {
685 goto err;
686 }
687
688 for (size_t i = num_certs - 2; i < num_certs; i--) {
689 X509 *cert = sk_X509_value(certs, i);
690 if (!x509v3_cache_extensions(cert)) {
691 goto err;
692 }
693 const int is_self_issued = (cert->ex_flags & EXFLAG_SI) != 0;
694
695 if (level == NULL) {
696 assert(i == num_certs - 2);
697 level = x509_policy_level_new();
698 if (level == NULL) {
699 goto err;
700 }
701 level->has_any_policy = 1;
702 }
703
704 // RFC 5280, section 6.1.3, steps (d) and (e). |any_policy_allowed| is
705 // computed as in step (d.2).
706 const int any_policy_allowed =
707 inhibit_any_policy > 0 || (i > 0 && is_self_issued);
708 if (!process_certificate_policies(cert, level, any_policy_allowed)) {
709 ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
710 *out_current_cert = cert;
711 goto err;
712 }
713
714 // RFC 5280, section 6.1.3, step (f).
715 if (explicit_policy == 0 && x509_policy_level_is_empty(level)) {
716 ret = X509_V_ERR_NO_EXPLICIT_POLICY;
717 goto err;
718 }
719
720 // Insert into the list.
721 if (!sk_X509_POLICY_LEVEL_push(levels, level)) {
722 goto err;
723 }
724 X509_POLICY_LEVEL *current_level = level;
725 level = NULL;
726
727 // If this is not the leaf certificate, we go to section 6.1.4. If it
728 // is the leaf certificate, we go to section 6.1.5 instead.
729 if (i != 0) {
730 // RFC 5280, section 6.1.4, steps (a) and (b).
731 level = process_policy_mappings(cert, current_level, policy_mapping > 0);
732 if (level == NULL) {
733 ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
734 *out_current_cert = cert;
735 goto err;
736 }
737 }
738
739 // RFC 5280, section 6.1.4, step (h-j) for non-leaves, and section 6.1.5,
740 // step (a-b) for leaves. In the leaf case, RFC 5280 says only to update
741 // |explicit_policy|, but |policy_mapping| and |inhibit_any_policy| are no
742 // longer read at this point, so we use the same process.
743 if (i == 0 || !is_self_issued) {
744 if (explicit_policy > 0) {
745 explicit_policy--;
746 }
747 if (policy_mapping > 0) {
748 policy_mapping--;
749 }
750 if (inhibit_any_policy > 0) {
751 inhibit_any_policy--;
752 }
753 }
754 if (!process_policy_constraints(cert, &explicit_policy, &policy_mapping,
755 &inhibit_any_policy)) {
756 ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
757 *out_current_cert = cert;
758 goto err;
759 }
760 }
761
762 // RFC 5280, section 6.1.5, step (g). We do not output the policy set, so it
763 // is only necessary to check if the user-constrained-policy-set is not empty.
764 if (explicit_policy == 0) {
765 // Build a sorted copy of |user_policies| for more efficient lookup.
766 if (user_policies != NULL) {
767 user_policies_sorted = sk_ASN1_OBJECT_dup(user_policies);
768 if (user_policies_sorted == NULL) {
769 goto err;
770 }
771 sk_ASN1_OBJECT_set_cmp_func(user_policies_sorted, asn1_object_cmp);
772 sk_ASN1_OBJECT_sort(user_policies_sorted);
773 }
774
775 if (!has_explicit_policy(levels, user_policies_sorted)) {
776 ret = X509_V_ERR_NO_EXPLICIT_POLICY;
777 goto err;
778 }
779 }
780
781 ret = X509_V_OK;
782
783err:
784 x509_policy_level_free(level);
785 // |user_policies_sorted|'s contents are owned by |user_policies|, so we do
786 // not use |sk_ASN1_OBJECT_pop_free|.
787 sk_ASN1_OBJECT_free(user_policies_sorted);
788 sk_X509_POLICY_LEVEL_pop_free(levels, x509_policy_level_free);
789 return ret;
790}