diff options
Diffstat (limited to 'crypto/x509v3')
-rw-r--r-- | crypto/x509v3/Makefile.ssl | 8 | ||||
-rw-r--r-- | crypto/x509v3/pcy_cache.c | 286 | ||||
-rw-r--r-- | crypto/x509v3/pcy_data.c | 123 | ||||
-rw-r--r-- | crypto/x509v3/pcy_int.h | 220 | ||||
-rw-r--r-- | crypto/x509v3/pcy_lib.c | 165 | ||||
-rw-r--r-- | crypto/x509v3/pcy_map.c | 186 | ||||
-rw-r--r-- | crypto/x509v3/pcy_node.c | 159 | ||||
-rw-r--r-- | crypto/x509v3/pcy_tree.c | 681 | ||||
-rw-r--r-- | crypto/x509v3/x509v3.h | 2 |
9 files changed, 1827 insertions, 3 deletions
diff --git a/crypto/x509v3/Makefile.ssl b/crypto/x509v3/Makefile.ssl index e29f366cbe..ab13173263 100644 --- a/crypto/x509v3/Makefile.ssl +++ b/crypto/x509v3/Makefile.ssl @@ -26,16 +26,18 @@ LIB=$(TOP)/libcrypto.a LIBSRC= v3_bcons.c v3_bitst.c v3_conf.c v3_extku.c v3_ia5.c v3_lib.c \ v3_prn.c v3_utl.c v3err.c v3_genn.c v3_alt.c v3_skey.c v3_akey.c v3_pku.c \ v3_int.c v3_enum.c v3_sxnet.c v3_cpols.c v3_crld.c v3_purp.c v3_info.c \ -v3_ocsp.c v3_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c +v3_ocsp.c v3_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c pcy_cache.c pcy_node.c \ +pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c LIBOBJ= v3_bcons.o v3_bitst.o v3_conf.o v3_extku.o v3_ia5.o v3_lib.o \ v3_prn.o v3_utl.o v3err.o v3_genn.o v3_alt.o v3_skey.o v3_akey.o v3_pku.o \ v3_int.o v3_enum.o v3_sxnet.o v3_cpols.o v3_crld.o v3_purp.o v3_info.o \ -v3_ocsp.o v3_akeya.o v3_pmaps.o v3_pcons.o v3_ncons.o +v3_ocsp.o v3_akeya.o v3_pmaps.o v3_pcons.o v3_ncons.o pcy_cache.o pcy_node.o \ +pcy_data.o pcy_map.o pcy_tree.o pcy_lib.o SRC= $(LIBSRC) EXHEADER= x509v3.h -HEADER= $(EXHEADER) +HEADER= $(EXHEADER) pcy_int.h ALL= $(GENERAL) $(SRC) $(HEADER) diff --git a/crypto/x509v3/pcy_cache.c b/crypto/x509v3/pcy_cache.c new file mode 100644 index 0000000000..23d930dd9c --- /dev/null +++ b/crypto/x509v3/pcy_cache.c @@ -0,0 +1,286 @@ +/* pcy_cache.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include "cryptlib.h" +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "pcy_int.h" + +static int policy_data_cmp(void *pa, void *pb); +static int policy_cache_set_int(long *out, ASN1_INTEGER *value); + +/* Set cache entry according to CertificatePolicies extension. + * Note: this destroys the passed CERTIFICATEPOLICIES structure. + */ + +static int policy_cache_create(X509 *x, + CERTIFICATEPOLICIES *policies, int crit) + { + int i; + int ret = 0; + X509_POLICY_CACHE *cache = x->policy_cache; + X509_POLICY_DATA *data = NULL; + POLICYINFO *policy; + if (sk_POLICYINFO_num(policies) == 0) + goto bad_policy; + cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp); + if (!cache->data) + goto bad_policy; + for (i = 0; i < sk_POLICYINFO_num(policies); i++) + { + policy = sk_POLICYINFO_value(policies, i); + data = policy_data_new(policy, NULL, crit); + if (!data) + goto bad_policy; + /* Duplicate policy OIDs are illegal: reject if matches + * found. + */ + if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) + { + if (cache->anyPolicy) + { + ret = -1; + goto bad_policy; + } + cache->anyPolicy = data; + } + else if (sk_X509_POLICY_DATA_find(cache->data, data) != -1) + { + ret = -1; + goto bad_policy; + } + else if (!sk_X509_POLICY_DATA_push(cache->data, data)) + goto bad_policy; + data = NULL; + } + ret = 1; + bad_policy: + if (ret == -1) + x->ex_flags |= EXFLAG_INVALID_POLICY; + if (data) + policy_data_free(data); + sk_POLICYINFO_pop_free(policies, POLICYINFO_free); + if (ret <= 0) + { + sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); + cache->data = NULL; + } + return ret; + } + + +static int policy_cache_new(X509 *x) + { + X509_POLICY_CACHE *cache; + ASN1_INTEGER *ext_any = NULL; + POLICY_CONSTRAINTS *ext_pcons = NULL; + CERTIFICATEPOLICIES *ext_cpols = NULL; + POLICY_MAPPINGS *ext_pmaps = NULL; + int i; + cache = OPENSSL_malloc(sizeof(X509_POLICY_CACHE)); + if (!cache) + return 0; + cache->anyPolicy = NULL; + cache->data = NULL; + cache->maps = NULL; + cache->any_skip = -1; + cache->explicit_skip = -1; + cache->map_skip = -1; + + x->policy_cache = cache; + + /* Handle requireExplicitPolicy *first*. Need to process this + * even if we don't have any policies. + */ + ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL); + + if (!ext_pcons) + { + if (i != -1) + goto bad_cache; + } + else + { + if (!ext_pcons->requireExplicitPolicy + && !ext_pcons->inhibitPolicyMapping) + goto bad_cache; + if (!policy_cache_set_int(&cache->explicit_skip, + ext_pcons->requireExplicitPolicy)) + goto bad_cache; + if (!policy_cache_set_int(&cache->map_skip, + ext_pcons->inhibitPolicyMapping)) + goto bad_cache; + } + + /* Process CertificatePolicies */ + + ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL); + /* If no CertificatePolicies extension or problem decoding then + * there is no point continuing because the valid policies will be + * NULL. + */ + if (!ext_cpols) + { + /* If not absent some problem with extension */ + if (i != -1) + goto bad_cache; + return 1; + } + + i = policy_cache_create(x, ext_cpols, i); + + /* NB: ext_cpols freed by policy_cache_set_policies */ + + if (i <= 0) + return i; + + ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL); + + if (!ext_pmaps) + { + /* If not absent some problem with extension */ + if (i != -1) + goto bad_cache; + } + else + { + i = policy_cache_set_mapping(x, ext_pmaps); + if (i <= 0) + goto bad_cache; + } + + ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL); + + if (!ext_any) + { + if (i != -1) + goto bad_cache; + } + else if (!policy_cache_set_int(&cache->any_skip, ext_any)) + goto bad_cache; + + if (0) + { + bad_cache: + x->ex_flags |= EXFLAG_INVALID_POLICY; + } + + if(ext_pcons) + POLICY_CONSTRAINTS_free(ext_pcons); + + if (ext_any) + ASN1_INTEGER_free(ext_any); + + return 1; + + +} + +void policy_cache_free(X509_POLICY_CACHE *cache) + { + if (!cache) + return; + if (cache->anyPolicy) + policy_data_free(cache->anyPolicy); + if (cache->data) + sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); + OPENSSL_free(cache); + } + +const X509_POLICY_CACHE *policy_cache_set(X509 *x) + { + + if (x->policy_cache == NULL) + { + CRYPTO_w_lock(CRYPTO_LOCK_X509); + policy_cache_new(x); + CRYPTO_w_unlock(CRYPTO_LOCK_X509); + } + + return x->policy_cache; + + } + +X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id) + { + int idx; + X509_POLICY_DATA tmp; + tmp.valid_policy = (ASN1_OBJECT *)id; + idx = sk_X509_POLICY_DATA_find(cache->data, &tmp); + if (idx == -1) + return NULL; + return sk_X509_POLICY_DATA_value(cache->data, idx); + } + +static int policy_data_cmp(void *pa, void *pb) + { + X509_POLICY_DATA **a = pa; X509_POLICY_DATA **b = pb; + return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy); + } + +static int policy_cache_set_int(long *out, ASN1_INTEGER *value) + { + if (value == NULL) + return 1; + if (value->type == V_ASN1_NEG_INTEGER) + return 0; + *out = ASN1_INTEGER_get(value); + return 1; + } diff --git a/crypto/x509v3/pcy_data.c b/crypto/x509v3/pcy_data.c new file mode 100644 index 0000000000..fae74cac92 --- /dev/null +++ b/crypto/x509v3/pcy_data.c @@ -0,0 +1,123 @@ +/* pcy_data.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include "cryptlib.h" +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "pcy_int.h" + +/* Policy Node routines */ + +void policy_data_free(X509_POLICY_DATA *data) + { + ASN1_OBJECT_free(data->valid_policy); + /* Don't free qualifiers if shared */ + if (!(data->flags & POLICY_DATA_FLAG_SHARED_QUALIFIERS)) + sk_POLICYINFO_pop_free(data->qualifier_set, + POLICYQUALINFO_free); + sk_ASN1_OBJECT_pop_free(data->expected_policy_set, ASN1_OBJECT_free); + OPENSSL_free(data); + } + +/* Create a data based on an existing policy. If 'id' is NULL use the + * oid in the policy, otherwise use 'id'. This behaviour covers the two + * types of data in RFC3280: data with from a CertificatePolcies extension + * and additional data with just the qualifiers of anyPolicy and ID from + * another source. + */ + +X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, ASN1_OBJECT *id, int crit) + { + X509_POLICY_DATA *ret; + if (!policy && !id) + return NULL; + ret = OPENSSL_malloc(sizeof(X509_POLICY_DATA)); + if (!ret) + return NULL; + ret->expected_policy_set = sk_ASN1_OBJECT_new_null(); + if (!ret->expected_policy_set) + { + OPENSSL_free(ret); + return NULL; + } + + if (crit) + ret->flags = POLICY_DATA_FLAG_CRITICAL; + else + ret->flags = 0; + + if (id) + ret->valid_policy = id; + else + { + ret->valid_policy = policy->policyid; + policy->policyid = NULL; + } + + if (policy) + { + ret->qualifier_set = policy->qualifiers; + policy->qualifiers = NULL; + } + else + ret->qualifier_set = NULL; + + return ret; + } + diff --git a/crypto/x509v3/pcy_int.h b/crypto/x509v3/pcy_int.h new file mode 100644 index 0000000000..65689880a6 --- /dev/null +++ b/crypto/x509v3/pcy_int.h @@ -0,0 +1,220 @@ +/* pcy_int.h */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +DECLARE_STACK_OF(X509_POLICY_DATA) +DECLARE_STACK_OF(X509_POLICY_REF) +DECLARE_STACK_OF(X509_POLICY_NODE) + +typedef struct X509_POLICY_DATA_st X509_POLICY_DATA; +typedef struct X509_POLICY_REF_st X509_POLICY_REF; + +/* Internal structures */ + +/* This structure and the field names correspond to the Policy 'node' of + * RFC3280. NB this structure contains no pointers to parent or child + * data: X509_POLICY_NODE contains that. This means that the main policy data + * can be kept static and cached with the certificate. + */ + +struct X509_POLICY_DATA_st + { + unsigned int flags; + /* Policy OID and qualifiers for this data */ + ASN1_OBJECT *valid_policy; + STACK_OF(POLICYQUALIFIER) *qualifier_set; + STACK_OF(ASN1_OBJECT) *expected_policy_set; + }; + +/* X509_POLICY_DATA flags values */ + +/* This flag indicates the structure has been mapped using a policy mapping + * extension. If policy mapping is not active its references get deleted. + */ + +#define POLICY_DATA_FLAG_MAPPED 0x1 + +/* This flag indicates the data doesn't correspond to a policy in Certificate + * Policies: it has been mapped to any policy. + */ + +#define POLICY_DATA_FLAG_MAPPED_ANY 0x2 + +/* AND with flags to see if any mapping has occurred */ + +#define POLICY_DATA_FLAG_MAP_MASK 0x3 + +/* qualifiers are shared and shouldn't be freed */ + +#define POLICY_DATA_FLAG_SHARED_QUALIFIERS 0x4 + +/* Parent node is an extra node and should be freed */ + +#define POLICY_DATA_FLAG_EXTRA_NODE 0x8 + +/* Corresponding CertificatePolicies is critical */ + +#define POLICY_DATA_FLAG_CRITICAL 0x10 + +/* This structure is an entry from a table of mapped policies which + * cross reference the policy it refers to. + */ + +struct X509_POLICY_REF_st + { + ASN1_OBJECT *subjectDomainPolicy; + const X509_POLICY_DATA *data; + }; + +/* This structure is cached with a certificate */ + +struct X509_POLICY_CACHE_st { + /* anyPolicy data or NULL if no anyPolicy */ + X509_POLICY_DATA *anyPolicy; + /* other policy data */ + STACK_OF(X509_POLICY_DATA) *data; + /* If policyMappings extension present a table of mapped policies */ + STACK_OF(POLICY_REF) *maps; + /* If InhibitAnyPolicy present this is its value or -1 if absent. */ + long any_skip; + /* If policyConstraints and requireExplicitPolicy present this is its + * value or -1 if absent. + */ + long explicit_skip; + /* If policyConstraints and policyMapping present this is its + * value or -1 if absent. + */ + long map_skip; + }; + +/*#define POLICY_CACHE_FLAG_CRITICAL POLICY_DATA_FLAG_CRITICAL*/ + +/* This structure represents the relationship between nodes */ + +struct X509_POLICY_NODE_st + { + /* node data this refers to */ + const X509_POLICY_DATA *data; + /* Parent node */ + X509_POLICY_NODE *parent; + /* Number of child nodes */ + int nchild; + }; + +struct X509_POLICY_LEVEL_st + { + /* Cert for this level */ + X509 *cert; + /* nodes at this level */ + STACK_OF(X509_POLICY_NODE) *nodes; + /* anyPolicy node */ + X509_POLICY_NODE *anyPolicy; + /* Extra data */ + /*STACK_OF(X509_POLICY_DATA) *extra_data;*/ + unsigned int flags; + }; + +struct X509_POLICY_TREE_st + { + /* This is the tree 'level' data */ + X509_POLICY_LEVEL *levels; + int nlevel; + /* Extra policy data when additional nodes (not from the certificate) + * are required. + */ + STACK_OF(X509_POLICY_DATA) *extra_data; + /* This is the authority constained policy set */ + STACK_OF(X509_POLICY_NODE) *auth_policies; + STACK_OF(X509_POLICY_NODE) *user_policies; + unsigned int flags; + }; + +/* Set if anyPolicy present in user policies */ +#define POLICY_FLAG_ANY_POLICY 0x2 + +/* Useful macros */ + +#define node_critical(node) ((node)->data->flags & POLICY_DATA_FLAG_CRITICAL) + +/* Internal functions */ + +X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, ASN1_OBJECT *id, + int crit); +void policy_data_free(X509_POLICY_DATA *data); + +X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id); +int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps); + + +STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void); + +void policy_cache_init(void); + +X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, + const ASN1_OBJECT *id); + +X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_TREE) *sk, + const ASN1_OBJECT *id); + +X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + const X509_POLICY_DATA *data, + X509_POLICY_NODE *parent, + X509_POLICY_TREE *tree); +void policy_node_free(X509_POLICY_NODE *node); + +const X509_POLICY_CACHE *policy_cache_set(X509 *x); diff --git a/crypto/x509v3/pcy_lib.c b/crypto/x509v3/pcy_lib.c new file mode 100644 index 0000000000..b56739e672 --- /dev/null +++ b/crypto/x509v3/pcy_lib.c @@ -0,0 +1,165 @@ +/* pcy_lib.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + +#include "cryptlib.h" +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "pcy_int.h" + +/* accessor functions */ + +/* X509_POLICY_TREE stuff */ + +int X509_policy_tree_level_count(const X509_POLICY_TREE *tree) + { + if (!tree) + return 0; + return tree->nlevel; + } + +X509_POLICY_LEVEL * + X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i) + { + if (!tree || (i < 0) || (i >= tree->nlevel)) + return NULL; + return tree->levels + i; + } + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree) + { + if (!tree) + return NULL; + return tree->auth_policies; + } + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree) + { + if (!tree) + return NULL; + if (tree->flags & POLICY_FLAG_ANY_POLICY) + return tree->auth_policies; + else + return tree->user_policies; + } + +/* X509_POLICY_LEVEL stuff */ + +int X509_policy_level_node_count(X509_POLICY_LEVEL *level) + { + int n; + if (!level) + return 0; + if (level->anyPolicy) + n = 1; + else + n = 0; + if (level->nodes) + n += sk_X509_POLICY_NODE_num(level->nodes); + return n; + } + +X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i) + { + if (!level) + return NULL; + if (level->anyPolicy) + { + if (i == 0) + return level->anyPolicy; + i--; + } + return sk_X509_POLICY_NODE_value(level->nodes, i); + } + +/* X509_POLICY_NODE stuff */ + +const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->data->valid_policy; + } + +int X509_policy_node_get_critical(const X509_POLICY_NODE *node) + { + if (node_critical(node)) + return 1; + return 0; + } + +STACK_OF(POLICYQUALIFIER) * + X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->data->qualifier_set; + } + +const X509_POLICY_NODE * + X509_policy_node_get0_parent(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->parent; + } + + diff --git a/crypto/x509v3/pcy_map.c b/crypto/x509v3/pcy_map.c new file mode 100644 index 0000000000..fe934e27b8 --- /dev/null +++ b/crypto/x509v3/pcy_map.c @@ -0,0 +1,186 @@ +/* pcy_map.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include "cryptlib.h" +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "pcy_int.h" + +static int ref_cmp(void *pa, void *pb) + { + X509_POLICY_REF **a = pa; X509_POLICY_REF **b = pb; + return OBJ_cmp((*a)->subjectDomainPolicy, (*b)->subjectDomainPolicy); + } + +static void policy_map_free(X509_POLICY_REF *map) + { + if (map->subjectDomainPolicy) + ASN1_OBJECT_free(map->subjectDomainPolicy); + OPENSSL_free(map); + } + +X509_POLICY_REF *policy_map_find(X509_POLICY_CACHE *cache, ASN1_OBJECT *id) + { + X509_POLICY_REF tmp; + int idx; + tmp.subjectDomainPolicy = id; + + idx = sk_X509_POLICY_REF_find(cache->maps, &tmp); + if (idx == -1) + return NULL; + return sk_X509_POLICY_REF_value(cache->maps, idx); + } + +/* Set policy mapping entries in cache. + * Note: this modifies the passed POLICY_MAPPINGS structure + */ + +int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps) + { + POLICY_MAPPING *map; + X509_POLICY_REF *ref = NULL; + X509_POLICY_DATA *data; + X509_POLICY_CACHE *cache = x->policy_cache; + int i; + int ret = 0; + if (sk_POLICY_MAPPING_num(maps) == 0) + { + ret = -1; + goto bad_mapping; + } + cache->maps = sk_X509_POLICY_REF_new(ref_cmp); + for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++) + { + map = sk_POLICY_MAPPING_value(maps, i); + /* Reject if map to or from anyPolicy */ + if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy) + || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy)) + { + ret = -1; + goto bad_mapping; + } + + /* If we've already mapped from this OID bad mapping */ + if (policy_map_find(cache, map->subjectDomainPolicy) != NULL) + { + ret = -1; + goto bad_mapping; + } + + /* Attempt to find matching policy data */ + data = policy_cache_find_data(cache, map->issuerDomainPolicy); + /* If we don't have anyPolicy can't map */ + if (!data && !cache->anyPolicy) + continue; + + /* Create a NODE from anyPolicy */ + if (!data) + { + data = policy_data_new(NULL, map->issuerDomainPolicy, + cache->anyPolicy->flags + & POLICY_DATA_FLAG_CRITICAL); + if (!data) + goto bad_mapping; + data->qualifier_set = cache->anyPolicy->qualifier_set; + map->issuerDomainPolicy = NULL; + data->flags |= POLICY_DATA_FLAG_MAPPED_ANY; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!sk_X509_POLICY_DATA_push(cache->data, data)) + { + policy_data_free(data); + goto bad_mapping; + } + } + else + data->flags |= POLICY_DATA_FLAG_MAPPED; + + if (!sk_ASN1_OBJECT_push(data->expected_policy_set, + map->subjectDomainPolicy)) + goto bad_mapping; + + ref = OPENSSL_malloc(sizeof(X509_POLICY_REF)); + if (!ref) + goto bad_mapping; + + ref->subjectDomainPolicy = map->subjectDomainPolicy; + map->subjectDomainPolicy = NULL; + ref->data = data; + + if (!sk_X509_POLICY_REF_push(cache->maps, ref)) + goto bad_mapping; + + ref = NULL; + + } + + ret = 1; + bad_mapping: + if (ret == -1) + x->ex_flags |= EXFLAG_INVALID_POLICY; + if (ref) + policy_map_free(ref); + if (ret <= 0) + { + sk_X509_POLICY_REF_pop_free(cache->maps, policy_map_free); + cache->maps = NULL; + } + sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free); + return ret; + + } diff --git a/crypto/x509v3/pcy_node.c b/crypto/x509v3/pcy_node.c new file mode 100644 index 0000000000..3d6bd34cc5 --- /dev/null +++ b/crypto/x509v3/pcy_node.c @@ -0,0 +1,159 @@ +/* pcy_node.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include <memory.h> +#include <openssl/asn1.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "pcy_int.h" + +static int node_cmp(void *pa, void *pb) + { + X509_POLICY_NODE **a = pa, **b = pb; + return OBJ_cmp((*a)->data->valid_policy, (*b)->data->valid_policy); + } + +STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void) + { + return sk_X509_POLICY_NODE_new(node_cmp); + } + +X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *nodes, + const ASN1_OBJECT *id) + { + X509_POLICY_DATA n; + X509_POLICY_NODE l; + int idx; + + n.valid_policy = (ASN1_OBJECT *)id; + l.data = &n; + + idx = sk_X509_POLICY_NODE_find(nodes, &l); + if (idx == -1) + return NULL; + + return sk_X509_POLICY_NODE_value(nodes, idx); + + } + +X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, + const ASN1_OBJECT *id) + { + return tree_find_sk(level->nodes, id); + } + +X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + const X509_POLICY_DATA *data, + X509_POLICY_NODE *parent, + X509_POLICY_TREE *tree) + { + X509_POLICY_NODE *node; + node = OPENSSL_malloc(sizeof(X509_POLICY_NODE)); + if (!node) + return NULL; + node->data = data; + node->parent = parent; + node->nchild = 0; + if (level) + { + if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) + { + if (level->anyPolicy) + goto node_error; + level->anyPolicy = node; + } + else + { + + if (!level->nodes) + level->nodes = policy_node_cmp_new(); + if (!level->nodes) + goto node_error; + if (!sk_X509_POLICY_NODE_push(level->nodes, node)) + goto node_error; + } + } + + if (tree) + { + if (!tree->extra_data) + tree->extra_data = sk_X509_POLICY_DATA_new_null(); + if (!tree->extra_data) + goto node_error; + if (!sk_X509_POLICY_DATA_push(tree->extra_data, data)) + goto node_error; + } + + if (parent) + parent->nchild++; + + return node; + + node_error: + policy_node_free(node); + return 0; + + } + +void policy_node_free(X509_POLICY_NODE *node) + { + OPENSSL_free(node); + } + + diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c new file mode 100644 index 0000000000..16cacde0c4 --- /dev/null +++ b/crypto/x509v3/pcy_tree.c @@ -0,0 +1,681 @@ +/* pcy_tree.c */ +/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include "cryptlib.h" +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "pcy_int.h" + +/* Initialize policy tree. Return values: + * 0 Some internal error occured. + * -1 Inconsistent or invalid extensions in certificates. + * 1 Tree initialized OK. + * 2 Policy tree is empty. + * 5 Tree OK and requireExplicitPolicy true. + * 6 Tree empty and requireExplicitPolicy true. + */ + +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + 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; + *ptree = NULL; + n = sk_X509_num(certs); + int explicit_policy; + int any_skip; + int map_skip; + + /* 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. + */ + +static int tree_link_nodes(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache) + { + int i; + X509_POLICY_LEVEL *last; + X509_POLICY_DATA *data; + X509_POLICY_NODE *parent; + last = curr - 1; + for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) + { + data = sk_X509_POLICY_DATA_value(cache->data, i); + /* If a node is mapped any it doesn't have a corresponding + * CertificatePolicies entry. + * However such an identical node would be created + * if anyPolicy matching is enabled because there would be + * no match with the parent valid_policy_set. So we create + * link because then it will have the mapping flags + * right and we can prune it later. + */ + if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY) + && !(curr->flags & X509_V_FLAG_INHIBIT_ANY)) + continue; + /* Look for matching node in parent */ + parent = level_find_node(last, data->valid_policy); + /* If no match link to anyPolicy */ + if (!parent) + parent = last->anyPolicy; + if (parent && !level_add_node(curr, data, parent, NULL)) + return 0; + } + return 1; + } + +/* This corresponds to RFC3280 XXXX XXXXX: + * Create new data for any unmatched policies in the parent and link + * to anyPolicy. + */ + +static int tree_link_any(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache, + X509_POLICY_TREE *tree) + { + int i; + X509_POLICY_DATA *data; + X509_POLICY_NODE *node; + X509_POLICY_LEVEL *last; + + last = curr - 1; + + for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(last->nodes, i); + + /* Skip any node with any children: we only want unmathced + * nodes. + * + * Note: need something better for policy mapping + * because each node may have multiple children + */ + if (node->nchild) + continue; + /* Create a new node with qualifiers from anyPolicy and + * id from unmatched node. + */ + data = policy_data_new(NULL, node->data->valid_policy, + node_critical(node)); + + if (data == NULL) + return 0; + data->qualifier_set = curr->anyPolicy->data->qualifier_set; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!level_add_node(curr, data, node, tree)) + { + policy_data_free(data); + return 0; + } + } + /* Finally add link to anyPolicy */ + if (last->anyPolicy) + { + if (!level_add_node(curr, cache->anyPolicy, + last->anyPolicy, NULL)) + return 0; + } + return 1; + } + +/* Prune the tree: delete any child mapped child data on the current level + * then proceed up the tree deleting any data with no children. If we ever + * have no data on a level we can halt because the tree will be empty. + */ + +static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr) + { + X509_POLICY_NODE *node; + int i; + for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--) + { + node = sk_X509_POLICY_NODE_value(curr->nodes, i); + /* Delete any mapped data: see RFC3280 XXXX */ + if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) + { + node->parent->nchild--; + OPENSSL_free(node); + sk_X509_POLICY_NODE_delete(curr->nodes, i); + } + } + + for(;;) { + --curr; + for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--) + { + node = sk_X509_POLICY_NODE_value(curr->nodes, i); + if (node->nchild == 0) + { + node->parent->nchild--; + OPENSSL_free(node); + sk_X509_POLICY_NODE_delete(curr->nodes, i); + } + } + if (curr->anyPolicy && !curr->anyPolicy->nchild) + { + if (curr->anyPolicy->parent) + curr->anyPolicy->parent->nchild--; + OPENSSL_free(curr->anyPolicy); + curr->anyPolicy = NULL; + } + if (curr == tree->levels) + { + /* If we zapped anyPolicy at top then tree is empty */ + if (!curr->anyPolicy) + return 2; + return 1; + } + } + + return 1; + + } + +static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes, + X509_POLICY_NODE *pcy) + { + if (!*pnodes) + { + *pnodes = policy_node_cmp_new(); + if (!*pnodes) + return 0; + } + else if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1) + return 1; + + if (!sk_X509_POLICY_NODE_push(*pnodes, pcy)) + return 0; + + return 1; + + } + +/* Calculate the authority set based on policy tree. + * The 'pnodes' parameter is used as a store for the set of policy nodes + * used to calculate the user set. If the authority set is not anyPolicy + * then pnodes will just point to the authority set. If however the authority + * set is anyPolicy then the set of valid policies (other than anyPolicy) + * is store in pnodes. The return value of '2' is used in this case to indicate + * that pnodes should be freed. + */ + +static int tree_calculate_authority_set(X509_POLICY_TREE *tree, + STACK_OF(X509_POLICY_NODES) **pnodes) + { + X509_POLICY_LEVEL *curr; + X509_POLICY_NODE *node, *anyptr; + STACK_OF(X509_POLICY_NODES) **addnodes; + int i, j; + curr = tree->levels + tree->nlevel - 1; + + /* If last level contains anyPolicy set is anyPolicy */ + if (curr->anyPolicy) + { + if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy)) + return 0; + addnodes = pnodes; + } + else + /* Add policies to authority set */ + addnodes = &tree->auth_policies; + + curr = tree->levels; + for (i = 1; i < tree->nlevel; i++) + { + /* If no anyPolicy node on this this level it can't + * appear on lower levels so end search. + */ + if (!(anyptr = curr->anyPolicy)) + break; + curr++; + for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) + { + node = sk_X509_POLICY_NODE_value(curr->nodes, j); + if ((node->parent == anyptr) + && !tree_add_auth_node(addnodes, node)) + return 0; + } + } + + if (addnodes == pnodes) + return 2; + + *pnodes = tree->auth_policies; + + return 1; + } + +static int tree_calculate_user_set(X509_POLICY_TREE *tree, + STACK_OF(ASN1_OBJECT) *policy_oids, + STACK_OF(X509_POLICY_NODE) *auth_nodes) + { + int i; + X509_POLICY_NODE *node; + ASN1_OBJECT *oid; + + X509_POLICY_NODE *anyPolicy; + X509_POLICY_DATA *extra; + + /* Check if anyPolicy present in authority constrained policy set: + * this will happen if it is a leaf node. + */ + + if (sk_ASN1_OBJECT_num(policy_oids) <= 0) + return 1; + + anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy; + + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) + { + oid = sk_ASN1_OBJECT_value(policy_oids, i); + if (OBJ_obj2nid(oid) == NID_any_policy) + { + tree->flags |= POLICY_FLAG_ANY_POLICY; + return 1; + } + } + + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) + { + oid = sk_ASN1_OBJECT_value(policy_oids, i); + node = tree_find_sk(auth_nodes, oid); + if (!node) + { + if (!anyPolicy) + continue; + /* Create a new node with policy ID from user set + * and qualifiers from anyPolicy. + */ + extra = policy_data_new(NULL, oid, + node_critical(anyPolicy)); + if (!extra) + return 0; + extra->qualifier_set = anyPolicy->data->qualifier_set; + extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS + | POLICY_DATA_FLAG_EXTRA_NODE; + node = level_add_node(NULL, extra, anyPolicy->parent, + tree); + } + if (!tree->user_policies) + { + tree->user_policies = sk_X509_POLICY_NODE_new_null(); + if (!tree->user_policies) + return 1; + } + if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) + return 0; + } + return 1; + + } + +static int tree_evaluate(X509_POLICY_TREE *tree) + { + int ret, i; + X509_POLICY_LEVEL *curr = tree->levels + 1; + const X509_POLICY_CACHE *cache; + + for(i = 1; i < tree->nlevel; i++, curr++) + { + cache = policy_cache_set(curr->cert); + if (!tree_link_nodes(curr, cache)) + return 0; + + if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) + && !tree_link_any(curr, cache, tree)) + return 0; + ret = tree_prune(tree, curr); + if (ret != 1) + return ret; + } + + return 1; + + } + +static void exnode_free(X509_POLICY_NODE *node) + { + if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE)) + OPENSSL_free(node); + } + + +void X509_policy_tree_free(X509_POLICY_TREE *tree) + { + X509_POLICY_LEVEL *curr; + int i; + + if (!tree) + return; + + sk_X509_POLICY_NODE_free(tree->auth_policies); + sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free); + + for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) + { + if (curr->cert) + X509_free(curr->cert); + if (curr->nodes) + sk_X509_POLICY_NODE_pop_free(curr->nodes, + policy_node_free); + if (curr->anyPolicy) + policy_node_free(curr->anyPolicy); + } + + if (tree->extra_data) + sk_X509_POLICY_DATA_pop_free(tree->extra_data, + policy_data_free); + + OPENSSL_free(tree->levels); + OPENSSL_free(tree); + + } + +/* Application policy checking function. + * Return codes: + * 0 Internal Error. + * 1 Successful. + * -1 One or more certificates contain invalid or inconsistent extensions + * -2 User constrained policy set empty and requireExplicit true. + */ + +int X509_policy_check(X509_POLICY_TREE **ptree, int *explicit, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags) + { + int ret; + X509_POLICY_TREE *tree = NULL; + STACK_OF(X509_NODE) *nodes, *auth_nodes = NULL; + *ptree = NULL; + + *explicit = 0; + ret = tree_init(&tree, certs, flags); + + + switch (ret) + { + + /* Tree empty requireExplicit False: OK */ + case 2: + return 1; + + /* Some internal error */ + case 0: + return 0; + + /* Tree empty requireExplicit True: Error */ + + case 6: + *explicit = 1; + return -2; + + /* Tree OK requireExplicit True: OK and continue */ + case 5: + *explicit = 1; + break; + + /* Tree OK: continue */ + + case 1: + break; + } + + ret = tree_evaluate(tree); + + if (ret <= 0) + goto error; + + /* Return value 2 means tree empty */ + if (ret == 2) + { + X509_policy_tree_free(tree); + if (*explicit) + return -2; + else + return 1; + } + + /* Tree is not empty: continue */ + + ret = tree_calculate_authority_set(tree, &auth_nodes); + + if (!ret) + goto error; + + if (!tree_calculate_user_set(tree, policy_oids, auth_nodes)) + goto error; + + if (ret == 2) + sk_X509_POLICY_NODE_free(auth_nodes); + + if (tree) + *ptree = tree; + + if (*explicit) + { + nodes = X509_policy_tree_get0_user_policies(tree); + if (sk_X509_POLICY_NODE_num(nodes) <= 0) + return -2; + } + + return 1; + + error: + + X509_policy_tree_free(tree); + + return 0; + + } + diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h index ec4df61bb8..d3c06f581d 100644 --- a/crypto/x509v3/x509v3.h +++ b/crypto/x509v3/x509v3.h @@ -352,6 +352,8 @@ typedef struct POLICY_CONSTRAINTS_st { #define EXFLAG_SET 0x100 #define EXFLAG_CRITICAL 0x200 +#define EXFLAG_INVALID_POLICY 0x400 + #define KU_DIGITAL_SIGNATURE 0x0080 #define KU_NON_REPUDIATION 0x0040 #define KU_KEY_ENCIPHERMENT 0x0020 |