- unsigned int flags)
- {
- X509_POLICY_TREE *tree;
- X509_POLICY_LEVEL *level;
- const X509_POLICY_CACHE *cache;
- X509_POLICY_DATA *data = NULL;
- X509 *x;
- int ret = 1;
- int i, n;
- int explicit_policy;
- int any_skip;
- int map_skip;
- *ptree = NULL;
- n = sk_X509_num(certs);
-
- /* Disable policy mapping for now... */
- flags |= X509_V_FLAG_INHIBIT_MAP;
-
- if (flags & X509_V_FLAG_EXPLICIT_POLICY)
- explicit_policy = 0;
- else
- explicit_policy = n + 1;
-
- if (flags & X509_V_FLAG_INHIBIT_ANY)
- any_skip = 0;
- else
- any_skip = n + 1;
-
- if (flags & X509_V_FLAG_INHIBIT_MAP)
- map_skip = 0;
- else
- map_skip = n + 1;
-
- /* Can't do anything with just a trust anchor */
- if (n == 1)
- return 1;
- /* First setup policy cache in all certificates apart from the
- * trust anchor. Note any bad cache results on the way. Also can
- * calculate explicit_policy value at this point.
- */
- for (i = n - 2; i >= 0; i--)
- {
- x = sk_X509_value(certs, i);
- X509_check_purpose(x, -1, -1);
- cache = policy_cache_set(x);
- /* If cache NULL something bad happened: return immediately */
- if (cache == NULL)
- return 0;
- /* If inconsistent extensions keep a note of it but continue */
- if (x->ex_flags & EXFLAG_INVALID_POLICY)
- ret = -1;
- /* Otherwise if we have no data (hence no CertificatePolicies)
- * and haven't already set an inconsistent code note it.
- */
- else if ((ret == 1) && !cache->data)
- ret = 2;
- if (explicit_policy > 0)
- {
- explicit_policy--;
- if (!(x->ex_flags & EXFLAG_SS)
- && (cache->explicit_skip != -1)
- && (cache->explicit_skip < explicit_policy))
- explicit_policy = cache->explicit_skip;
- }
- }
-
- if (ret != 1)
- {
- if (ret == 2 && !explicit_policy)
- return 6;
- return ret;
- }
-
-
- /* If we get this far initialize the tree */
-
- tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE));
-
- if (!tree)
- return 0;
-
- tree->flags = 0;
- tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n);
- tree->nlevel = 0;
- tree->extra_data = NULL;
- tree->auth_policies = NULL;
- tree->user_policies = NULL;
-
- if (!tree)
- {
- OPENSSL_free(tree);
- return 0;
- }
-
- memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL));
-
- tree->nlevel = n;
-
- level = tree->levels;
-
- /* Root data: initialize to anyPolicy */
-
- data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0);
-
- if (!data || !level_add_node(level, data, NULL, tree))
- goto bad_tree;
-
- for (i = n - 2; i >= 0; i--)
- {
- level++;
- x = sk_X509_value(certs, i);
- cache = policy_cache_set(x);
-
- CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
- level->cert = x;
-
- if (!cache->anyPolicy)
- level->flags |= X509_V_FLAG_INHIBIT_ANY;
-
- /* Determine inhibit any and inhibit map flags */
- if (any_skip == 0)
- {
- /* Any matching allowed if certificate is self
- * issued and not the last in the chain.
- */
- if (!(x->ex_flags && EXFLAG_SS) || (i == 0))
- level->flags |= X509_V_FLAG_INHIBIT_ANY;
- }
- else
- {
- any_skip--;
- if ((cache->any_skip > 0)
- && (cache->any_skip < any_skip))
- any_skip = cache->any_skip;
- }
-
- if (map_skip == 0)
- level->flags |= X509_V_FLAG_INHIBIT_MAP;
- else
- {
- map_skip--;
- if ((cache->map_skip > 0)
- && (cache->map_skip < map_skip))
- map_skip = cache->map_skip;
- }
-
-
- }
-
- *ptree = tree;
-
- if (explicit_policy)
- return 1;
- else
- return 5;
-
- bad_tree:
-
- X509_policy_tree_free(tree);
-
- return 0;
-
- }
-
-/* This corresponds to RFC3280 XXXX XXXXX:
- * link any data from CertificatePolicies onto matching parent
- * or anyPolicy if no match.
+ unsigned int flags)
+{
+ X509_POLICY_TREE *tree;
+ X509_POLICY_LEVEL *level;
+ const X509_POLICY_CACHE *cache;
+ X509_POLICY_DATA *data = NULL;
+ X509 *x;
+ int ret = 1;
+ int i, n;
+ int explicit_policy;
+ int any_skip;
+ int map_skip;
+
+ *ptree = NULL;
+ n = sk_X509_num(certs);
+
+ if (flags & X509_V_FLAG_EXPLICIT_POLICY)
+ explicit_policy = 0;
+ else
+ explicit_policy = n + 1;
+
+ if (flags & X509_V_FLAG_INHIBIT_ANY)
+ any_skip = 0;
+ else
+ any_skip = n + 1;
+
+ if (flags & X509_V_FLAG_INHIBIT_MAP)
+ map_skip = 0;
+ else
+ map_skip = n + 1;
+
+ /* Can't do anything with just a trust anchor */
+ if (n == 1)
+ return 1;
+ /*
+ * First setup policy cache in all certificates apart from the trust
+ * anchor. Note any bad cache results on the way. Also can calculate
+ * explicit_policy value at this point.
+ */
+ for (i = n - 2; i >= 0; i--) {
+ x = sk_X509_value(certs, i);
+ X509_check_purpose(x, -1, -1);
+ cache = policy_cache_set(x);
+ /* If cache NULL something bad happened: return immediately */
+ if (cache == NULL)
+ return 0;
+ /*
+ * If inconsistent extensions keep a note of it but continue
+ */
+ if (x->ex_flags & EXFLAG_INVALID_POLICY)
+ ret = -1;
+ /*
+ * Otherwise if we have no data (hence no CertificatePolicies) and
+ * haven't already set an inconsistent code note it.
+ */
+ else if ((ret == 1) && !cache->data)
+ ret = 2;
+ if (explicit_policy > 0) {
+ if (!(x->ex_flags & EXFLAG_SI))
+ explicit_policy--;
+ if ((cache->explicit_skip != -1)
+ && (cache->explicit_skip < explicit_policy))
+ explicit_policy = cache->explicit_skip;
+ }
+ }
+
+ if (ret != 1) {
+ if (ret == 2 && !explicit_policy)
+ return 6;
+ return ret;
+ }
+
+ /* If we get this far initialize the tree */
+ tree = OPENSSL_zalloc(sizeof(*tree));
+ if (!tree)
+ return 0;
+ tree->levels = OPENSSL_zalloc(sizeof(*tree->levels) * n);
+ if (!tree->levels) {
+ OPENSSL_free(tree);
+ return 0;
+ }
+ tree->nlevel = n;
+ level = tree->levels;
+
+ /* Root data: initialize to anyPolicy */
+ data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0);
+
+ if (!data || !level_add_node(level, data, NULL, tree))
+ goto bad_tree;
+
+ for (i = n - 2; i >= 0; i--) {
+ level++;
+ x = sk_X509_value(certs, i);
+ cache = policy_cache_set(x);
+ X509_up_ref(x);
+ level->cert = x;
+
+ if (!cache->anyPolicy)
+ level->flags |= X509_V_FLAG_INHIBIT_ANY;
+
+ /* Determine inhibit any and inhibit map flags */
+ if (any_skip == 0) {
+ /*
+ * Any matching allowed if certificate is self issued and not the
+ * last in the chain.
+ */
+ if (!(x->ex_flags & EXFLAG_SI) || (i == 0))
+ level->flags |= X509_V_FLAG_INHIBIT_ANY;
+ } else {
+ if (!(x->ex_flags & EXFLAG_SI))
+ any_skip--;
+ if ((cache->any_skip >= 0)
+ && (cache->any_skip < any_skip))
+ any_skip = cache->any_skip;
+ }
+
+ if (map_skip == 0)
+ level->flags |= X509_V_FLAG_INHIBIT_MAP;
+ else {
+ if (!(x->ex_flags & EXFLAG_SI))
+ map_skip--;
+ if ((cache->map_skip >= 0)
+ && (cache->map_skip < map_skip))
+ map_skip = cache->map_skip;
+ }
+
+ }
+
+ *ptree = tree;
+
+ if (explicit_policy)
+ return 1;
+ else
+ return 5;
+
+ bad_tree:
+
+ X509_policy_tree_free(tree);
+
+ return 0;
+
+}
+
+static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
+ const X509_POLICY_DATA *data)
+{
+ X509_POLICY_LEVEL *last = curr - 1;
+ X509_POLICY_NODE *node;
+ int i, matched = 0;
+ /* Iterate through all in nodes linking matches */
+ for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) {
+ node = sk_X509_POLICY_NODE_value(last->nodes, i);
+ if (policy_node_match(last, node, data->valid_policy)) {
+ if (!level_add_node(curr, data, node, NULL))
+ return 0;
+ matched = 1;
+ }
+ }
+ if (!matched && last->anyPolicy) {
+ if (!level_add_node(curr, data, last->anyPolicy, NULL))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This corresponds to RFC3280 6.1.3(d)(1): link any data from
+ * CertificatePolicies onto matching parent or anyPolicy if no match.