Initial support for certificate policy checking and evaluation.
authorDr. Stephen Henson <steve@openssl.org>
Tue, 23 Mar 2004 14:14:35 +0000 (14:14 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Tue, 23 Mar 2004 14:14:35 +0000 (14:14 +0000)
This is currently *very* experimental and needs to be more fully integrated
with the main verification code.

15 files changed:
CHANGES
crypto/asn1/x_x509.c
crypto/ossl_typ.h
crypto/stack/safestack.h
crypto/x509/x509.h
crypto/x509/x509_vfy.h
crypto/x509v3/Makefile.ssl
crypto/x509v3/pcy_cache.c [new file with mode: 0644]
crypto/x509v3/pcy_data.c [new file with mode: 0644]
crypto/x509v3/pcy_int.h [new file with mode: 0644]
crypto/x509v3/pcy_lib.c [new file with mode: 0644]
crypto/x509v3/pcy_map.c [new file with mode: 0644]
crypto/x509v3/pcy_node.c [new file with mode: 0644]
crypto/x509v3/pcy_tree.c [new file with mode: 0644]
crypto/x509v3/x509v3.h

diff --git a/CHANGES b/CHANGES
index 5677cb7..aebf096 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@
 
  Changes between 0.9.7c and 0.9.8  [xx XXX xxxx]
 
+  *) Preliminary support for certificate policy evaluation and checking. This
+     is initially intended to pass the tests outlined in "Conformance Testing
+     of Relying Party Client Certificate Path Processing Logic" v1.07.
+     [Steve Henson]
+
   *) bn_dup_expand() has been deprecated, it was introduced in 0.9.7 and
      remained unused and not that useful. A variety of other little bignum
      tweaks and fixes have also been made continuing on from the audit (see
index f71ba26..eff2290 100644 (file)
@@ -79,6 +79,8 @@ ASN1_SEQUENCE(X509_CINF) = {
 IMPLEMENT_ASN1_FUNCTIONS(X509_CINF)
 /* X509 top level structure needs a bit of customisation */
 
+extern void policy_cache_free(X509_POLICY_CACHE *cache);
+
 static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it)
 {
        X509 *ret = (X509 *)*pval;
@@ -106,6 +108,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it)
                X509_CERT_AUX_free(ret->aux);
                ASN1_OCTET_STRING_free(ret->skid);
                AUTHORITY_KEYID_free(ret->akid);
+               policy_cache_free(ret->policy_cache);
 
                if (ret->name != NULL) OPENSSL_free(ret->name);
                break;
index 46200a8..2977b10 100644 (file)
@@ -119,6 +119,11 @@ typedef struct conf_st CONF;
 
 typedef struct engine_st ENGINE;
 
+typedef struct X509_POLICY_NODE_st X509_POLICY_NODE;
+typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL;
+typedef struct X509_POLICY_TREE_st X509_POLICY_TREE;
+typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE;
+
   /* If placed in pkcs12.h, we end up with a circular depency with pkcs7.h */
 #define DECLARE_PKCS12_STACK_OF(type) /* Nothing */
 #define IMPLEMENT_PKCS12_STACK_OF(type) /* Nothing */
index 3110e50..cd9e780 100644 (file)
@@ -1359,6 +1359,69 @@ STACK_OF(type) \
 #define sk_X509_OBJECT_pop(st) SKM_sk_pop(X509_OBJECT, (st))
 #define sk_X509_OBJECT_sort(st) SKM_sk_sort(X509_OBJECT, (st))
 
+#define sk_X509_POLICY_DATA_new(st) SKM_sk_new(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_new_null() SKM_sk_new_null(X509_POLICY_DATA)
+#define sk_X509_POLICY_DATA_free(st) SKM_sk_free(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_num(st) SKM_sk_num(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_value(st, i) SKM_sk_value(X509_POLICY_DATA, (st), (i))
+#define sk_X509_POLICY_DATA_set(st, i, val) SKM_sk_set(X509_POLICY_DATA, (st), (i), (val))
+#define sk_X509_POLICY_DATA_zero(st) SKM_sk_zero(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_push(st, val) SKM_sk_push(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_unshift(st, val) SKM_sk_unshift(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_find(st, val) SKM_sk_find(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_delete(st, i) SKM_sk_delete(X509_POLICY_DATA, (st), (i))
+#define sk_X509_POLICY_DATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_DATA, (st), (ptr))
+#define sk_X509_POLICY_DATA_insert(st, val, i) SKM_sk_insert(X509_POLICY_DATA, (st), (val), (i))
+#define sk_X509_POLICY_DATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_DATA, (st), (cmp))
+#define sk_X509_POLICY_DATA_dup(st) SKM_sk_dup(X509_POLICY_DATA, st)
+#define sk_X509_POLICY_DATA_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_DATA, (st), (free_func))
+#define sk_X509_POLICY_DATA_shift(st) SKM_sk_shift(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_pop(st) SKM_sk_pop(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_sort(st) SKM_sk_sort(X509_POLICY_DATA, (st))
+
+#define sk_X509_POLICY_NODE_new(st) SKM_sk_new(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_new_null() SKM_sk_new_null(X509_POLICY_NODE)
+#define sk_X509_POLICY_NODE_free(st) SKM_sk_free(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_num(st) SKM_sk_num(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_value(st, i) SKM_sk_value(X509_POLICY_NODE, (st), (i))
+#define sk_X509_POLICY_NODE_set(st, i, val) SKM_sk_set(X509_POLICY_NODE, (st), (i), (val))
+#define sk_X509_POLICY_NODE_zero(st) SKM_sk_zero(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_push(st, val) SKM_sk_push(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_unshift(st, val) SKM_sk_unshift(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_find(st, val) SKM_sk_find(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_delete(st, i) SKM_sk_delete(X509_POLICY_NODE, (st), (i))
+#define sk_X509_POLICY_NODE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_NODE, (st), (ptr))
+#define sk_X509_POLICY_NODE_insert(st, val, i) SKM_sk_insert(X509_POLICY_NODE, (st), (val), (i))
+#define sk_X509_POLICY_NODE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_NODE, (st), (cmp))
+#define sk_X509_POLICY_NODE_dup(st) SKM_sk_dup(X509_POLICY_NODE, st)
+#define sk_X509_POLICY_NODE_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_NODE, (st), (free_func))
+#define sk_X509_POLICY_NODE_shift(st) SKM_sk_shift(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_pop(st) SKM_sk_pop(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_sort(st) SKM_sk_sort(X509_POLICY_NODE, (st))
+
+#define sk_X509_POLICY_REF_new(st) SKM_sk_new(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_new_null() SKM_sk_new_null(X509_POLICY_REF)
+#define sk_X509_POLICY_REF_free(st) SKM_sk_free(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_num(st) SKM_sk_num(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_value(st, i) SKM_sk_value(X509_POLICY_REF, (st), (i))
+#define sk_X509_POLICY_REF_set(st, i, val) SKM_sk_set(X509_POLICY_REF, (st), (i), (val))
+#define sk_X509_POLICY_REF_zero(st) SKM_sk_zero(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_push(st, val) SKM_sk_push(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_unshift(st, val) SKM_sk_unshift(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_find(st, val) SKM_sk_find(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_delete(st, i) SKM_sk_delete(X509_POLICY_REF, (st), (i))
+#define sk_X509_POLICY_REF_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_REF, (st), (ptr))
+#define sk_X509_POLICY_REF_insert(st, val, i) SKM_sk_insert(X509_POLICY_REF, (st), (val), (i))
+#define sk_X509_POLICY_REF_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_REF, (st), (cmp))
+#define sk_X509_POLICY_REF_dup(st) SKM_sk_dup(X509_POLICY_REF, st)
+#define sk_X509_POLICY_REF_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_REF, (st), (free_func))
+#define sk_X509_POLICY_REF_shift(st) SKM_sk_shift(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_pop(st) SKM_sk_pop(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_sort(st) SKM_sk_sort(X509_POLICY_REF, (st))
+
 #define sk_X509_PURPOSE_new(st) SKM_sk_new(X509_PURPOSE, (st))
 #define sk_X509_PURPOSE_new_null() SKM_sk_new_null(X509_PURPOSE)
 #define sk_X509_PURPOSE_free(st) SKM_sk_free(X509_PURPOSE, (st))
index e7d2c5b..b73a699 100644 (file)
@@ -285,6 +285,7 @@ struct x509_st
        unsigned long ex_nscert;
        ASN1_OCTET_STRING *skid;
        struct AUTHORITY_KEYID_st *akid;
+       X509_POLICY_CACHE *policy_cache;
 #ifndef OPENSSL_NO_SHA
        unsigned char sha1_hash[SHA_DIGEST_LENGTH];
 #endif
index 7e24ded..6cf3d70 100644 (file)
@@ -325,6 +325,14 @@ struct x509_store_ctx_st      /* X509_STORE_CTX */
 #define        X509_V_FLAG_IGNORE_CRITICAL             0x10
 /* Disable workarounds for broken certificates */
 #define        X509_V_FLAG_X509_STRICT                 0x20
+/* Enable policy checking */
+#define X509_V_FLAG_POLICY_CHECK               0x40
+/* Policy variable require-explicit-policy */
+#define X509_V_FLAG_EXPLICIT_POLICY            0x80
+/* Policy variable inhibit-policy-mapping */
+#define        X509_V_FLAG_INHIBIT_ANY                 0x100
+/* Policy variable inhibit-any-policy */
+#define X509_V_FLAG_INHIBIT_MAP                        0x200
 
 int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
             X509_NAME *name);
@@ -410,6 +418,36 @@ void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, long flags, time_t t);
 void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
                                  int (*verify_cb)(int, X509_STORE_CTX *));
 
+int X509_policy_check(X509_POLICY_TREE **ptree, int *explicit,
+                       STACK_OF(X509) *certs,
+                       STACK_OF(ASN1_OBJECT) *policy_oids,
+                       unsigned int flags);
+
+void X509_policy_tree_free(X509_POLICY_TREE *tree);
+
+int X509_policy_tree_level_count(const X509_POLICY_TREE *tree);
+X509_POLICY_LEVEL *
+       X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i);
+
+STACK_OF(X509_POLICY_NODE) *
+       X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree);
+
+STACK_OF(X509_POLICY_NODE) *
+       X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree);
+
+int X509_policy_level_node_count(X509_POLICY_LEVEL *level);
+
+X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i);
+
+const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node);
+
+STACK_OF(POLICYQUALIFIER) *
+       X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node);
+const X509_POLICY_NODE *
+       X509_policy_node_get0_parent(const X509_POLICY_NODE *node);
+
+void X509_policy_lib_init(void);
+
 #ifdef  __cplusplus
 }
 #endif
index e29f366..ab13173 100644 (file)
@@ -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 (file)
index 0000000..23d930d
--- /dev/null
@@ -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 (file)
index 0000000..fae74ca
--- /dev/null
@@ -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 (file)
index 0000000..6568988
--- /dev/null
@@ -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 (file)
index 0000000..b56739e
--- /dev/null
@@ -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 (file)
index 0000000..fe934e2
--- /dev/null
@@ -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 (file)
index 0000000..3d6bd34
--- /dev/null
@@ -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 (file)
index 0000000..16cacde
--- /dev/null
@@ -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;
+
+       }
+
index ec4df61..d3c06f5 100644 (file)
@@ -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