Initial support for certificate policy checking and evaluation.

This is currently *very* experimental and needs to be more fully integrated
with the main verification code.
This commit is contained in:
Dr. Stephen Henson 2004-03-23 14:14:35 +00:00
parent 9449e38504
commit 4acc3e907d
15 changed files with 1942 additions and 3 deletions

View File

@ -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

View 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;

View 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 */

View 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))

View 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

View 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

View 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)

286
crypto/x509v3/pcy_cache.c Normal file
View File

@ -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;
}

123
crypto/x509v3/pcy_data.c Normal file
View File

@ -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;
}

220
crypto/x509v3/pcy_int.h Normal file
View File

@ -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);

165
crypto/x509v3/pcy_lib.c Normal file
View File

@ -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;
}

186
crypto/x509v3/pcy_map.c Normal file
View File

@ -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;
}

159
crypto/x509v3/pcy_node.c Normal file
View File

@ -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);
}

681
crypto/x509v3/pcy_tree.c Normal file
View File

@ -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;
}

View 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