-/* $OpenBSD: x509_policy.c,v 1.9 2023/04/26 20:52:11 tb Exp $ */
+/* $OpenBSD: x509_policy.c,v 1.10 2023/04/26 21:07:32 tb Exp $ */
/* Copyright (c) 2022, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
// from RFC 5280, section 6.1.2, step (a), but we store some fields differently.
typedef struct x509_policy_node_st {
// policy is the "valid_policy" field from RFC 5280.
- ASN1_OBJECT *policy;
+ ASN1_OBJECT *policy;
// parent_policies, if non-empty, is the list of "valid_policy" values for all
// nodes which are a parent of this node. In this case, no entry in this list
// concrete policy as a parent. Section 6.1.3, step (d.1.ii) only runs if
// there was no match in step (d.1.i). We do not need to represent a parent
// list of, say, {anyPolicy, OID1, OID2}.
- STACK_OF(ASN1_OBJECT) *parent_policies;
+ STACK_OF(ASN1_OBJECT) *parent_policies;
// mapped is one if this node matches a policy mapping in the certificate and
// zero otherwise.
- int mapped;
+ int mapped;
// reachable is one if this node is reachable from some valid policy in the
// end-entity certificate. It is computed during |has_explicit_policy|.
- int reachable;
+ int reachable;
} X509_POLICY_NODE;
DECLARE_STACK_OF(X509_POLICY_NODE)
typedef struct x509_policy_level_st {
// nodes is the list of nodes at this depth, except for the anyPolicy node, if
// any. This list is sorted by policy OID for efficient lookup.
- STACK_OF(X509_POLICY_NODE) *nodes;
+ STACK_OF(X509_POLICY_NODE) *nodes;
// has_any_policy is one if there is an anyPolicy node at this depth, and zero
// otherwise.
- int has_any_policy;
+ int has_any_policy;
} X509_POLICY_LEVEL;
DECLARE_STACK_OF(X509_POLICY_LEVEL)
sk->num = new_num;
}
-static int is_any_policy(const ASN1_OBJECT *obj) {
- return OBJ_obj2nid(obj) == NID_any_policy;
+static int
+is_any_policy(const ASN1_OBJECT *obj)
+{
+ return OBJ_obj2nid(obj) == NID_any_policy;
}
-static void x509_policy_node_free(X509_POLICY_NODE *node) {
- if (node != NULL) {
- ASN1_OBJECT_free(node->policy);
- sk_ASN1_OBJECT_pop_free(node->parent_policies, ASN1_OBJECT_free);
- free(node);
- }
+static void
+x509_policy_node_free(X509_POLICY_NODE *node)
+{
+ if (node != NULL) {
+ ASN1_OBJECT_free(node->policy);
+ sk_ASN1_OBJECT_pop_free(node->parent_policies,
+ ASN1_OBJECT_free);
+ free(node);
+ }
}
-static X509_POLICY_NODE *x509_policy_node_new(const ASN1_OBJECT *policy) {
- assert(!is_any_policy(policy));
- X509_POLICY_NODE *node = malloc(sizeof(X509_POLICY_NODE));
- if (node == NULL) {
- return NULL;
- }
- memset(node, 0, sizeof(X509_POLICY_NODE));
- node->policy = OBJ_dup(policy);
- node->parent_policies = sk_ASN1_OBJECT_new_null();
- if (node->policy == NULL || node->parent_policies == NULL) {
- x509_policy_node_free(node);
- return NULL;
- }
- return node;
+static X509_POLICY_NODE *
+x509_policy_node_new(const ASN1_OBJECT *policy)
+{
+ assert(!is_any_policy(policy));
+ X509_POLICY_NODE *node = malloc(sizeof(X509_POLICY_NODE));
+ if (node == NULL) {
+ return NULL;
+ }
+ memset(node, 0, sizeof(X509_POLICY_NODE));
+ node->policy = OBJ_dup(policy);
+ node->parent_policies = sk_ASN1_OBJECT_new_null();
+ if (node->policy == NULL || node->parent_policies == NULL) {
+ x509_policy_node_free(node);
+ return NULL;
+ }
+ return node;
}
-static int x509_policy_node_cmp(const X509_POLICY_NODE *const *a,
- const X509_POLICY_NODE *const *b) {
- return OBJ_cmp((*a)->policy, (*b)->policy);
+static int
+x509_policy_node_cmp(const X509_POLICY_NODE *const *a,
+ const X509_POLICY_NODE *const *b)
+{
+ return OBJ_cmp((*a)->policy, (*b)->policy);
}
-static void x509_policy_level_free(X509_POLICY_LEVEL *level) {
- if (level != NULL) {
- sk_X509_POLICY_NODE_pop_free(level->nodes, x509_policy_node_free);
- free(level);
- }
+static void
+x509_policy_level_free(X509_POLICY_LEVEL *level)
+{
+ if (level != NULL) {
+ sk_X509_POLICY_NODE_pop_free(level->nodes,
+ x509_policy_node_free);
+ free(level);
+ }
}
-static X509_POLICY_LEVEL *x509_policy_level_new(void) {
- X509_POLICY_LEVEL *level = malloc(sizeof(X509_POLICY_LEVEL));
- if (level == NULL) {
- return NULL;
- }
- memset(level, 0, sizeof(X509_POLICY_LEVEL));
- level->nodes = sk_X509_POLICY_NODE_new(x509_policy_node_cmp);
- if (level->nodes == NULL) {
- x509_policy_level_free(level);
- return NULL;
- }
- return level;
+static X509_POLICY_LEVEL *
+x509_policy_level_new(void)
+{
+ X509_POLICY_LEVEL *level = malloc(sizeof(X509_POLICY_LEVEL));
+ if (level == NULL) {
+ return NULL;
+ }
+ memset(level, 0, sizeof(X509_POLICY_LEVEL));
+ level->nodes = sk_X509_POLICY_NODE_new(x509_policy_node_cmp);
+ if (level->nodes == NULL) {
+ x509_policy_level_free(level);
+ return NULL;
+ }
+ return level;
}
-static int x509_policy_level_is_empty(const X509_POLICY_LEVEL *level) {
- return !level->has_any_policy && sk_X509_POLICY_NODE_num(level->nodes) == 0;
+static int
+x509_policy_level_is_empty(const X509_POLICY_LEVEL *level)
+{
+ return !level->has_any_policy &&
+ sk_X509_POLICY_NODE_num(level->nodes) == 0;
}
-static void x509_policy_level_clear(X509_POLICY_LEVEL *level) {
- level->has_any_policy = 0;
- for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
- x509_policy_node_free(sk_X509_POLICY_NODE_value(level->nodes, i));
- }
- sk_X509_POLICY_NODE_zero(level->nodes);
+static void
+x509_policy_level_clear(X509_POLICY_LEVEL *level)
+{
+ level->has_any_policy = 0;
+ for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
+ x509_policy_node_free(
+ sk_X509_POLICY_NODE_value(level->nodes, i));
+ }
+ sk_X509_POLICY_NODE_zero(level->nodes);
}
// x509_policy_level_find returns the node in |level| corresponding to |policy|,
// or NULL if none exists.
-static X509_POLICY_NODE *x509_policy_level_find(X509_POLICY_LEVEL *level,
- const ASN1_OBJECT *policy) {
- assert(sk_X509_POLICY_NODE_is_sorted(level->nodes));
- X509_POLICY_NODE node;
- node.policy = (ASN1_OBJECT *)policy;
- int idx;
- if ((idx = sk_X509_POLICY_NODE_find(level->nodes, &node)) < 0) {
- return NULL;
- }
- return sk_X509_POLICY_NODE_value(level->nodes, idx);
+static X509_POLICY_NODE *
+x509_policy_level_find(X509_POLICY_LEVEL *level,
+ const ASN1_OBJECT *policy)
+{
+ assert(sk_X509_POLICY_NODE_is_sorted(level->nodes));
+ X509_POLICY_NODE node;
+ node.policy = (ASN1_OBJECT *)policy;
+ int idx;
+ if ((idx = sk_X509_POLICY_NODE_find(level->nodes, &node)) < 0) {
+ return NULL;
+ }
+ return sk_X509_POLICY_NODE_value(level->nodes, idx);
}
// x509_policy_level_add_nodes adds the nodes in |nodes| to |level|. It returns
//
// This function is used to add nodes to |level| in bulk, and avoid resorting
// |level| after each addition.
-static int x509_policy_level_add_nodes(X509_POLICY_LEVEL *level,
- STACK_OF(X509_POLICY_NODE) *nodes) {
- for (size_t i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) {
- X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(nodes, i);
- if (!sk_X509_POLICY_NODE_push(level->nodes, node)) {
- return 0;
- }
- sk_X509_POLICY_NODE_set(nodes, i, NULL);
- }
- sk_X509_POLICY_NODE_sort(level->nodes);
+static int
+x509_policy_level_add_nodes(X509_POLICY_LEVEL *level,
+ STACK_OF(X509_POLICY_NODE) *nodes)
+{
+ for (size_t i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) {
+ X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(nodes, i);
+ if (!sk_X509_POLICY_NODE_push(level->nodes, node)) {
+ return 0;
+ }
+ sk_X509_POLICY_NODE_set(nodes, i, NULL);
+ }
+ sk_X509_POLICY_NODE_sort(level->nodes);
#if !defined(NDEBUG)
// There should be no duplicate nodes.
- for (size_t i = 1; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
- assert(OBJ_cmp(sk_X509_POLICY_NODE_value(level->nodes, i - 1)->policy,
- sk_X509_POLICY_NODE_value(level->nodes, i)->policy) != 0);
- }
+ for (size_t i = 1; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
+ assert(
+ OBJ_cmp(
+ sk_X509_POLICY_NODE_value(level->nodes, i - 1)->policy,
+ sk_X509_POLICY_NODE_value(level->nodes, i)->policy) != 0);
+ }
#endif
- return 1;
+ return 1;
}
-static int policyinfo_cmp(const POLICYINFO *const *a,
- const POLICYINFO *const *b) {
- return OBJ_cmp((*a)->policyid, (*b)->policyid);
+static int
+policyinfo_cmp(const POLICYINFO *const *a,
+ const POLICYINFO *const *b)
+{
+ return OBJ_cmp((*a)->policyid, (*b)->policyid);
}
-static int delete_if_not_in_policies(X509_POLICY_NODE *node, void *data) {
- const CERTIFICATEPOLICIES *policies = data;
- assert(sk_POLICYINFO_is_sorted(policies));
- POLICYINFO info;
- info.policyid = node->policy;
- if (sk_POLICYINFO_find(policies, &info) >= 0) {
- return 0;
- }
- x509_policy_node_free(node);
- return 1;
+static int
+delete_if_not_in_policies(X509_POLICY_NODE *node, void *data)
+{
+ const CERTIFICATEPOLICIES *policies = data;
+ assert(sk_POLICYINFO_is_sorted(policies));
+ POLICYINFO info;
+ info.policyid = node->policy;
+ if (sk_POLICYINFO_find(policies, &info) >= 0) {
+ return 0;
+ }
+ x509_policy_node_free(node);
+ return 1;
}
// process_certificate_policies updates |level| to incorporate |x509|'s
// the output of |process_policy_mappings|. |any_policy_allowed| specifies
// whether anyPolicy is allowed or inhibited, taking into account the exception
// for self-issued certificates.
-static int process_certificate_policies(const X509 *x509,
- X509_POLICY_LEVEL *level,
- int any_policy_allowed) {
- int ret = 0;
- int critical;
- STACK_OF(X509_POLICY_NODE) *new_nodes = NULL;
- CERTIFICATEPOLICIES *policies =
- X509_get_ext_d2i(x509, NID_certificate_policies, &critical, NULL);
- if (policies == NULL) {
- if (critical != -1) {
- return 0; // Syntax error in the extension.
- }
+static int
+process_certificate_policies(const X509 *x509,
+ X509_POLICY_LEVEL *level,
+ int any_policy_allowed)
+{
+ int ret = 0;
+ int critical;
+ STACK_OF(X509_POLICY_NODE) *new_nodes = NULL;
+ CERTIFICATEPOLICIES *policies =
+ X509_get_ext_d2i(x509, NID_certificate_policies, &critical, NULL);
+ if (policies == NULL) {
+ if (critical != -1) {
+ return 0; // Syntax error in the extension.
+ }
// RFC 5280, section 6.1.3, step (e).
- x509_policy_level_clear(level);
- return 1;
- }
+ x509_policy_level_clear(level);
+ return 1;
+ }
// certificatePolicies may not be empty. See RFC 5280, section 4.2.1.4.
// TODO(https://crbug.com/boringssl/443): Move this check into the parser.
- if (sk_POLICYINFO_num(policies) == 0) {
- X509error(X509_R_INVALID_POLICY_EXTENSION);
- goto err;
- }
-
- sk_POLICYINFO_set_cmp_func(policies, policyinfo_cmp);
- sk_POLICYINFO_sort(policies);
- int cert_has_any_policy = 0;
- for (size_t i = 0; i < sk_POLICYINFO_num(policies); i++) {
- const POLICYINFO *policy = sk_POLICYINFO_value(policies, i);
- if (is_any_policy(policy->policyid)) {
- cert_has_any_policy = 1;
- }
- if (i > 0 && OBJ_cmp(sk_POLICYINFO_value(policies, i - 1)->policyid,
- policy->policyid) == 0) {
+ if (sk_POLICYINFO_num(policies) == 0) {
+ X509error(X509_R_INVALID_POLICY_EXTENSION);
+ goto err;
+ }
+
+ sk_POLICYINFO_set_cmp_func(policies, policyinfo_cmp);
+ sk_POLICYINFO_sort(policies);
+ int cert_has_any_policy = 0;
+ for (size_t i = 0; i < sk_POLICYINFO_num(policies); i++) {
+ const POLICYINFO *policy = sk_POLICYINFO_value(policies, i);
+ if (is_any_policy(policy->policyid)) {
+ cert_has_any_policy = 1;
+ }
+ if (i > 0 &&
+ OBJ_cmp(sk_POLICYINFO_value(policies, i - 1)->policyid,
+ policy->policyid) == 0) {
// Per RFC 5280, section 4.2.1.4, |policies| may not have duplicates.
- X509error(X509_R_INVALID_POLICY_EXTENSION);
- goto err;
- }
- }
+ X509error(X509_R_INVALID_POLICY_EXTENSION);
+ goto err;
+ }
+ }
// This does the same thing as RFC 5280, section 6.1.3, step (d), though in
// a slighty different order. |level| currently contains "expected_policy_set"
// values of the previous level. See |process_policy_mappings| for details.
- const int previous_level_has_any_policy = level->has_any_policy;
+ const int previous_level_has_any_policy = level->has_any_policy;
// First, we handle steps (d.1.i) and (d.2). The net effect of these two steps
// is to intersect |level| with |policies|, ignoring anyPolicy if it is
// inhibited.
- if (!cert_has_any_policy || !any_policy_allowed) {
- sk_X509_POLICY_NODE_delete_if(level->nodes, delete_if_not_in_policies,
- policies);
- level->has_any_policy = 0;
- }
+ if (!cert_has_any_policy || !any_policy_allowed) {
+ sk_X509_POLICY_NODE_delete_if(level->nodes,
+ delete_if_not_in_policies, policies);
+ level->has_any_policy = 0;
+ }
// Step (d.1.ii) may attach new nodes to the previous level's anyPolicy node.
- if (previous_level_has_any_policy) {
- new_nodes = sk_X509_POLICY_NODE_new_null();
- if (new_nodes == NULL) {
- goto err;
- }
- for (size_t i = 0; i < sk_POLICYINFO_num(policies); i++) {
- const POLICYINFO *policy = sk_POLICYINFO_value(policies, i);
+ if (previous_level_has_any_policy) {
+ new_nodes = sk_X509_POLICY_NODE_new_null();
+ if (new_nodes == NULL) {
+ goto err;
+ }
+ for (size_t i = 0; i < sk_POLICYINFO_num(policies); i++) {
+ const POLICYINFO *policy = sk_POLICYINFO_value(policies,
+ i);
// Though we've reordered the steps slightly, |policy| is in |level| if
// and only if it would have been a match in step (d.1.ii).
- if (!is_any_policy(policy->policyid) &&
- x509_policy_level_find(level, policy->policyid) == NULL) {
- X509_POLICY_NODE *node = x509_policy_node_new(policy->policyid);
- if (node == NULL || //
- !sk_X509_POLICY_NODE_push(new_nodes, node)) {
- x509_policy_node_free(node);
- goto err;
- }
- }
- }
- if (!x509_policy_level_add_nodes(level, new_nodes)) {
- goto err;
- }
- }
-
- ret = 1;
+ if (!is_any_policy(policy->policyid) &&
+ x509_policy_level_find(level, policy->policyid) ==
+ NULL) {
+ X509_POLICY_NODE *node = x509_policy_node_new(
+ policy->policyid);
+ if (node == NULL || //
+ !sk_X509_POLICY_NODE_push(new_nodes,
+ node)) {
+ x509_policy_node_free(node);
+ goto err;
+ }
+ }
+ }
+ if (!x509_policy_level_add_nodes(level, new_nodes)) {
+ goto err;
+ }
+ }
+
+ ret = 1;
err:
- sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free);
- CERTIFICATEPOLICIES_free(policies);
- return ret;
+ sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free);
+ CERTIFICATEPOLICIES_free(policies);
+ return ret;
}
-static int compare_issuer_policy(const POLICY_MAPPING *const *a,
- const POLICY_MAPPING *const *b) {
- return OBJ_cmp((*a)->issuerDomainPolicy, (*b)->issuerDomainPolicy);
+static int
+compare_issuer_policy(const POLICY_MAPPING *const *a,
+ const POLICY_MAPPING *const *b)
+{
+ return OBJ_cmp((*a)->issuerDomainPolicy, (*b)->issuerDomainPolicy);
}
-static int compare_subject_policy(const POLICY_MAPPING *const *a,
- const POLICY_MAPPING *const *b) {
- return OBJ_cmp((*a)->subjectDomainPolicy, (*b)->subjectDomainPolicy);
+static int
+compare_subject_policy(const POLICY_MAPPING *const *a,
+ const POLICY_MAPPING *const *b)
+{
+ return OBJ_cmp((*a)->subjectDomainPolicy, (*b)->subjectDomainPolicy);
}
-static int delete_if_mapped(X509_POLICY_NODE *node, void *data) {
- const POLICY_MAPPINGS *mappings = data;
+static int
+delete_if_mapped(X509_POLICY_NODE *node, void *data)
+{
+ const POLICY_MAPPINGS *mappings = data;
// |mappings| must have been sorted by |compare_issuer_policy|.
- assert(sk_POLICY_MAPPING_is_sorted(mappings));
- POLICY_MAPPING mapping;
- mapping.issuerDomainPolicy = node->policy;
- if (sk_POLICY_MAPPING_find(mappings, &mapping) < 0) {
- return 0;
- }
- x509_policy_node_free(node);
- return 1;
+ assert(sk_POLICY_MAPPING_is_sorted(mappings));
+ POLICY_MAPPING mapping;
+ mapping.issuerDomainPolicy = node->policy;
+ if (sk_POLICY_MAPPING_find(mappings, &mapping) < 0) {
+ return 0;
+ }
+ x509_policy_node_free(node);
+ return 1;
}
// process_policy_mappings processes the policy mappings extension of |cert|,
// This is equivalent to the |X509_POLICY_LEVEL| that would result if the next
// certificats contained anyPolicy. |process_certificate_policies| will filter
// this result down to compute the actual level.
-static X509_POLICY_LEVEL *process_policy_mappings(const X509 *cert,
- X509_POLICY_LEVEL *level,
- int mapping_allowed) {
- int ok = 0;
- STACK_OF(X509_POLICY_NODE) *new_nodes = NULL;
- X509_POLICY_LEVEL *next = NULL;
- int critical;
- POLICY_MAPPINGS *mappings =
- X509_get_ext_d2i(cert, NID_policy_mappings, &critical, NULL);
- if (mappings == NULL && critical != -1) {
+static X509_POLICY_LEVEL *
+process_policy_mappings(const X509 *cert,
+ X509_POLICY_LEVEL *level,
+ int mapping_allowed)
+{
+ int ok = 0;
+ STACK_OF(X509_POLICY_NODE) *new_nodes = NULL;
+ X509_POLICY_LEVEL *next = NULL;
+ int critical;
+ POLICY_MAPPINGS *mappings =
+ X509_get_ext_d2i(cert, NID_policy_mappings, &critical, NULL);
+ if (mappings == NULL && critical != -1) {
// Syntax error in the policy mappings extension.
- goto err;
- }
+ goto err;
+ }
- if (mappings != NULL) {
+ if (mappings != NULL) {
// PolicyMappings may not be empty. See RFC 5280, section 4.2.1.5.
// TODO(https://crbug.com/boringssl/443): Move this check into the parser.
- if (sk_POLICY_MAPPING_num(mappings) == 0) {
- X509error(X509_R_INVALID_POLICY_EXTENSION);
- goto err;
- }
+ if (sk_POLICY_MAPPING_num(mappings) == 0) {
+ X509error(X509_R_INVALID_POLICY_EXTENSION);
+ goto err;
+ }
// RFC 5280, section 6.1.4, step (a).
- for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
- POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings, i);
- if (is_any_policy(mapping->issuerDomainPolicy) ||
- is_any_policy(mapping->subjectDomainPolicy)) {
- goto err;
- }
- }
+ for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
+ POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings,
+ i);
+ if (is_any_policy(mapping->issuerDomainPolicy) ||
+ is_any_policy(mapping->subjectDomainPolicy)) {
+ goto err;
+ }
+ }
// Sort to group by issuerDomainPolicy.
- sk_POLICY_MAPPING_set_cmp_func(mappings, compare_issuer_policy);
- sk_POLICY_MAPPING_sort(mappings);
+ sk_POLICY_MAPPING_set_cmp_func(mappings, compare_issuer_policy);
+ sk_POLICY_MAPPING_sort(mappings);
- if (mapping_allowed) {
+ if (mapping_allowed) {
// Mark nodes as mapped, and add any nodes to |level| which may be needed
// as part of RFC 5280, section 6.1.4, step (b.1).
- new_nodes = sk_X509_POLICY_NODE_new_null();
- if (new_nodes == NULL) {
- goto err;
- }
- const ASN1_OBJECT *last_policy = NULL;
- for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
- const POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings, i);
- // There may be multiple mappings with the same |issuerDomainPolicy|.
- if (last_policy != NULL &&
- OBJ_cmp(mapping->issuerDomainPolicy, last_policy) == 0) {
- continue;
- }
- last_policy = mapping->issuerDomainPolicy;
-
- X509_POLICY_NODE *node =
- x509_policy_level_find(level, mapping->issuerDomainPolicy);
- if (node == NULL) {
- if (!level->has_any_policy) {
- continue;
- }
- node = x509_policy_node_new(mapping->issuerDomainPolicy);
- if (node == NULL || //
- !sk_X509_POLICY_NODE_push(new_nodes, node)) {
- x509_policy_node_free(node);
- goto err;
- }
- }
- node->mapped = 1;
- }
- if (!x509_policy_level_add_nodes(level, new_nodes)) {
- goto err;
- }
- } else {
+ new_nodes = sk_X509_POLICY_NODE_new_null();
+ if (new_nodes == NULL) {
+ goto err;
+ }
+ const ASN1_OBJECT *last_policy = NULL;
+ for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings);
+ i++) {
+ const POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings,
+ i);
+ // There may be multiple mappings with the same |issuerDomainPolicy|.
+ if (last_policy != NULL &&
+ OBJ_cmp(mapping->issuerDomainPolicy,
+ last_policy) == 0) {
+ continue;
+ }
+ last_policy = mapping->issuerDomainPolicy;
+
+ X509_POLICY_NODE *node =
+ x509_policy_level_find(level,
+ mapping->issuerDomainPolicy);
+ if (node == NULL) {
+ if (!level->has_any_policy) {
+ continue;
+ }
+ node = x509_policy_node_new(
+ mapping->issuerDomainPolicy);
+ if (node == NULL || //
+ !sk_X509_POLICY_NODE_push(new_nodes,
+ node)) {
+ x509_policy_node_free(node);
+ goto err;
+ }
+ }
+ node->mapped = 1;
+ }
+ if (!x509_policy_level_add_nodes(level, new_nodes)) {
+ goto err;
+ }
+ } else {
// RFC 5280, section 6.1.4, step (b.2). If mapping is inhibited, delete
// all mapped nodes.
- sk_X509_POLICY_NODE_delete_if(level->nodes, delete_if_mapped, mappings);
- sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
- mappings = NULL;
- }
- }
+ sk_X509_POLICY_NODE_delete_if(level->nodes,
+ delete_if_mapped, mappings);
+ sk_POLICY_MAPPING_pop_free(mappings,
+ POLICY_MAPPING_free);
+ mappings = NULL;
+ }
+ }
// If a node was not mapped, it retains the original "explicit_policy_set"
// value, itself. Add those to |mappings|.
- if (mappings == NULL) {
- mappings = sk_POLICY_MAPPING_new_null();
- if (mappings == NULL) {
- goto err;
- }
- }
- for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
- X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(level->nodes, i);
- if (!node->mapped) {
- POLICY_MAPPING *mapping = POLICY_MAPPING_new();
- if (mapping == NULL) {
- goto err;
- }
- mapping->issuerDomainPolicy = OBJ_dup(node->policy);
- mapping->subjectDomainPolicy = OBJ_dup(node->policy);
- if (mapping->issuerDomainPolicy == NULL ||
- mapping->subjectDomainPolicy == NULL ||
- !sk_POLICY_MAPPING_push(mappings, mapping)) {
- POLICY_MAPPING_free(mapping);
- goto err;
- }
- }
- }
+ if (mappings == NULL) {
+ mappings = sk_POLICY_MAPPING_new_null();
+ if (mappings == NULL) {
+ goto err;
+ }
+ }
+ for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
+ X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(level->nodes,
+ i);
+ if (!node->mapped) {
+ POLICY_MAPPING *mapping = POLICY_MAPPING_new();
+ if (mapping == NULL) {
+ goto err;
+ }
+ mapping->issuerDomainPolicy = OBJ_dup(node->policy);
+ mapping->subjectDomainPolicy = OBJ_dup(node->policy);
+ if (mapping->issuerDomainPolicy == NULL ||
+ mapping->subjectDomainPolicy == NULL ||
+ !sk_POLICY_MAPPING_push(mappings, mapping)) {
+ POLICY_MAPPING_free(mapping);
+ goto err;
+ }
+ }
+ }
// Sort to group by subjectDomainPolicy.
- sk_POLICY_MAPPING_set_cmp_func(mappings, compare_subject_policy);
- sk_POLICY_MAPPING_sort(mappings);
+ sk_POLICY_MAPPING_set_cmp_func(mappings, compare_subject_policy);
+ sk_POLICY_MAPPING_sort(mappings);
// Convert |mappings| to our "expected_policy_set" representation.
- next = x509_policy_level_new();
- if (next == NULL) {
- goto err;
- }
- next->has_any_policy = level->has_any_policy;
-
- X509_POLICY_NODE *last_node = NULL;
- for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
- POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings, i);
+ next = x509_policy_level_new();
+ if (next == NULL) {
+ goto err;
+ }
+ next->has_any_policy = level->has_any_policy;
+
+ X509_POLICY_NODE *last_node = NULL;
+ for (size_t i = 0; i < sk_POLICY_MAPPING_num(mappings); i++) {
+ POLICY_MAPPING *mapping = sk_POLICY_MAPPING_value(mappings, i);
// Skip mappings where |issuerDomainPolicy| does not appear in the graph.
- if (!level->has_any_policy &&
- x509_policy_level_find(level, mapping->issuerDomainPolicy) == NULL) {
- continue;
- }
-
- if (last_node == NULL ||
- OBJ_cmp(last_node->policy, mapping->subjectDomainPolicy) != 0) {
- last_node = x509_policy_node_new(mapping->subjectDomainPolicy);
- if (last_node == NULL ||
- !sk_X509_POLICY_NODE_push(next->nodes, last_node)) {
- x509_policy_node_free(last_node);
- goto err;
- }
- }
-
- if (!sk_ASN1_OBJECT_push(last_node->parent_policies,
- mapping->issuerDomainPolicy)) {
- goto err;
- }
- mapping->issuerDomainPolicy = NULL;
- }
-
- sk_X509_POLICY_NODE_sort(next->nodes);
- ok = 1;
+ if (!level->has_any_policy &&
+ x509_policy_level_find(level,
+ mapping->issuerDomainPolicy) == NULL) {
+ continue;
+ }
+
+ if (last_node == NULL ||
+ OBJ_cmp(last_node->policy, mapping->subjectDomainPolicy) !=
+ 0) {
+ last_node = x509_policy_node_new(
+ mapping->subjectDomainPolicy);
+ if (last_node == NULL ||
+ !sk_X509_POLICY_NODE_push(next->nodes, last_node)) {
+ x509_policy_node_free(last_node);
+ goto err;
+ }
+ }
+
+ if (!sk_ASN1_OBJECT_push(last_node->parent_policies,
+ mapping->issuerDomainPolicy)) {
+ goto err;
+ }
+ mapping->issuerDomainPolicy = NULL;
+ }
+
+ sk_X509_POLICY_NODE_sort(next->nodes);
+ ok = 1;
err:
- if (!ok) {
- x509_policy_level_free(next);
- next = NULL;
- }
-
- sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
- sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free);
- return next;
+ if (!ok) {
+ x509_policy_level_free(next);
+ next = NULL;
+ }
+
+ sk_POLICY_MAPPING_pop_free(mappings, POLICY_MAPPING_free);
+ sk_X509_POLICY_NODE_pop_free(new_nodes, x509_policy_node_free);
+ return next;
}
// apply_skip_certs, if |skip_certs| is non-NULL, sets |*value| to the minimum
// of its current value and |skip_certs|. It returns one on success and zero if
// |skip_certs| is negative.
-static int apply_skip_certs(const ASN1_INTEGER *skip_certs, size_t *value) {
- if (skip_certs == NULL) {
- return 1;
- }
+static int
+apply_skip_certs(const ASN1_INTEGER *skip_certs, size_t *value)
+{
+ if (skip_certs == NULL) {
+ return 1;
+ }
// TODO(https://crbug.com/boringssl/443): Move this check into the parser.
- if (skip_certs->type & V_ASN1_NEG) {
- X509error(X509_R_INVALID_POLICY_EXTENSION);
- return 0;
- }
+ if (skip_certs->type & V_ASN1_NEG) {
+ X509error(X509_R_INVALID_POLICY_EXTENSION);
+ return 0;
+ }
// If |skip_certs| does not fit in |uint64_t|, it must exceed |*value|.
- uint64_t u64;
- if (ASN1_INTEGER_get_uint64(&u64, skip_certs) && u64 < *value) {
- *value = (size_t)u64;
- }
- ERR_clear_error();
- return 1;
+ uint64_t u64;
+ if (ASN1_INTEGER_get_uint64(&u64, skip_certs) && u64 < *value) {
+ *value = (size_t)u64;
+ }
+ ERR_clear_error();
+ return 1;
}
// process_policy_constraints updates |*explicit_policy|, |*policy_mapping|, and
// |*inhibit_any_policy| according to |x509|'s policy constraints and inhibit
// anyPolicy extensions. It returns one on success and zero on error. This
// implements steps (i) and (j) of RFC 5280, section 6.1.4.
-static int process_policy_constraints(const X509 *x509, size_t *explicit_policy,
- size_t *policy_mapping,
- size_t *inhibit_any_policy) {
- int critical;
- POLICY_CONSTRAINTS *constraints =
- X509_get_ext_d2i(x509, NID_policy_constraints, &critical, NULL);
- if (constraints == NULL && critical != -1) {
- return 0;
- }
- if (constraints != NULL) {
- if (constraints->requireExplicitPolicy == NULL &&
- constraints->inhibitPolicyMapping == NULL) {
+static int
+process_policy_constraints(const X509 *x509, size_t *explicit_policy,
+ size_t *policy_mapping,
+ size_t *inhibit_any_policy)
+{
+ int critical;
+ POLICY_CONSTRAINTS *constraints =
+ X509_get_ext_d2i(x509, NID_policy_constraints, &critical, NULL);
+ if (constraints == NULL && critical != -1) {
+ return 0;
+ }
+ if (constraints != NULL) {
+ if (constraints->requireExplicitPolicy == NULL &&
+ constraints->inhibitPolicyMapping == NULL) {
// Per RFC 5280, section 4.2.1.11, at least one of the fields must be
// present.
- X509error(X509_R_INVALID_POLICY_EXTENSION);
- POLICY_CONSTRAINTS_free(constraints);
- return 0;
- }
- int ok =
- apply_skip_certs(constraints->requireExplicitPolicy, explicit_policy) &&
- apply_skip_certs(constraints->inhibitPolicyMapping, policy_mapping);
- POLICY_CONSTRAINTS_free(constraints);
- if (!ok) {
- return 0;
- }
- }
-
- ASN1_INTEGER *inhibit_any_policy_ext =
- X509_get_ext_d2i(x509, NID_inhibit_any_policy, &critical, NULL);
- if (inhibit_any_policy_ext == NULL && critical != -1) {
- return 0;
- }
- int ok = apply_skip_certs(inhibit_any_policy_ext, inhibit_any_policy);
- ASN1_INTEGER_free(inhibit_any_policy_ext);
- return ok;
+ X509error(X509_R_INVALID_POLICY_EXTENSION);
+ POLICY_CONSTRAINTS_free(constraints);
+ return 0;
+ }
+ int ok =
+ apply_skip_certs(constraints->requireExplicitPolicy,
+ explicit_policy) &&
+ apply_skip_certs(constraints->inhibitPolicyMapping,
+ policy_mapping);
+ POLICY_CONSTRAINTS_free(constraints);
+ if (!ok) {
+ return 0;
+ }
+ }
+
+ ASN1_INTEGER *inhibit_any_policy_ext =
+ X509_get_ext_d2i(x509, NID_inhibit_any_policy, &critical, NULL);
+ if (inhibit_any_policy_ext == NULL && critical != -1) {
+ return 0;
+ }
+ int ok = apply_skip_certs(inhibit_any_policy_ext, inhibit_any_policy);
+ ASN1_INTEGER_free(inhibit_any_policy_ext);
+ return ok;
}
// has_explicit_policy returns one if the set of authority-space policy OIDs
// otherwise. This mirrors the logic in RFC 5280, section 6.1.5, step (g). This
// function modifies |levels| and should only be called at the end of policy
// evaluation.
-static int has_explicit_policy(STACK_OF(X509_POLICY_LEVEL) *levels,
- const STACK_OF(ASN1_OBJECT) *user_policies) {
- assert(user_policies == NULL || sk_ASN1_OBJECT_is_sorted(user_policies));
+static int
+has_explicit_policy(STACK_OF(X509_POLICY_LEVEL) *levels,
+ const STACK_OF(ASN1_OBJECT) *user_policies)
+{
+ assert(user_policies == NULL ||
+ sk_ASN1_OBJECT_is_sorted(user_policies));
// Step (g.i). If the policy graph is empty, the intersection is empty.
- size_t num_levels = sk_X509_POLICY_LEVEL_num(levels);
- X509_POLICY_LEVEL *level = sk_X509_POLICY_LEVEL_value(levels, num_levels - 1);
- if (x509_policy_level_is_empty(level)) {
- return 0;
- }
+ size_t num_levels = sk_X509_POLICY_LEVEL_num(levels);
+ X509_POLICY_LEVEL *level = sk_X509_POLICY_LEVEL_value(levels,
+ num_levels - 1);
+ if (x509_policy_level_is_empty(level)) {
+ return 0;
+ }
// If |user_policies| is empty, we interpret it as having a single anyPolicy
// value. The caller may also have supplied anyPolicy explicitly.
- int user_has_any_policy = sk_ASN1_OBJECT_num(user_policies) == 0;
- for (size_t i = 0; i < sk_ASN1_OBJECT_num(user_policies); i++) {
- if (is_any_policy(sk_ASN1_OBJECT_value(user_policies, i))) {
- user_has_any_policy = 1;
- break;
- }
- }
+ int user_has_any_policy = sk_ASN1_OBJECT_num(user_policies) == 0;
+ for (size_t i = 0; i < sk_ASN1_OBJECT_num(user_policies); i++) {
+ if (is_any_policy(sk_ASN1_OBJECT_value(user_policies, i))) {
+ user_has_any_policy = 1;
+ break;
+ }
+ }
// Step (g.ii). If the policy graph is not empty and the user set contains
// anyPolicy, the intersection is the entire (non-empty) graph.
- if (user_has_any_policy) {
- return 1;
- }
+ if (user_has_any_policy) {
+ return 1;
+ }
// Step (g.iii) does not delete anyPolicy nodes, so if the graph has
// anyPolicy, some explicit policy will survive. The actual intersection may
// synthesize some nodes in step (g.iii.3), but we do not return the policy
// list itself, so we skip actually computing this.
- if (level->has_any_policy) {
- return 1;
- }
+ if (level->has_any_policy) {
+ return 1;
+ }
// We defer pruning the tree, so as we look for nodes with parent anyPolicy,
// step (g.iii.1), we must limit to nodes reachable from the bottommost level.
// Start by marking each of those nodes as reachable.
- for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
- sk_X509_POLICY_NODE_value(level->nodes, i)->reachable = 1;
- }
-
- for (size_t i = num_levels - 1; i < num_levels; i--) {
- level = sk_X509_POLICY_LEVEL_value(levels, i);
- for (size_t j = 0; j < sk_X509_POLICY_NODE_num(level->nodes); j++) {
- X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(level->nodes, j);
- if (!node->reachable) {
- continue;
- }
- if (sk_ASN1_OBJECT_num(node->parent_policies) == 0) {
- // |node|'s parent is anyPolicy and is part of "valid_policy_node_set".
- // If it exists in |user_policies|, the intersection is non-empty and we
- // can return immediately.
- if (sk_ASN1_OBJECT_find(user_policies, node->policy) >= 0) {
- return 1;
- }
- } else if (i > 0) {
- // |node|'s parents are concrete policies. Mark the parents reachable,
- // to be inspected by the next loop iteration.
- X509_POLICY_LEVEL *prev = sk_X509_POLICY_LEVEL_value(levels, i - 1);
- for (size_t k = 0; k < sk_ASN1_OBJECT_num(node->parent_policies); k++) {
- X509_POLICY_NODE *parent = x509_policy_level_find(
- prev, sk_ASN1_OBJECT_value(node->parent_policies, k));
- if (parent != NULL) {
- parent->reachable = 1;
- }
- }
- }
- }
- }
-
- return 0;
+ for (size_t i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
+ sk_X509_POLICY_NODE_value(level->nodes, i)->reachable = 1;
+ }
+
+ for (size_t i = num_levels - 1; i < num_levels; i--) {
+ level = sk_X509_POLICY_LEVEL_value(levels, i);
+ for (size_t j = 0; j < sk_X509_POLICY_NODE_num(level->nodes);
+ j++) {
+ X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(level->nodes,
+ j);
+ if (!node->reachable) {
+ continue;
+ }
+ if (sk_ASN1_OBJECT_num(node->parent_policies) == 0) {
+ // |node|'s parent is anyPolicy and is part of "valid_policy_node_set".
+ // If it exists in |user_policies|, the intersection is non-empty and we
+ // can return immediately.
+ if (sk_ASN1_OBJECT_find(user_policies,
+ node->policy) >= 0) {
+ return 1;
+ }
+ } else if (i > 0) {
+ // |node|'s parents are concrete policies. Mark the parents reachable,
+ // to be inspected by the next loop iteration.
+ X509_POLICY_LEVEL *prev = sk_X509_POLICY_LEVEL_value(levels,
+ i - 1);
+ for (size_t k = 0; k <
+ sk_ASN1_OBJECT_num(node->parent_policies);
+ k++) {
+ X509_POLICY_NODE *parent = x509_policy_level_find(
+ prev,
+
+ sk_ASN1_OBJECT_value(node->parent_policies,
+ k));
+ if (parent != NULL) {
+ parent->reachable = 1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
}
-static int asn1_object_cmp(const ASN1_OBJECT *const *a,
- const ASN1_OBJECT *const *b) {
- return OBJ_cmp(*a, *b);
+static int
+asn1_object_cmp(const ASN1_OBJECT *const *a,
+ const ASN1_OBJECT *const *b)
+{
+ return OBJ_cmp(*a, *b);
}
-int X509_policy_check(const STACK_OF(X509) *certs,
- const STACK_OF(ASN1_OBJECT) *user_policies,
- unsigned long flags, X509 **out_current_cert) {
- *out_current_cert = NULL;
- int ret = X509_V_ERR_OUT_OF_MEM;
- X509_POLICY_LEVEL *level = NULL;
- STACK_OF(X509_POLICY_LEVEL) *levels = NULL;
- STACK_OF(ASN1_OBJECT) *user_policies_sorted = NULL;
- size_t num_certs = sk_X509_num(certs);
+int
+X509_policy_check(const STACK_OF(X509) *certs,
+ const STACK_OF(ASN1_OBJECT) *user_policies,
+ unsigned long flags, X509 **out_current_cert)
+{
+ *out_current_cert = NULL;
+ int ret = X509_V_ERR_OUT_OF_MEM;
+ X509_POLICY_LEVEL *level = NULL;
+ STACK_OF(X509_POLICY_LEVEL) *levels = NULL;
+ STACK_OF(ASN1_OBJECT) *user_policies_sorted = NULL;
+ size_t num_certs = sk_X509_num(certs);
// Skip policy checking if the chain is just the trust anchor.
- if (num_certs <= 1) {
- return X509_V_OK;
- }
+ if (num_certs <= 1) {
+ return X509_V_OK;
+ }
// See RFC 5280, section 6.1.2, steps (d) through (f).
- size_t explicit_policy =
- (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : num_certs + 1;
- size_t inhibit_any_policy =
- (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : num_certs + 1;
- size_t policy_mapping =
- (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : num_certs + 1;
-
- levels = sk_X509_POLICY_LEVEL_new_null();
- if (levels == NULL) {
- goto err;
- }
-
- for (size_t i = num_certs - 2; i < num_certs; i--) {
- X509 *cert = sk_X509_value(certs, i);
- if (!x509v3_cache_extensions(cert)) {
- goto err;
- }
- const int is_self_issued = (cert->ex_flags & EXFLAG_SI) != 0;
-
- if (level == NULL) {
- assert(i == num_certs - 2);
- level = x509_policy_level_new();
- if (level == NULL) {
- goto err;
- }
- level->has_any_policy = 1;
- }
+ size_t explicit_policy =
+ (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : num_certs + 1;
+ size_t inhibit_any_policy =
+ (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : num_certs + 1;
+ size_t policy_mapping =
+ (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : num_certs + 1;
+
+ levels = sk_X509_POLICY_LEVEL_new_null();
+ if (levels == NULL) {
+ goto err;
+ }
+
+ for (size_t i = num_certs - 2; i < num_certs; i--) {
+ X509 *cert = sk_X509_value(certs, i);
+ if (!x509v3_cache_extensions(cert)) {
+ goto err;
+ }
+ const int is_self_issued = (cert->ex_flags & EXFLAG_SI) != 0;
+
+ if (level == NULL) {
+ assert(i == num_certs - 2);
+ level = x509_policy_level_new();
+ if (level == NULL) {
+ goto err;
+ }
+ level->has_any_policy = 1;
+ }
// RFC 5280, section 6.1.3, steps (d) and (e). |any_policy_allowed| is
// computed as in step (d.2).
- const int any_policy_allowed =
- inhibit_any_policy > 0 || (i > 0 && is_self_issued);
- if (!process_certificate_policies(cert, level, any_policy_allowed)) {
- ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
- *out_current_cert = cert;
- goto err;
- }
+ const int any_policy_allowed =
+ inhibit_any_policy > 0 || (i > 0 && is_self_issued);
+ if (!process_certificate_policies(cert, level,
+ any_policy_allowed)) {
+ ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
+ *out_current_cert = cert;
+ goto err;
+ }
// RFC 5280, section 6.1.3, step (f).
- if (explicit_policy == 0 && x509_policy_level_is_empty(level)) {
- ret = X509_V_ERR_NO_EXPLICIT_POLICY;
- goto err;
- }
+ if (explicit_policy == 0 && x509_policy_level_is_empty(level)) {
+ ret = X509_V_ERR_NO_EXPLICIT_POLICY;
+ goto err;
+ }
// Insert into the list.
- if (!sk_X509_POLICY_LEVEL_push(levels, level)) {
- goto err;
- }
- X509_POLICY_LEVEL *current_level = level;
- level = NULL;
+ if (!sk_X509_POLICY_LEVEL_push(levels, level)) {
+ goto err;
+ }
+ X509_POLICY_LEVEL *current_level = level;
+ level = NULL;
// If this is not the leaf certificate, we go to section 6.1.4. If it
// is the leaf certificate, we go to section 6.1.5 instead.
- if (i != 0) {
+ if (i != 0) {
// RFC 5280, section 6.1.4, steps (a) and (b).
- level = process_policy_mappings(cert, current_level, policy_mapping > 0);
- if (level == NULL) {
- ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
- *out_current_cert = cert;
- goto err;
- }
- }
+ level = process_policy_mappings(cert, current_level,
+ policy_mapping > 0);
+ if (level == NULL) {
+ ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
+ *out_current_cert = cert;
+ goto err;
+ }
+ }
// RFC 5280, section 6.1.4, step (h-j) for non-leaves, and section 6.1.5,
// step (a-b) for leaves. In the leaf case, RFC 5280 says only to update
// |explicit_policy|, but |policy_mapping| and |inhibit_any_policy| are no
// longer read at this point, so we use the same process.
- if (i == 0 || !is_self_issued) {
- if (explicit_policy > 0) {
- explicit_policy--;
- }
- if (policy_mapping > 0) {
- policy_mapping--;
- }
- if (inhibit_any_policy > 0) {
- inhibit_any_policy--;
- }
- }
- if (!process_policy_constraints(cert, &explicit_policy, &policy_mapping,
- &inhibit_any_policy)) {
- ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
- *out_current_cert = cert;
- goto err;
- }
- }
+ if (i == 0 || !is_self_issued) {
+ if (explicit_policy > 0) {
+ explicit_policy--;
+ }
+ if (policy_mapping > 0) {
+ policy_mapping--;
+ }
+ if (inhibit_any_policy > 0) {
+ inhibit_any_policy--;
+ }
+ }
+ if (!process_policy_constraints(cert, &explicit_policy,
+ &policy_mapping, &inhibit_any_policy)) {
+ ret = X509_V_ERR_INVALID_POLICY_EXTENSION;
+ *out_current_cert = cert;
+ goto err;
+ }
+ }
// RFC 5280, section 6.1.5, step (g). We do not output the policy set, so it
// is only necessary to check if the user-constrained-policy-set is not empty.
- if (explicit_policy == 0) {
+ if (explicit_policy == 0) {
// Build a sorted copy of |user_policies| for more efficient lookup.
- if (user_policies != NULL) {
- user_policies_sorted = sk_ASN1_OBJECT_dup(user_policies);
- if (user_policies_sorted == NULL) {
- goto err;
- }
- sk_ASN1_OBJECT_set_cmp_func(user_policies_sorted, asn1_object_cmp);
- sk_ASN1_OBJECT_sort(user_policies_sorted);
- }
-
- if (!has_explicit_policy(levels, user_policies_sorted)) {
- ret = X509_V_ERR_NO_EXPLICIT_POLICY;
- goto err;
- }
- }
-
- ret = X509_V_OK;
+ if (user_policies != NULL) {
+ user_policies_sorted = sk_ASN1_OBJECT_dup(
+ user_policies);
+ if (user_policies_sorted == NULL) {
+ goto err;
+ }
+ sk_ASN1_OBJECT_set_cmp_func(user_policies_sorted,
+ asn1_object_cmp);
+ sk_ASN1_OBJECT_sort(user_policies_sorted);
+ }
+
+ if (!has_explicit_policy(levels, user_policies_sorted)) {
+ ret = X509_V_ERR_NO_EXPLICIT_POLICY;
+ goto err;
+ }
+ }
+
+ ret = X509_V_OK;
err:
- x509_policy_level_free(level);
+ x509_policy_level_free(level);
// |user_policies_sorted|'s contents are owned by |user_policies|, so we do
// not use |sk_ASN1_OBJECT_pop_free|.
- sk_ASN1_OBJECT_free(user_policies_sorted);
- sk_X509_POLICY_LEVEL_pop_free(levels, x509_policy_level_free);
- return ret;
+ sk_ASN1_OBJECT_free(user_policies_sorted);
+ sk_X509_POLICY_LEVEL_pop_free(levels, x509_policy_level_free);
+ return ret;
}
#endif /* LIBRESSL_HAS_POLICY_DAG */