1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

Upgrade openssl from 1.1.0e to 1.1.1b, with source code. 4.0.78

This commit is contained in:
winlin 2021-03-01 20:47:57 +08:00
parent 8f1c992379
commit 96dbd7bced
1476 changed files with 616554 additions and 4 deletions

View file

@ -0,0 +1,8 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
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_akeya.c v3_pmaps.c v3_pcons.c v3_ncons.c v3_pcia.c v3_pci.c \
pcy_cache.c pcy_node.c pcy_data.c pcy_map.c pcy_tree.c pcy_lib.c \
v3_asid.c v3_addr.c v3_tlsf.c v3_admis.c

View file

@ -0,0 +1,25 @@
/*
* Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
int name_cmp(const char *name, const char *cmp);
extern const X509V3_EXT_METHOD v3_bcons, v3_nscert, v3_key_usage, v3_ext_ku;
extern const X509V3_EXT_METHOD v3_pkey_usage_period, v3_sxnet, v3_info, v3_sinfo;
extern const X509V3_EXT_METHOD v3_ns_ia5_list[8], v3_alt[3], v3_skey_id, v3_akey_id;
extern const X509V3_EXT_METHOD v3_crl_num, v3_crl_reason, v3_crl_invdate;
extern const X509V3_EXT_METHOD v3_delta_crl, v3_cpols, v3_crld, v3_freshest_crl;
extern const X509V3_EXT_METHOD v3_ocsp_nonce, v3_ocsp_accresp, v3_ocsp_acutoff;
extern const X509V3_EXT_METHOD v3_ocsp_crlid, v3_ocsp_nocheck, v3_ocsp_serviceloc;
extern const X509V3_EXT_METHOD v3_crl_hold, v3_pci;
extern const X509V3_EXT_METHOD v3_policy_mappings, v3_policy_constraints;
extern const X509V3_EXT_METHOD v3_name_constraints, v3_inhibit_anyp, v3_idp;
extern const X509V3_EXT_METHOD v3_addr, v3_asid;
extern const X509V3_EXT_METHOD v3_ct_scts[3];
extern const X509V3_EXT_METHOD v3_tls_feature;
extern const X509V3_EXT_METHOD v3_ext_admission;

View file

@ -0,0 +1,224 @@
/*
* Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/cryptlib.h"
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "internal/x509_int.h"
#include "pcy_int.h"
static int policy_data_cmp(const X509_POLICY_DATA *const *a,
const X509_POLICY_DATA *const *b);
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, num, ret = 0;
X509_POLICY_CACHE *cache = x->policy_cache;
X509_POLICY_DATA *data = NULL;
POLICYINFO *policy;
if ((num = sk_POLICYINFO_num(policies)) <= 0)
goto bad_policy;
cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp);
if (cache->data == NULL) {
X509V3err(X509V3_F_POLICY_CACHE_CREATE, ERR_R_MALLOC_FAILURE);
goto just_cleanup;
}
for (i = 0; i < num; i++) {
policy = sk_POLICYINFO_value(policies, i);
data = policy_data_new(policy, NULL, crit);
if (data == NULL) {
X509V3err(X509V3_F_POLICY_CACHE_CREATE, ERR_R_MALLOC_FAILURE);
goto just_cleanup;
}
/*
* 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) >=0 ) {
ret = -1;
goto bad_policy;
} else if (!sk_X509_POLICY_DATA_push(cache->data, data)) {
X509V3err(X509V3_F_POLICY_CACHE_CREATE, ERR_R_MALLOC_FAILURE);
goto bad_policy;
}
data = NULL;
}
ret = 1;
bad_policy:
if (ret == -1)
x->ex_flags |= EXFLAG_INVALID_POLICY;
policy_data_free(data);
just_cleanup:
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;
if (x->policy_cache != NULL)
return 1;
cache = OPENSSL_malloc(sizeof(*cache));
if (cache == NULL) {
X509V3err(X509V3_F_POLICY_CACHE_NEW, ERR_R_MALLOC_FAILURE);
return 0;
}
cache->anyPolicy = NULL;
cache->data = 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;
goto just_cleanup;
bad_cache:
x->ex_flags |= EXFLAG_INVALID_POLICY;
just_cleanup:
POLICY_CONSTRAINTS_free(ext_pcons);
ASN1_INTEGER_free(ext_any);
return 1;
}
void policy_cache_free(X509_POLICY_CACHE *cache)
{
if (!cache)
return;
policy_data_free(cache->anyPolicy);
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_THREAD_write_lock(x->lock);
policy_cache_new(x);
CRYPTO_THREAD_unlock(x->lock);
}
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);
return sk_X509_POLICY_DATA_value(cache->data, idx);
}
static int policy_data_cmp(const X509_POLICY_DATA *const *a,
const X509_POLICY_DATA *const *b)
{
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;
}

View file

@ -0,0 +1,81 @@
/*
* Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/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)
{
if (data == NULL)
return;
ASN1_OBJECT_free(data->valid_policy);
/* Don't free qualifiers if shared */
if (!(data->flags & POLICY_DATA_FLAG_SHARED_QUALIFIERS))
sk_POLICYQUALINFO_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 CertificatePolicies extension and
* additional data with just the qualifiers of anyPolicy and ID from another
* source.
*/
X509_POLICY_DATA *policy_data_new(POLICYINFO *policy,
const ASN1_OBJECT *cid, int crit)
{
X509_POLICY_DATA *ret;
ASN1_OBJECT *id;
if (policy == NULL && cid == NULL)
return NULL;
if (cid) {
id = OBJ_dup(cid);
if (id == NULL)
return NULL;
} else
id = NULL;
ret = OPENSSL_zalloc(sizeof(*ret));
if (ret == NULL) {
X509V3err(X509V3_F_POLICY_DATA_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
ret->expected_policy_set = sk_ASN1_OBJECT_new_null();
if (ret->expected_policy_set == NULL) {
OPENSSL_free(ret);
ASN1_OBJECT_free(id);
X509V3err(X509V3_F_POLICY_DATA_NEW, ERR_R_MALLOC_FAILURE);
return NULL;
}
if (crit)
ret->flags = POLICY_DATA_FLAG_CRITICAL;
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;
}
return ret;
}

View file

@ -0,0 +1,167 @@
/*
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
typedef struct X509_POLICY_DATA_st X509_POLICY_DATA;
DEFINE_STACK_OF(X509_POLICY_DATA)
/* 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(POLICYQUALINFO) *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 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 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 constrained 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_data_critical(data) (data->flags & POLICY_DATA_FLAG_CRITICAL)
#define node_critical(node) node_data_critical(node->data)
/* Internal functions */
X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, const 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);
void policy_cache_free(X509_POLICY_CACHE *cache);
X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level,
const X509_POLICY_NODE *parent,
const ASN1_OBJECT *id);
X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk,
const ASN1_OBJECT *id);
X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
X509_POLICY_DATA *data,
X509_POLICY_NODE *parent,
X509_POLICY_TREE *tree);
void policy_node_free(X509_POLICY_NODE *node);
int policy_node_match(const X509_POLICY_LEVEL *lvl,
const X509_POLICY_NODE *node, const ASN1_OBJECT *oid);
const X509_POLICY_CACHE *policy_cache_set(X509 *x);

View file

@ -0,0 +1,108 @@
/*
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/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;
}
STACK_OF(POLICYQUALINFO) *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;
}

View file

@ -0,0 +1,81 @@
/*
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/cryptlib.h"
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "internal/x509_int.h"
#include "pcy_int.h"
/*
* 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_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;
}
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;
}
/* 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 == NULL && !cache->anyPolicy)
continue;
/* Create a NODE from anyPolicy */
if (data == NULL) {
data = policy_data_new(NULL, map->issuerDomainPolicy,
cache->anyPolicy->flags
& POLICY_DATA_FLAG_CRITICAL);
if (data == NULL)
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;
map->subjectDomainPolicy = NULL;
}
ret = 1;
bad_mapping:
if (ret == -1)
x->ex_flags |= EXFLAG_INVALID_POLICY;
sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free);
return ret;
}

View file

@ -0,0 +1,147 @@
/*
* Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "pcy_int.h"
static int node_cmp(const X509_POLICY_NODE *const *a,
const X509_POLICY_NODE *const *b)
{
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);
return sk_X509_POLICY_NODE_value(nodes, idx);
}
X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level,
const X509_POLICY_NODE *parent,
const ASN1_OBJECT *id)
{
X509_POLICY_NODE *node;
int i;
for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) {
node = sk_X509_POLICY_NODE_value(level->nodes, i);
if (node->parent == parent) {
if (!OBJ_cmp(node->data->valid_policy, id))
return node;
}
}
return NULL;
}
X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
X509_POLICY_DATA *data,
X509_POLICY_NODE *parent,
X509_POLICY_TREE *tree)
{
X509_POLICY_NODE *node;
node = OPENSSL_zalloc(sizeof(*node));
if (node == NULL) {
X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE);
return NULL;
}
node->data = data;
node->parent = parent;
if (level) {
if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
if (level->anyPolicy)
goto node_error;
level->anyPolicy = node;
} else {
if (level->nodes == NULL)
level->nodes = policy_node_cmp_new();
if (level->nodes == NULL) {
X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE);
goto node_error;
}
if (!sk_X509_POLICY_NODE_push(level->nodes, node)) {
X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE);
goto node_error;
}
}
}
if (tree) {
if (tree->extra_data == NULL)
tree->extra_data = sk_X509_POLICY_DATA_new_null();
if (tree->extra_data == NULL){
X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE);
goto node_error;
}
if (!sk_X509_POLICY_DATA_push(tree->extra_data, data)) {
X509V3err(X509V3_F_LEVEL_ADD_NODE, ERR_R_MALLOC_FAILURE);
goto node_error;
}
}
if (parent)
parent->nchild++;
return node;
node_error:
policy_node_free(node);
return NULL;
}
void policy_node_free(X509_POLICY_NODE *node)
{
OPENSSL_free(node);
}
/*
* See if a policy node matches a policy OID. If mapping enabled look through
* expected policy set otherwise just valid policy.
*/
int policy_node_match(const X509_POLICY_LEVEL *lvl,
const X509_POLICY_NODE *node, const ASN1_OBJECT *oid)
{
int i;
ASN1_OBJECT *policy_oid;
const X509_POLICY_DATA *x = node->data;
if ((lvl->flags & X509_V_FLAG_INHIBIT_MAP)
|| !(x->flags & POLICY_DATA_FLAG_MAP_MASK)) {
if (!OBJ_cmp(x->valid_policy, oid))
return 1;
return 0;
}
for (i = 0; i < sk_ASN1_OBJECT_num(x->expected_policy_set); i++) {
policy_oid = sk_ASN1_OBJECT_value(x->expected_policy_set, i);
if (!OBJ_cmp(policy_oid, oid))
return 1;
}
return 0;
}

View file

@ -0,0 +1,703 @@
/*
* Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/cryptlib.h"
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "pcy_int.h"
/*
* Enable this to print out the complete policy tree at various point during
* evaluation.
*/
/*
* #define OPENSSL_POLICY_DEBUG
*/
#ifdef OPENSSL_POLICY_DEBUG
static void expected_print(BIO *err, X509_POLICY_LEVEL *lev,
X509_POLICY_NODE *node, int indent)
{
if ((lev->flags & X509_V_FLAG_INHIBIT_MAP)
|| !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK))
BIO_puts(err, " Not Mapped\n");
else {
int i;
STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set;
ASN1_OBJECT *oid;
BIO_puts(err, " Expected: ");
for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) {
oid = sk_ASN1_OBJECT_value(pset, i);
if (i)
BIO_puts(err, ", ");
i2a_ASN1_OBJECT(err, oid);
}
BIO_puts(err, "\n");
}
}
static void tree_print(char *str, X509_POLICY_TREE *tree,
X509_POLICY_LEVEL *curr)
{
BIO *err = BIO_new_fp(stderr, BIO_NOCLOSE);
X509_POLICY_LEVEL *plev;
if (err == NULL)
return;
if (!curr)
curr = tree->levels + tree->nlevel;
else
curr++;
BIO_printf(err, "Level print after %s\n", str);
BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels);
for (plev = tree->levels; plev != curr; plev++) {
int i;
BIO_printf(err, "Level %ld, flags = %x\n",
(long)(plev - tree->levels), plev->flags);
for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) {
X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(plev->nodes, i);
X509_POLICY_NODE_print(err, node, 2);
expected_print(err, plev, node, 2);
BIO_printf(err, " Flags: %x\n", node->data->flags);
}
if (plev->anyPolicy)
X509_POLICY_NODE_print(err, plev->anyPolicy, 2);
}
BIO_free(err);
}
#endif
/*-
* Return value: <= 0 on error, or positive bit mask:
*
* X509_PCY_TREE_VALID: valid tree
* X509_PCY_TREE_EMPTY: empty tree (including bare TA case)
* X509_PCY_TREE_EXPLICIT: explicit policy required
*/
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;
int ret = X509_PCY_TREE_VALID;
int n = sk_X509_num(certs) - 1; /* RFC5280 paths omit the TA */
int explicit_policy = (flags & X509_V_FLAG_EXPLICIT_POLICY) ? 0 : n+1;
int any_skip = (flags & X509_V_FLAG_INHIBIT_ANY) ? 0 : n+1;
int map_skip = (flags & X509_V_FLAG_INHIBIT_MAP) ? 0 : n+1;
int i;
*ptree = NULL;
/* Can't do anything with just a trust anchor */
if (n == 0)
return X509_PCY_TREE_EMPTY;
/*
* First setup the policy cache in all n non-TA certificates, this will be
* used in X509_verify_cert() which will invoke the verify callback for all
* certificates with invalid policy extensions.
*/
for (i = n - 1; i >= 0; i--) {
X509 *x = sk_X509_value(certs, i);
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, 0);
/* If cache is NULL, likely ENOMEM: return immediately */
if (policy_cache_set(x) == NULL)
return X509_PCY_TREE_INTERNAL;
}
/*
* At this point check for invalid policies and required explicit policy.
* Note that the explicit_policy counter is a count-down to zero, with the
* requirement kicking in if and once it does that. The counter is
* decremented for every non-self-issued certificate in the path, but may
* be further reduced by policy constraints in a non-leaf certificate.
*
* The ultimate policy set is the intersection of all the policies along
* the path, if we hit a certificate with an empty policy set, and explicit
* policy is required we're done.
*/
for (i = n - 1;
i >= 0 && (explicit_policy > 0 || (ret & X509_PCY_TREE_EMPTY) == 0);
i--) {
X509 *x = sk_X509_value(certs, i);
uint32_t ex_flags = X509_get_extension_flags(x);
/* All the policies are already cached, we can return early */
if (ex_flags & EXFLAG_INVALID_POLICY)
return X509_PCY_TREE_INVALID;
/* Access the cache which we now know exists */
cache = policy_cache_set(x);
if ((ret & X509_PCY_TREE_VALID) && cache->data == NULL)
ret = X509_PCY_TREE_EMPTY;
if (explicit_policy > 0) {
if (!(ex_flags & EXFLAG_SI))
explicit_policy--;
if ((cache->explicit_skip >= 0)
&& (cache->explicit_skip < explicit_policy))
explicit_policy = cache->explicit_skip;
}
}
if (explicit_policy == 0)
ret |= X509_PCY_TREE_EXPLICIT;
if ((ret & X509_PCY_TREE_VALID) == 0)
return ret;
/* If we get this far initialize the tree */
if ((tree = OPENSSL_zalloc(sizeof(*tree))) == NULL) {
X509V3err(X509V3_F_TREE_INIT, ERR_R_MALLOC_FAILURE);
return X509_PCY_TREE_INTERNAL;
}
/*
* http://tools.ietf.org/html/rfc5280#section-6.1.2, figure 3.
*
* The top level is implicitly for the trust anchor with valid expected
* policies of anyPolicy. (RFC 5280 has the TA at depth 0 and the leaf at
* depth n, we have the leaf at depth 0 and the TA at depth n).
*/
if ((tree->levels = OPENSSL_zalloc(sizeof(*tree->levels)*(n+1))) == NULL) {
OPENSSL_free(tree);
X509V3err(X509V3_F_TREE_INIT, ERR_R_MALLOC_FAILURE);
return X509_PCY_TREE_INTERNAL;
}
tree->nlevel = n+1;
level = tree->levels;
if ((data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0)) == NULL)
goto bad_tree;
if (level_add_node(level, data, NULL, tree) == NULL) {
policy_data_free(data);
goto bad_tree;
}
/*
* In this pass initialize all the tree levels and whether anyPolicy and
* policy mapping are inhibited at each level.
*/
for (i = n - 1; i >= 0; i--) {
X509 *x = sk_X509_value(certs, i);
uint32_t ex_flags = X509_get_extension_flags(x);
/* Access the cache which we now know exists */
cache = policy_cache_set(x);
X509_up_ref(x);
(++level)->cert = x;
if (!cache->anyPolicy)
level->flags |= X509_V_FLAG_INHIBIT_ANY;
/* Determine inhibit any and inhibit map flags */
if (any_skip == 0) {
/*
* Any matching allowed only if certificate is self issued and not
* the last in the chain.
*/
if (!(ex_flags & EXFLAG_SI) || (i == 0))
level->flags |= X509_V_FLAG_INHIBIT_ANY;
} else {
if (!(ex_flags & EXFLAG_SI))
any_skip--;
if ((cache->any_skip >= 0) && (cache->any_skip < any_skip))
any_skip = cache->any_skip;
}
if (map_skip == 0)
level->flags |= X509_V_FLAG_INHIBIT_MAP;
else {
if (!(ex_flags & EXFLAG_SI))
map_skip--;
if ((cache->map_skip >= 0) && (cache->map_skip < map_skip))
map_skip = cache->map_skip;
}
}
*ptree = tree;
return ret;
bad_tree:
X509_policy_tree_free(tree);
return X509_PCY_TREE_INTERNAL;
}
/*
* Return value: 1 on success, 0 otherwise
*/
static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
X509_POLICY_DATA *data)
{
X509_POLICY_LEVEL *last = curr - 1;
int i, matched = 0;
/* Iterate through all in nodes linking matches */
for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) {
X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(last->nodes, i);
if (policy_node_match(last, node, data->valid_policy)) {
if (level_add_node(curr, data, node, NULL) == NULL)
return 0;
matched = 1;
}
}
if (!matched && last->anyPolicy) {
if (level_add_node(curr, data, last->anyPolicy, NULL) == NULL)
return 0;
}
return 1;
}
/*
* This corresponds to RFC3280 6.1.3(d)(1): link any data from
* CertificatePolicies onto matching parent or anyPolicy if no match.
*
* Return value: 1 on success, 0 otherwise.
*/
static int tree_link_nodes(X509_POLICY_LEVEL *curr,
const X509_POLICY_CACHE *cache)
{
int i;
for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) {
X509_POLICY_DATA *data = sk_X509_POLICY_DATA_value(cache->data, i);
/* Look for matching nodes in previous level */
if (!tree_link_matching_nodes(curr, data))
return 0;
}
return 1;
}
/*
* This corresponds to RFC3280 6.1.3(d)(2): Create new data for any unmatched
* policies in the parent and link to anyPolicy.
*
* Return value: 1 on success, 0 otherwise.
*/
static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
const X509_POLICY_CACHE *cache,
const ASN1_OBJECT *id,
X509_POLICY_NODE *node, X509_POLICY_TREE *tree)
{
X509_POLICY_DATA *data;
if (id == NULL)
id = node->data->valid_policy;
/*
* Create a new node with qualifiers from anyPolicy and id from unmatched
* node.
*/
if ((data = policy_data_new(NULL, id, node_critical(node))) == NULL)
return 0;
/* Curr may not have anyPolicy */
data->qualifier_set = cache->anyPolicy->qualifier_set;
data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
if (level_add_node(curr, data, node, tree) == NULL) {
policy_data_free(data);
return 0;
}
return 1;
}
/*
* Return value: 1 on success, 0 otherwise.
*/
static int tree_link_unmatched(X509_POLICY_LEVEL *curr,
const X509_POLICY_CACHE *cache,
X509_POLICY_NODE *node, X509_POLICY_TREE *tree)
{
const X509_POLICY_LEVEL *last = curr - 1;
int i;
if ((last->flags & X509_V_FLAG_INHIBIT_MAP)
|| !(node->data->flags & POLICY_DATA_FLAG_MAPPED)) {
/* If no policy mapping: matched if one child present */
if (node->nchild)
return 1;
if (!tree_add_unmatched(curr, cache, NULL, node, tree))
return 0;
/* Add it */
} else {
/* If mapping: matched if one child per expected policy set */
STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set;
if (node->nchild == sk_ASN1_OBJECT_num(expset))
return 1;
/* Locate unmatched nodes */
for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++) {
ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i);
if (level_find_node(curr, node, oid))
continue;
if (!tree_add_unmatched(curr, cache, oid, node, tree))
return 0;
}
}
return 1;
}
/*
* Return value: 1 on success, 0 otherwise
*/
static int tree_link_any(X509_POLICY_LEVEL *curr,
const X509_POLICY_CACHE *cache,
X509_POLICY_TREE *tree)
{
int i;
X509_POLICY_NODE *node;
X509_POLICY_LEVEL *last = curr - 1;
for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) {
node = sk_X509_POLICY_NODE_value(last->nodes, i);
if (!tree_link_unmatched(curr, cache, node, tree))
return 0;
}
/* Finally add link to anyPolicy */
if (last->anyPolicy &&
level_add_node(curr, cache->anyPolicy, last->anyPolicy, NULL) == 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.
*
* Return value: <= 0 error, otherwise one of:
*
* X509_PCY_TREE_VALID: valid tree
* X509_PCY_TREE_EMPTY: empty tree
*/
static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
{
STACK_OF(X509_POLICY_NODE) *nodes;
X509_POLICY_NODE *node;
int i;
nodes = curr->nodes;
if (curr->flags & X509_V_FLAG_INHIBIT_MAP) {
for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) {
node = sk_X509_POLICY_NODE_value(nodes, i);
/* Delete any mapped data: see RFC3280 XXXX */
if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) {
node->parent->nchild--;
OPENSSL_free(node);
(void)sk_X509_POLICY_NODE_delete(nodes, i);
}
}
}
for (;;) {
--curr;
nodes = curr->nodes;
for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) {
node = sk_X509_POLICY_NODE_value(nodes, i);
if (node->nchild == 0) {
node->parent->nchild--;
OPENSSL_free(node);
(void)sk_X509_POLICY_NODE_delete(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 X509_PCY_TREE_EMPTY;
break;
}
}
return X509_PCY_TREE_VALID;
}
/*
* Return value: 1 on success, 0 otherwise.
*/
static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes,
X509_POLICY_NODE *pcy)
{
if (*pnodes == NULL &&
(*pnodes = policy_node_cmp_new()) == NULL)
return 0;
if (sk_X509_POLICY_NODE_find(*pnodes, pcy) >= 0)
return 1;
return sk_X509_POLICY_NODE_push(*pnodes, pcy) != 0;
}
#define TREE_CALC_FAILURE 0
#define TREE_CALC_OK_NOFREE 1
#define TREE_CALC_OK_DOFREE 2
/*-
* 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.
*
* Return value:
* TREE_CALC_FAILURE on failure,
* TREE_CALC_OK_NOFREE on success and pnodes need not be freed,
* TREE_CALC_OK_DOFREE on success and pnodes needs to be freed
*/
static int tree_calculate_authority_set(X509_POLICY_TREE *tree,
STACK_OF(X509_POLICY_NODE) **pnodes)
{
X509_POLICY_LEVEL *curr;
X509_POLICY_NODE *node, *anyptr;
STACK_OF(X509_POLICY_NODE) **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 TREE_CALC_FAILURE;
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) == NULL)
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)) {
if (addnodes == pnodes) {
sk_X509_POLICY_NODE_free(*pnodes);
*pnodes = NULL;
}
return TREE_CALC_FAILURE;
}
}
}
if (addnodes == pnodes)
return TREE_CALC_OK_DOFREE;
*pnodes = tree->auth_policies;
return TREE_CALC_OK_NOFREE;
}
/*
* Return value: 1 on success, 0 otherwise.
*/
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 == NULL)
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;
}
/*-
* Return value: <= 0 error, otherwise one of:
* X509_PCY_TREE_VALID: valid tree
* X509_PCY_TREE_EMPTY: empty tree
* (see tree_prune()).
*/
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 X509_PCY_TREE_INTERNAL;
if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
&& !tree_link_any(curr, cache, tree))
return X509_PCY_TREE_INTERNAL;
#ifdef OPENSSL_POLICY_DEBUG
tree_print("before tree_prune()", tree, curr);
#endif
ret = tree_prune(tree, curr);
if (ret != X509_PCY_TREE_VALID)
return ret;
}
return X509_PCY_TREE_VALID;
}
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++) {
X509_free(curr->cert);
sk_X509_POLICY_NODE_pop_free(curr->nodes, policy_node_free);
policy_node_free(curr->anyPolicy);
}
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:
* X509_PCY_TREE_FAILURE: Failure to satisfy explicit policy
* X509_PCY_TREE_INVALID: Inconsistent or invalid extensions
* X509_PCY_TREE_INTERNAL: Internal error, most likely malloc
* X509_PCY_TREE_VALID: Success (null tree if empty or bare TA)
*/
int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
STACK_OF(X509) *certs,
STACK_OF(ASN1_OBJECT) *policy_oids, unsigned int flags)
{
int init_ret;
int ret;
int calc_ret;
X509_POLICY_TREE *tree = NULL;
STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL;
*ptree = NULL;
*pexplicit_policy = 0;
init_ret = tree_init(&tree, certs, flags);
if (init_ret <= 0)
return init_ret;
if ((init_ret & X509_PCY_TREE_EXPLICIT) == 0) {
if (init_ret & X509_PCY_TREE_EMPTY) {
X509_policy_tree_free(tree);
return X509_PCY_TREE_VALID;
}
} else {
*pexplicit_policy = 1;
/* Tree empty and requireExplicit True: Error */
if (init_ret & X509_PCY_TREE_EMPTY)
return X509_PCY_TREE_FAILURE;
}
ret = tree_evaluate(tree);
#ifdef OPENSSL_POLICY_DEBUG
tree_print("tree_evaluate()", tree, NULL);
#endif
if (ret <= 0)
goto error;
if (ret == X509_PCY_TREE_EMPTY) {
X509_policy_tree_free(tree);
if (init_ret & X509_PCY_TREE_EXPLICIT)
return X509_PCY_TREE_FAILURE;
return X509_PCY_TREE_VALID;
}
/* Tree is not empty: continue */
if ((calc_ret = tree_calculate_authority_set(tree, &auth_nodes)) == 0)
goto error;
ret = tree_calculate_user_set(tree, policy_oids, auth_nodes);
if (calc_ret == TREE_CALC_OK_DOFREE)
sk_X509_POLICY_NODE_free(auth_nodes);
if (!ret)
goto error;
*ptree = tree;
if (init_ret & X509_PCY_TREE_EXPLICIT) {
nodes = X509_policy_tree_get0_user_policies(tree);
if (sk_X509_POLICY_NODE_num(nodes) <= 0)
return X509_PCY_TREE_FAILURE;
}
return X509_PCY_TREE_VALID;
error:
X509_policy_tree_free(tree);
return X509_PCY_TREE_INTERNAL;
}

View file

@ -0,0 +1,78 @@
/*
* Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* This table will be searched using OBJ_bsearch so it *must* kept in order
* of the ext_nid values.
*/
static const X509V3_EXT_METHOD *standard_exts[] = {
&v3_nscert,
&v3_ns_ia5_list[0],
&v3_ns_ia5_list[1],
&v3_ns_ia5_list[2],
&v3_ns_ia5_list[3],
&v3_ns_ia5_list[4],
&v3_ns_ia5_list[5],
&v3_ns_ia5_list[6],
&v3_skey_id,
&v3_key_usage,
&v3_pkey_usage_period,
&v3_alt[0],
&v3_alt[1],
&v3_bcons,
&v3_crl_num,
&v3_cpols,
&v3_akey_id,
&v3_crld,
&v3_ext_ku,
&v3_delta_crl,
&v3_crl_reason,
#ifndef OPENSSL_NO_OCSP
&v3_crl_invdate,
#endif
&v3_sxnet,
&v3_info,
#ifndef OPENSSL_NO_RFC3779
&v3_addr,
&v3_asid,
#endif
#ifndef OPENSSL_NO_OCSP
&v3_ocsp_nonce,
&v3_ocsp_crlid,
&v3_ocsp_accresp,
&v3_ocsp_nocheck,
&v3_ocsp_acutoff,
&v3_ocsp_serviceloc,
#endif
&v3_sinfo,
&v3_policy_constraints,
#ifndef OPENSSL_NO_OCSP
&v3_crl_hold,
#endif
&v3_pci,
&v3_name_constraints,
&v3_policy_mappings,
&v3_inhibit_anyp,
&v3_idp,
&v3_alt[2],
&v3_freshest_crl,
#ifndef OPENSSL_NO_CT
&v3_ct_scts[0],
&v3_ct_scts[1],
&v3_ct_scts[2],
#endif
&v3_tls_feature,
&v3_ext_admission
};
/* Number of standard extensions */
#define STANDARD_EXTENSION_COUNT OSSL_NELEM(standard_exts)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,356 @@
/*
* Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/ossl_typ.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include <openssl/safestack.h>
#include "v3_admis.h"
#include "ext_dat.h"
ASN1_SEQUENCE(NAMING_AUTHORITY) = {
ASN1_OPT(NAMING_AUTHORITY, namingAuthorityId, ASN1_OBJECT),
ASN1_OPT(NAMING_AUTHORITY, namingAuthorityUrl, ASN1_IA5STRING),
ASN1_OPT(NAMING_AUTHORITY, namingAuthorityText, DIRECTORYSTRING),
} ASN1_SEQUENCE_END(NAMING_AUTHORITY)
ASN1_SEQUENCE(PROFESSION_INFO) = {
ASN1_EXP_OPT(PROFESSION_INFO, namingAuthority, NAMING_AUTHORITY, 0),
ASN1_SEQUENCE_OF(PROFESSION_INFO, professionItems, DIRECTORYSTRING),
ASN1_SEQUENCE_OF_OPT(PROFESSION_INFO, professionOIDs, ASN1_OBJECT),
ASN1_OPT(PROFESSION_INFO, registrationNumber, ASN1_PRINTABLESTRING),
ASN1_OPT(PROFESSION_INFO, addProfessionInfo, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(PROFESSION_INFO)
ASN1_SEQUENCE(ADMISSIONS) = {
ASN1_EXP_OPT(ADMISSIONS, admissionAuthority, GENERAL_NAME, 0),
ASN1_EXP_OPT(ADMISSIONS, namingAuthority, NAMING_AUTHORITY, 1),
ASN1_SEQUENCE_OF(ADMISSIONS, professionInfos, PROFESSION_INFO),
} ASN1_SEQUENCE_END(ADMISSIONS)
ASN1_SEQUENCE(ADMISSION_SYNTAX) = {
ASN1_OPT(ADMISSION_SYNTAX, admissionAuthority, GENERAL_NAME),
ASN1_SEQUENCE_OF(ADMISSION_SYNTAX, contentsOfAdmissions, ADMISSIONS),
} ASN1_SEQUENCE_END(ADMISSION_SYNTAX)
IMPLEMENT_ASN1_FUNCTIONS(NAMING_AUTHORITY)
IMPLEMENT_ASN1_FUNCTIONS(PROFESSION_INFO)
IMPLEMENT_ASN1_FUNCTIONS(ADMISSIONS)
IMPLEMENT_ASN1_FUNCTIONS(ADMISSION_SYNTAX)
static int i2r_ADMISSION_SYNTAX(const struct v3_ext_method *method, void *in,
BIO *bp, int ind);
const X509V3_EXT_METHOD v3_ext_admission = {
NID_x509ExtAdmission, /* .ext_nid = */
0, /* .ext_flags = */
ASN1_ITEM_ref(ADMISSION_SYNTAX), /* .it = */
NULL, NULL, NULL, NULL,
NULL, /* .i2s = */
NULL, /* .s2i = */
NULL, /* .i2v = */
NULL, /* .v2i = */
&i2r_ADMISSION_SYNTAX, /* .i2r = */
NULL, /* .r2i = */
NULL /* extension-specific data */
};
static int i2r_NAMING_AUTHORITY(const struct v3_ext_method *method, void *in,
BIO *bp, int ind)
{
NAMING_AUTHORITY * namingAuthority = (NAMING_AUTHORITY*) in;
if (namingAuthority == NULL)
return 0;
if (namingAuthority->namingAuthorityId == NULL
&& namingAuthority->namingAuthorityText == NULL
&& namingAuthority->namingAuthorityUrl == NULL)
return 0;
if (BIO_printf(bp, "%*snamingAuthority: ", ind, "") <= 0)
goto err;
if (namingAuthority->namingAuthorityId != NULL) {
char objbuf[128];
const char *ln = OBJ_nid2ln(OBJ_obj2nid(namingAuthority->namingAuthorityId));
if (BIO_printf(bp, "%*s admissionAuthorityId: ", ind, "") <= 0)
goto err;
OBJ_obj2txt(objbuf, sizeof(objbuf), namingAuthority->namingAuthorityId, 1);
if (BIO_printf(bp, "%s%s%s%s\n", ln ? ln : "",
ln ? " (" : "", objbuf, ln ? ")" : "") <= 0)
goto err;
}
if (namingAuthority->namingAuthorityText != NULL) {
if (BIO_printf(bp, "%*s namingAuthorityText: ", ind, "") <= 0
|| ASN1_STRING_print(bp, namingAuthority->namingAuthorityText) <= 0
|| BIO_printf(bp, "\n") <= 0)
goto err;
}
if (namingAuthority->namingAuthorityUrl != NULL ) {
if (BIO_printf(bp, "%*s namingAuthorityUrl: ", ind, "") <= 0
|| ASN1_STRING_print(bp, namingAuthority->namingAuthorityUrl) <= 0
|| BIO_printf(bp, "\n") <= 0)
goto err;
}
return 1;
err:
return 0;
}
static int i2r_ADMISSION_SYNTAX(const struct v3_ext_method *method, void *in,
BIO *bp, int ind)
{
ADMISSION_SYNTAX * admission = (ADMISSION_SYNTAX *)in;
int i, j, k;
if (admission->admissionAuthority != NULL) {
if (BIO_printf(bp, "%*sadmissionAuthority:\n", ind, "") <= 0
|| BIO_printf(bp, "%*s ", ind, "") <= 0
|| GENERAL_NAME_print(bp, admission->admissionAuthority) <= 0
|| BIO_printf(bp, "\n") <= 0)
goto err;
}
for (i = 0; i < sk_ADMISSIONS_num(admission->contentsOfAdmissions); i++) {
ADMISSIONS* entry = sk_ADMISSIONS_value(admission->contentsOfAdmissions, i);
if (BIO_printf(bp, "%*sEntry %0d:\n", ind, "", 1 + i) <= 0) goto err;
if (entry->admissionAuthority != NULL) {
if (BIO_printf(bp, "%*s admissionAuthority:\n", ind, "") <= 0
|| BIO_printf(bp, "%*s ", ind, "") <= 0
|| GENERAL_NAME_print(bp, entry->admissionAuthority) <= 0
|| BIO_printf(bp, "\n") <= 0)
goto err;
}
if (entry->namingAuthority != NULL) {
if (i2r_NAMING_AUTHORITY(method, entry->namingAuthority, bp, ind) <= 0)
goto err;
}
for (j = 0; j < sk_PROFESSION_INFO_num(entry->professionInfos); j++) {
PROFESSION_INFO* pinfo = sk_PROFESSION_INFO_value(entry->professionInfos, j);
if (BIO_printf(bp, "%*s Profession Info Entry %0d:\n", ind, "", 1 + j) <= 0)
goto err;
if (pinfo->registrationNumber != NULL) {
if (BIO_printf(bp, "%*s registrationNumber: ", ind, "") <= 0
|| ASN1_STRING_print(bp, pinfo->registrationNumber) <= 0
|| BIO_printf(bp, "\n") <= 0)
goto err;
}
if (pinfo->namingAuthority != NULL) {
if (i2r_NAMING_AUTHORITY(method, pinfo->namingAuthority, bp, ind + 2) <= 0)
goto err;
}
if (pinfo->professionItems != NULL) {
if (BIO_printf(bp, "%*s Info Entries:\n", ind, "") <= 0)
goto err;
for (k = 0; k < sk_ASN1_STRING_num(pinfo->professionItems); k++) {
ASN1_STRING* val = sk_ASN1_STRING_value(pinfo->professionItems, k);
if (BIO_printf(bp, "%*s ", ind, "") <= 0
|| ASN1_STRING_print(bp, val) <= 0
|| BIO_printf(bp, "\n") <= 0)
goto err;
}
}
if (pinfo->professionOIDs != NULL) {
if (BIO_printf(bp, "%*s Profession OIDs:\n", ind, "") <= 0)
goto err;
for (k = 0; k < sk_ASN1_OBJECT_num(pinfo->professionOIDs); k++) {
ASN1_OBJECT* obj = sk_ASN1_OBJECT_value(pinfo->professionOIDs, k);
const char *ln = OBJ_nid2ln(OBJ_obj2nid(obj));
char objbuf[128];
OBJ_obj2txt(objbuf, sizeof(objbuf), obj, 1);
if (BIO_printf(bp, "%*s %s%s%s%s\n", ind, "",
ln ? ln : "", ln ? " (" : "",
objbuf, ln ? ")" : "") <= 0)
goto err;
}
}
}
}
return 1;
err:
return -1;
}
const ASN1_OBJECT *NAMING_AUTHORITY_get0_authorityId(const NAMING_AUTHORITY *n)
{
return n->namingAuthorityId;
}
void NAMING_AUTHORITY_set0_authorityId(NAMING_AUTHORITY *n, ASN1_OBJECT* id)
{
ASN1_OBJECT_free(n->namingAuthorityId);
n->namingAuthorityId = id;
}
const ASN1_IA5STRING *NAMING_AUTHORITY_get0_authorityURL(
const NAMING_AUTHORITY *n)
{
return n->namingAuthorityUrl;
}
void NAMING_AUTHORITY_set0_authorityURL(NAMING_AUTHORITY *n, ASN1_IA5STRING* u)
{
ASN1_IA5STRING_free(n->namingAuthorityUrl);
n->namingAuthorityUrl = u;
}
const ASN1_STRING *NAMING_AUTHORITY_get0_authorityText(
const NAMING_AUTHORITY *n)
{
return n->namingAuthorityText;
}
void NAMING_AUTHORITY_set0_authorityText(NAMING_AUTHORITY *n, ASN1_STRING* t)
{
ASN1_IA5STRING_free(n->namingAuthorityText);
n->namingAuthorityText = t;
}
const GENERAL_NAME *ADMISSION_SYNTAX_get0_admissionAuthority(const ADMISSION_SYNTAX *as)
{
return as->admissionAuthority;
}
void ADMISSION_SYNTAX_set0_admissionAuthority(ADMISSION_SYNTAX *as,
GENERAL_NAME *aa)
{
GENERAL_NAME_free(as->admissionAuthority);
as->admissionAuthority = aa;
}
const STACK_OF(ADMISSIONS) *ADMISSION_SYNTAX_get0_contentsOfAdmissions(const ADMISSION_SYNTAX *as)
{
return as->contentsOfAdmissions;
}
void ADMISSION_SYNTAX_set0_contentsOfAdmissions(ADMISSION_SYNTAX *as,
STACK_OF(ADMISSIONS) *a)
{
sk_ADMISSIONS_pop_free(as->contentsOfAdmissions, ADMISSIONS_free);
as->contentsOfAdmissions = a;
}
const GENERAL_NAME *ADMISSIONS_get0_admissionAuthority(const ADMISSIONS *a)
{
return a->admissionAuthority;
}
void ADMISSIONS_set0_admissionAuthority(ADMISSIONS *a, GENERAL_NAME *aa)
{
GENERAL_NAME_free(a->admissionAuthority);
a->admissionAuthority = aa;
}
const NAMING_AUTHORITY *ADMISSIONS_get0_namingAuthority(const ADMISSIONS *a)
{
return a->namingAuthority;
}
void ADMISSIONS_set0_namingAuthority(ADMISSIONS *a, NAMING_AUTHORITY *na)
{
NAMING_AUTHORITY_free(a->namingAuthority);
a->namingAuthority = na;
}
const PROFESSION_INFOS *ADMISSIONS_get0_professionInfos(const ADMISSIONS *a)
{
return a->professionInfos;
}
void ADMISSIONS_set0_professionInfos(ADMISSIONS *a, PROFESSION_INFOS *pi)
{
sk_PROFESSION_INFO_pop_free(a->professionInfos, PROFESSION_INFO_free);
a->professionInfos = pi;
}
const ASN1_OCTET_STRING *PROFESSION_INFO_get0_addProfessionInfo(const PROFESSION_INFO *pi)
{
return pi->addProfessionInfo;
}
void PROFESSION_INFO_set0_addProfessionInfo(PROFESSION_INFO *pi,
ASN1_OCTET_STRING *aos)
{
ASN1_OCTET_STRING_free(pi->addProfessionInfo);
pi->addProfessionInfo = aos;
}
const NAMING_AUTHORITY *PROFESSION_INFO_get0_namingAuthority(const PROFESSION_INFO *pi)
{
return pi->namingAuthority;
}
void PROFESSION_INFO_set0_namingAuthority(PROFESSION_INFO *pi,
NAMING_AUTHORITY *na)
{
NAMING_AUTHORITY_free(pi->namingAuthority);
pi->namingAuthority = na;
}
const STACK_OF(ASN1_STRING) *PROFESSION_INFO_get0_professionItems(const PROFESSION_INFO *pi)
{
return pi->professionItems;
}
void PROFESSION_INFO_set0_professionItems(PROFESSION_INFO *pi,
STACK_OF(ASN1_STRING) *as)
{
sk_ASN1_STRING_pop_free(pi->professionItems, ASN1_STRING_free);
pi->professionItems = as;
}
const STACK_OF(ASN1_OBJECT) *PROFESSION_INFO_get0_professionOIDs(const PROFESSION_INFO *pi)
{
return pi->professionOIDs;
}
void PROFESSION_INFO_set0_professionOIDs(PROFESSION_INFO *pi,
STACK_OF(ASN1_OBJECT) *po)
{
sk_ASN1_OBJECT_pop_free(pi->professionOIDs, ASN1_OBJECT_free);
pi->professionOIDs = po;
}
const ASN1_PRINTABLESTRING *PROFESSION_INFO_get0_registrationNumber(const PROFESSION_INFO *pi)
{
return pi->registrationNumber;
}
void PROFESSION_INFO_set0_registrationNumber(PROFESSION_INFO *pi,
ASN1_PRINTABLESTRING *rn)
{
ASN1_PRINTABLESTRING_free(pi->registrationNumber);
pi->registrationNumber = rn;
}

View file

@ -0,0 +1,38 @@
/*
* Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef HEADER_V3_ADMISSION_H
# define HEADER_V3_ADMISSION_H
struct NamingAuthority_st {
ASN1_OBJECT* namingAuthorityId;
ASN1_IA5STRING* namingAuthorityUrl;
ASN1_STRING* namingAuthorityText; /* i.e. DIRECTORYSTRING */
};
struct ProfessionInfo_st {
NAMING_AUTHORITY* namingAuthority;
STACK_OF(ASN1_STRING)* professionItems; /* i.e. DIRECTORYSTRING */
STACK_OF(ASN1_OBJECT)* professionOIDs;
ASN1_PRINTABLESTRING* registrationNumber;
ASN1_OCTET_STRING* addProfessionInfo;
};
struct Admissions_st {
GENERAL_NAME* admissionAuthority;
NAMING_AUTHORITY* namingAuthority;
STACK_OF(PROFESSION_INFO)* professionInfos;
};
struct AdmissionSyntax_st {
GENERAL_NAME* admissionAuthority;
STACK_OF(ADMISSIONS)* contentsOfAdmissions;
};
#endif

View file

@ -0,0 +1,160 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
AUTHORITY_KEYID *akeyid,
STACK_OF(CONF_VALUE)
*extlist);
static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *values);
const X509V3_EXT_METHOD v3_akey_id = {
NID_authority_key_identifier,
X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_KEYID),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V) i2v_AUTHORITY_KEYID,
(X509V3_EXT_V2I)v2i_AUTHORITY_KEYID,
0, 0,
NULL
};
static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
AUTHORITY_KEYID *akeyid,
STACK_OF(CONF_VALUE)
*extlist)
{
char *tmp;
if (akeyid->keyid) {
tmp = OPENSSL_buf2hexstr(akeyid->keyid->data, akeyid->keyid->length);
X509V3_add_value("keyid", tmp, &extlist);
OPENSSL_free(tmp);
}
if (akeyid->issuer)
extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist);
if (akeyid->serial) {
tmp = OPENSSL_buf2hexstr(akeyid->serial->data, akeyid->serial->length);
X509V3_add_value("serial", tmp, &extlist);
OPENSSL_free(tmp);
}
return extlist;
}
/*-
* Currently two options:
* keyid: use the issuers subject keyid, the value 'always' means its is
* an error if the issuer certificate doesn't have a key id.
* issuer: use the issuers cert issuer and serial number. The default is
* to only use this if keyid is not present. With the option 'always'
* this is always included.
*/
static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *values)
{
char keyid = 0, issuer = 0;
int i;
CONF_VALUE *cnf;
ASN1_OCTET_STRING *ikeyid = NULL;
X509_NAME *isname = NULL;
GENERAL_NAMES *gens = NULL;
GENERAL_NAME *gen = NULL;
ASN1_INTEGER *serial = NULL;
X509_EXTENSION *ext;
X509 *cert;
AUTHORITY_KEYID *akeyid;
for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
cnf = sk_CONF_VALUE_value(values, i);
if (strcmp(cnf->name, "keyid") == 0) {
keyid = 1;
if (cnf->value && strcmp(cnf->value, "always") == 0)
keyid = 2;
} else if (strcmp(cnf->name, "issuer") == 0) {
issuer = 1;
if (cnf->value && strcmp(cnf->value, "always") == 0)
issuer = 2;
} else {
X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, X509V3_R_UNKNOWN_OPTION);
ERR_add_error_data(2, "name=", cnf->name);
return NULL;
}
}
if (!ctx || !ctx->issuer_cert) {
if (ctx && (ctx->flags == CTX_TEST))
return AUTHORITY_KEYID_new();
X509V3err(X509V3_F_V2I_AUTHORITY_KEYID,
X509V3_R_NO_ISSUER_CERTIFICATE);
return NULL;
}
cert = ctx->issuer_cert;
if (keyid) {
i = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
if ((i >= 0) && (ext = X509_get_ext(cert, i)))
ikeyid = X509V3_EXT_d2i(ext);
if (keyid == 2 && !ikeyid) {
X509V3err(X509V3_F_V2I_AUTHORITY_KEYID,
X509V3_R_UNABLE_TO_GET_ISSUER_KEYID);
return NULL;
}
}
if ((issuer && !ikeyid) || (issuer == 2)) {
isname = X509_NAME_dup(X509_get_issuer_name(cert));
serial = ASN1_INTEGER_dup(X509_get_serialNumber(cert));
if (!isname || !serial) {
X509V3err(X509V3_F_V2I_AUTHORITY_KEYID,
X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS);
goto err;
}
}
if ((akeyid = AUTHORITY_KEYID_new()) == NULL)
goto err;
if (isname) {
if ((gens = sk_GENERAL_NAME_new_null()) == NULL
|| (gen = GENERAL_NAME_new()) == NULL
|| !sk_GENERAL_NAME_push(gens, gen)) {
X509V3err(X509V3_F_V2I_AUTHORITY_KEYID, ERR_R_MALLOC_FAILURE);
goto err;
}
gen->type = GEN_DIRNAME;
gen->d.dirn = isname;
}
akeyid->issuer = gens;
gen = NULL;
gens = NULL;
akeyid->serial = serial;
akeyid->keyid = ikeyid;
return akeyid;
err:
sk_GENERAL_NAME_free(gens);
GENERAL_NAME_free(gen);
X509_NAME_free(isname);
ASN1_INTEGER_free(serial);
ASN1_OCTET_STRING_free(ikeyid);
return NULL;
}

View file

@ -0,0 +1,23 @@
/*
* Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
ASN1_SEQUENCE(AUTHORITY_KEYID) = {
ASN1_IMP_OPT(AUTHORITY_KEYID, keyid, ASN1_OCTET_STRING, 0),
ASN1_IMP_SEQUENCE_OF_OPT(AUTHORITY_KEYID, issuer, GENERAL_NAME, 1),
ASN1_IMP_OPT(AUTHORITY_KEYID, serial, ASN1_INTEGER, 2)
} ASN1_SEQUENCE_END(AUTHORITY_KEYID)
IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_KEYID)

View file

@ -0,0 +1,592 @@
/*
* Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p);
static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens);
static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx);
const X509V3_EXT_METHOD v3_alt[3] = {
{NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V) i2v_GENERAL_NAMES,
(X509V3_EXT_V2I)v2i_subject_alt,
NULL, NULL, NULL},
{NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V) i2v_GENERAL_NAMES,
(X509V3_EXT_V2I)v2i_issuer_alt,
NULL, NULL, NULL},
{NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V) i2v_GENERAL_NAMES,
NULL, NULL, NULL, NULL},
};
STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
GENERAL_NAMES *gens,
STACK_OF(CONF_VALUE) *ret)
{
int i;
GENERAL_NAME *gen;
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
gen = sk_GENERAL_NAME_value(gens, i);
ret = i2v_GENERAL_NAME(method, gen, ret);
}
if (!ret)
return sk_CONF_VALUE_new_null();
return ret;
}
STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method,
GENERAL_NAME *gen,
STACK_OF(CONF_VALUE) *ret)
{
unsigned char *p;
char oline[256], htmp[5];
int i;
switch (gen->type) {
case GEN_OTHERNAME:
if (!X509V3_add_value("othername", "<unsupported>", &ret))
return NULL;
break;
case GEN_X400:
if (!X509V3_add_value("X400Name", "<unsupported>", &ret))
return NULL;
break;
case GEN_EDIPARTY:
if (!X509V3_add_value("EdiPartyName", "<unsupported>", &ret))
return NULL;
break;
case GEN_EMAIL:
if (!X509V3_add_value_uchar("email", gen->d.ia5->data, &ret))
return NULL;
break;
case GEN_DNS:
if (!X509V3_add_value_uchar("DNS", gen->d.ia5->data, &ret))
return NULL;
break;
case GEN_URI:
if (!X509V3_add_value_uchar("URI", gen->d.ia5->data, &ret))
return NULL;
break;
case GEN_DIRNAME:
if (X509_NAME_oneline(gen->d.dirn, oline, sizeof(oline)) == NULL
|| !X509V3_add_value("DirName", oline, &ret))
return NULL;
break;
case GEN_IPADD:
p = gen->d.ip->data;
if (gen->d.ip->length == 4)
BIO_snprintf(oline, sizeof(oline), "%d.%d.%d.%d",
p[0], p[1], p[2], p[3]);
else if (gen->d.ip->length == 16) {
oline[0] = 0;
for (i = 0; i < 8; i++) {
BIO_snprintf(htmp, sizeof(htmp), "%X", p[0] << 8 | p[1]);
p += 2;
strcat(oline, htmp);
if (i != 7)
strcat(oline, ":");
}
} else {
if (!X509V3_add_value("IP Address", "<invalid>", &ret))
return NULL;
break;
}
if (!X509V3_add_value("IP Address", oline, &ret))
return NULL;
break;
case GEN_RID:
i2t_ASN1_OBJECT(oline, 256, gen->d.rid);
if (!X509V3_add_value("Registered ID", oline, &ret))
return NULL;
break;
}
return ret;
}
int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
{
unsigned char *p;
int i;
switch (gen->type) {
case GEN_OTHERNAME:
BIO_printf(out, "othername:<unsupported>");
break;
case GEN_X400:
BIO_printf(out, "X400Name:<unsupported>");
break;
case GEN_EDIPARTY:
/* Maybe fix this: it is supported now */
BIO_printf(out, "EdiPartyName:<unsupported>");
break;
case GEN_EMAIL:
BIO_printf(out, "email:%s", gen->d.ia5->data);
break;
case GEN_DNS:
BIO_printf(out, "DNS:%s", gen->d.ia5->data);
break;
case GEN_URI:
BIO_printf(out, "URI:%s", gen->d.ia5->data);
break;
case GEN_DIRNAME:
BIO_printf(out, "DirName:");
X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE);
break;
case GEN_IPADD:
p = gen->d.ip->data;
if (gen->d.ip->length == 4)
BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
else if (gen->d.ip->length == 16) {
BIO_printf(out, "IP Address");
for (i = 0; i < 8; i++) {
BIO_printf(out, ":%X", p[0] << 8 | p[1]);
p += 2;
}
BIO_puts(out, "\n");
} else {
BIO_printf(out, "IP Address:<invalid>");
break;
}
break;
case GEN_RID:
BIO_printf(out, "Registered ID:");
i2a_ASN1_OBJECT(out, gen->d.rid);
break;
}
return 1;
}
static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval)
{
const int num = sk_CONF_VALUE_num(nval);
GENERAL_NAMES *gens = sk_GENERAL_NAME_new_reserve(NULL, num);
int i;
if (gens == NULL) {
X509V3err(X509V3_F_V2I_ISSUER_ALT, ERR_R_MALLOC_FAILURE);
sk_GENERAL_NAME_free(gens);
return NULL;
}
for (i = 0; i < num; i++) {
CONF_VALUE *cnf = sk_CONF_VALUE_value(nval, i);
if (!name_cmp(cnf->name, "issuer")
&& cnf->value && strcmp(cnf->value, "copy") == 0) {
if (!copy_issuer(ctx, gens))
goto err;
} else {
GENERAL_NAME *gen = v2i_GENERAL_NAME(method, ctx, cnf);
if (gen == NULL)
goto err;
sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
}
}
return gens;
err:
sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
return NULL;
}
/* Append subject altname of issuer to issuer alt name of subject */
static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens)
{
GENERAL_NAMES *ialt;
GENERAL_NAME *gen;
X509_EXTENSION *ext;
int i, num;
if (ctx && (ctx->flags == CTX_TEST))
return 1;
if (!ctx || !ctx->issuer_cert) {
X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_NO_ISSUER_DETAILS);
goto err;
}
i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1);
if (i < 0)
return 1;
if ((ext = X509_get_ext(ctx->issuer_cert, i)) == NULL
|| (ialt = X509V3_EXT_d2i(ext)) == NULL) {
X509V3err(X509V3_F_COPY_ISSUER, X509V3_R_ISSUER_DECODE_ERROR);
goto err;
}
num = sk_GENERAL_NAME_num(ialt);
if (!sk_GENERAL_NAME_reserve(gens, num)) {
X509V3err(X509V3_F_COPY_ISSUER, ERR_R_MALLOC_FAILURE);
goto err;
}
for (i = 0; i < num; i++) {
gen = sk_GENERAL_NAME_value(ialt, i);
sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
}
sk_GENERAL_NAME_free(ialt);
return 1;
err:
return 0;
}
static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval)
{
GENERAL_NAMES *gens;
CONF_VALUE *cnf;
const int num = sk_CONF_VALUE_num(nval);
int i;
gens = sk_GENERAL_NAME_new_reserve(NULL, num);
if (gens == NULL) {
X509V3err(X509V3_F_V2I_SUBJECT_ALT, ERR_R_MALLOC_FAILURE);
sk_GENERAL_NAME_free(gens);
return NULL;
}
for (i = 0; i < num; i++) {
cnf = sk_CONF_VALUE_value(nval, i);
if (!name_cmp(cnf->name, "email")
&& cnf->value && strcmp(cnf->value, "copy") == 0) {
if (!copy_email(ctx, gens, 0))
goto err;
} else if (!name_cmp(cnf->name, "email")
&& cnf->value && strcmp(cnf->value, "move") == 0) {
if (!copy_email(ctx, gens, 1))
goto err;
} else {
GENERAL_NAME *gen;
if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL)
goto err;
sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
}
}
return gens;
err:
sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
return NULL;
}
/*
* Copy any email addresses in a certificate or request to GENERAL_NAMES
*/
static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p)
{
X509_NAME *nm;
ASN1_IA5STRING *email = NULL;
X509_NAME_ENTRY *ne;
GENERAL_NAME *gen = NULL;
int i = -1;
if (ctx != NULL && ctx->flags == CTX_TEST)
return 1;
if (ctx == NULL
|| (ctx->subject_cert == NULL && ctx->subject_req == NULL)) {
X509V3err(X509V3_F_COPY_EMAIL, X509V3_R_NO_SUBJECT_DETAILS);
goto err;
}
/* Find the subject name */
if (ctx->subject_cert)
nm = X509_get_subject_name(ctx->subject_cert);
else
nm = X509_REQ_get_subject_name(ctx->subject_req);
/* Now add any email address(es) to STACK */
while ((i = X509_NAME_get_index_by_NID(nm,
NID_pkcs9_emailAddress, i)) >= 0) {
ne = X509_NAME_get_entry(nm, i);
email = ASN1_STRING_dup(X509_NAME_ENTRY_get_data(ne));
if (move_p) {
X509_NAME_delete_entry(nm, i);
X509_NAME_ENTRY_free(ne);
i--;
}
if (email == NULL || (gen = GENERAL_NAME_new()) == NULL) {
X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE);
goto err;
}
gen->d.ia5 = email;
email = NULL;
gen->type = GEN_EMAIL;
if (!sk_GENERAL_NAME_push(gens, gen)) {
X509V3err(X509V3_F_COPY_EMAIL, ERR_R_MALLOC_FAILURE);
goto err;
}
gen = NULL;
}
return 1;
err:
GENERAL_NAME_free(gen);
ASN1_IA5STRING_free(email);
return 0;
}
GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
{
GENERAL_NAME *gen;
GENERAL_NAMES *gens;
CONF_VALUE *cnf;
const int num = sk_CONF_VALUE_num(nval);
int i;
gens = sk_GENERAL_NAME_new_reserve(NULL, num);
if (gens == NULL) {
X509V3err(X509V3_F_V2I_GENERAL_NAMES, ERR_R_MALLOC_FAILURE);
sk_GENERAL_NAME_free(gens);
return NULL;
}
for (i = 0; i < num; i++) {
cnf = sk_CONF_VALUE_value(nval, i);
if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL)
goto err;
sk_GENERAL_NAME_push(gens, gen); /* no failure as it was reserved */
}
return gens;
err:
sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
return NULL;
}
GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, CONF_VALUE *cnf)
{
return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0);
}
GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,
const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, int gen_type, const char *value,
int is_nc)
{
char is_string = 0;
GENERAL_NAME *gen = NULL;
if (!value) {
X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_MISSING_VALUE);
return NULL;
}
if (out)
gen = out;
else {
gen = GENERAL_NAME_new();
if (gen == NULL) {
X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE);
return NULL;
}
}
switch (gen_type) {
case GEN_URI:
case GEN_EMAIL:
case GEN_DNS:
is_string = 1;
break;
case GEN_RID:
{
ASN1_OBJECT *obj;
if ((obj = OBJ_txt2obj(value, 0)) == NULL) {
X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_OBJECT);
ERR_add_error_data(2, "value=", value);
goto err;
}
gen->d.rid = obj;
}
break;
case GEN_IPADD:
if (is_nc)
gen->d.ip = a2i_IPADDRESS_NC(value);
else
gen->d.ip = a2i_IPADDRESS(value);
if (gen->d.ip == NULL) {
X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_BAD_IP_ADDRESS);
ERR_add_error_data(2, "value=", value);
goto err;
}
break;
case GEN_DIRNAME:
if (!do_dirname(gen, value, ctx)) {
X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_DIRNAME_ERROR);
goto err;
}
break;
case GEN_OTHERNAME:
if (!do_othername(gen, value, ctx)) {
X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_OTHERNAME_ERROR);
goto err;
}
break;
default:
X509V3err(X509V3_F_A2I_GENERAL_NAME, X509V3_R_UNSUPPORTED_TYPE);
goto err;
}
if (is_string) {
if ((gen->d.ia5 = ASN1_IA5STRING_new()) == NULL ||
!ASN1_STRING_set(gen->d.ia5, (unsigned char *)value,
strlen(value))) {
X509V3err(X509V3_F_A2I_GENERAL_NAME, ERR_R_MALLOC_FAILURE);
goto err;
}
}
gen->type = gen_type;
return gen;
err:
if (!out)
GENERAL_NAME_free(gen);
return NULL;
}
GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out,
const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc)
{
int type;
char *name, *value;
name = cnf->name;
value = cnf->value;
if (!value) {
X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_MISSING_VALUE);
return NULL;
}
if (!name_cmp(name, "email"))
type = GEN_EMAIL;
else if (!name_cmp(name, "URI"))
type = GEN_URI;
else if (!name_cmp(name, "DNS"))
type = GEN_DNS;
else if (!name_cmp(name, "RID"))
type = GEN_RID;
else if (!name_cmp(name, "IP"))
type = GEN_IPADD;
else if (!name_cmp(name, "dirName"))
type = GEN_DIRNAME;
else if (!name_cmp(name, "otherName"))
type = GEN_OTHERNAME;
else {
X509V3err(X509V3_F_V2I_GENERAL_NAME_EX, X509V3_R_UNSUPPORTED_OPTION);
ERR_add_error_data(2, "name=", name);
return NULL;
}
return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc);
}
static int do_othername(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx)
{
char *objtmp = NULL, *p;
int objlen;
if ((p = strchr(value, ';')) == NULL)
return 0;
if ((gen->d.otherName = OTHERNAME_new()) == NULL)
return 0;
/*
* Free this up because we will overwrite it. no need to free type_id
* because it is static
*/
ASN1_TYPE_free(gen->d.otherName->value);
if ((gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx)) == NULL)
return 0;
objlen = p - value;
objtmp = OPENSSL_strndup(value, objlen);
if (objtmp == NULL)
return 0;
gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0);
OPENSSL_free(objtmp);
if (!gen->d.otherName->type_id)
return 0;
return 1;
}
static int do_dirname(GENERAL_NAME *gen, const char *value, X509V3_CTX *ctx)
{
int ret = 0;
STACK_OF(CONF_VALUE) *sk = NULL;
X509_NAME *nm;
if ((nm = X509_NAME_new()) == NULL)
goto err;
sk = X509V3_get_section(ctx, value);
if (!sk) {
X509V3err(X509V3_F_DO_DIRNAME, X509V3_R_SECTION_NOT_FOUND);
ERR_add_error_data(2, "section=", value);
goto err;
}
/* FIXME: should allow other character types... */
ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC);
if (!ret)
goto err;
gen->d.dirn = nm;
err:
if (ret == 0)
X509_NAME_free(nm);
X509V3_section_free(ctx, sk);
return ret;
}

View file

@ -0,0 +1,880 @@
/*
* Copyright 2006-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* Implementation of RFC 3779 section 3.2.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include <openssl/x509.h>
#include "internal/x509_int.h"
#include <openssl/bn.h>
#include "ext_dat.h"
#ifndef OPENSSL_NO_RFC3779
/*
* OpenSSL ASN.1 template translation of RFC 3779 3.2.3.
*/
ASN1_SEQUENCE(ASRange) = {
ASN1_SIMPLE(ASRange, min, ASN1_INTEGER),
ASN1_SIMPLE(ASRange, max, ASN1_INTEGER)
} ASN1_SEQUENCE_END(ASRange)
ASN1_CHOICE(ASIdOrRange) = {
ASN1_SIMPLE(ASIdOrRange, u.id, ASN1_INTEGER),
ASN1_SIMPLE(ASIdOrRange, u.range, ASRange)
} ASN1_CHOICE_END(ASIdOrRange)
ASN1_CHOICE(ASIdentifierChoice) = {
ASN1_SIMPLE(ASIdentifierChoice, u.inherit, ASN1_NULL),
ASN1_SEQUENCE_OF(ASIdentifierChoice, u.asIdsOrRanges, ASIdOrRange)
} ASN1_CHOICE_END(ASIdentifierChoice)
ASN1_SEQUENCE(ASIdentifiers) = {
ASN1_EXP_OPT(ASIdentifiers, asnum, ASIdentifierChoice, 0),
ASN1_EXP_OPT(ASIdentifiers, rdi, ASIdentifierChoice, 1)
} ASN1_SEQUENCE_END(ASIdentifiers)
IMPLEMENT_ASN1_FUNCTIONS(ASRange)
IMPLEMENT_ASN1_FUNCTIONS(ASIdOrRange)
IMPLEMENT_ASN1_FUNCTIONS(ASIdentifierChoice)
IMPLEMENT_ASN1_FUNCTIONS(ASIdentifiers)
/*
* i2r method for an ASIdentifierChoice.
*/
static int i2r_ASIdentifierChoice(BIO *out,
ASIdentifierChoice *choice,
int indent, const char *msg)
{
int i;
char *s;
if (choice == NULL)
return 1;
BIO_printf(out, "%*s%s:\n", indent, "", msg);
switch (choice->type) {
case ASIdentifierChoice_inherit:
BIO_printf(out, "%*sinherit\n", indent + 2, "");
break;
case ASIdentifierChoice_asIdsOrRanges:
for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges); i++) {
ASIdOrRange *aor =
sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
switch (aor->type) {
case ASIdOrRange_id:
if ((s = i2s_ASN1_INTEGER(NULL, aor->u.id)) == NULL)
return 0;
BIO_printf(out, "%*s%s\n", indent + 2, "", s);
OPENSSL_free(s);
break;
case ASIdOrRange_range:
if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->min)) == NULL)
return 0;
BIO_printf(out, "%*s%s-", indent + 2, "", s);
OPENSSL_free(s);
if ((s = i2s_ASN1_INTEGER(NULL, aor->u.range->max)) == NULL)
return 0;
BIO_printf(out, "%s\n", s);
OPENSSL_free(s);
break;
default:
return 0;
}
}
break;
default:
return 0;
}
return 1;
}
/*
* i2r method for an ASIdentifier extension.
*/
static int i2r_ASIdentifiers(const X509V3_EXT_METHOD *method,
void *ext, BIO *out, int indent)
{
ASIdentifiers *asid = ext;
return (i2r_ASIdentifierChoice(out, asid->asnum, indent,
"Autonomous System Numbers") &&
i2r_ASIdentifierChoice(out, asid->rdi, indent,
"Routing Domain Identifiers"));
}
/*
* Sort comparison function for a sequence of ASIdOrRange elements.
*/
static int ASIdOrRange_cmp(const ASIdOrRange *const *a_,
const ASIdOrRange *const *b_)
{
const ASIdOrRange *a = *a_, *b = *b_;
assert((a->type == ASIdOrRange_id && a->u.id != NULL) ||
(a->type == ASIdOrRange_range && a->u.range != NULL &&
a->u.range->min != NULL && a->u.range->max != NULL));
assert((b->type == ASIdOrRange_id && b->u.id != NULL) ||
(b->type == ASIdOrRange_range && b->u.range != NULL &&
b->u.range->min != NULL && b->u.range->max != NULL));
if (a->type == ASIdOrRange_id && b->type == ASIdOrRange_id)
return ASN1_INTEGER_cmp(a->u.id, b->u.id);
if (a->type == ASIdOrRange_range && b->type == ASIdOrRange_range) {
int r = ASN1_INTEGER_cmp(a->u.range->min, b->u.range->min);
return r != 0 ? r : ASN1_INTEGER_cmp(a->u.range->max,
b->u.range->max);
}
if (a->type == ASIdOrRange_id)
return ASN1_INTEGER_cmp(a->u.id, b->u.range->min);
else
return ASN1_INTEGER_cmp(a->u.range->min, b->u.id);
}
/*
* Add an inherit element.
*/
int X509v3_asid_add_inherit(ASIdentifiers *asid, int which)
{
ASIdentifierChoice **choice;
if (asid == NULL)
return 0;
switch (which) {
case V3_ASID_ASNUM:
choice = &asid->asnum;
break;
case V3_ASID_RDI:
choice = &asid->rdi;
break;
default:
return 0;
}
if (*choice == NULL) {
if ((*choice = ASIdentifierChoice_new()) == NULL)
return 0;
if (((*choice)->u.inherit = ASN1_NULL_new()) == NULL)
return 0;
(*choice)->type = ASIdentifierChoice_inherit;
}
return (*choice)->type == ASIdentifierChoice_inherit;
}
/*
* Add an ID or range to an ASIdentifierChoice.
*/
int X509v3_asid_add_id_or_range(ASIdentifiers *asid,
int which, ASN1_INTEGER *min, ASN1_INTEGER *max)
{
ASIdentifierChoice **choice;
ASIdOrRange *aor;
if (asid == NULL)
return 0;
switch (which) {
case V3_ASID_ASNUM:
choice = &asid->asnum;
break;
case V3_ASID_RDI:
choice = &asid->rdi;
break;
default:
return 0;
}
if (*choice != NULL && (*choice)->type == ASIdentifierChoice_inherit)
return 0;
if (*choice == NULL) {
if ((*choice = ASIdentifierChoice_new()) == NULL)
return 0;
(*choice)->u.asIdsOrRanges = sk_ASIdOrRange_new(ASIdOrRange_cmp);
if ((*choice)->u.asIdsOrRanges == NULL)
return 0;
(*choice)->type = ASIdentifierChoice_asIdsOrRanges;
}
if ((aor = ASIdOrRange_new()) == NULL)
return 0;
if (max == NULL) {
aor->type = ASIdOrRange_id;
aor->u.id = min;
} else {
aor->type = ASIdOrRange_range;
if ((aor->u.range = ASRange_new()) == NULL)
goto err;
ASN1_INTEGER_free(aor->u.range->min);
aor->u.range->min = min;
ASN1_INTEGER_free(aor->u.range->max);
aor->u.range->max = max;
}
if (!(sk_ASIdOrRange_push((*choice)->u.asIdsOrRanges, aor)))
goto err;
return 1;
err:
ASIdOrRange_free(aor);
return 0;
}
/*
* Extract min and max values from an ASIdOrRange.
*/
static int extract_min_max(ASIdOrRange *aor,
ASN1_INTEGER **min, ASN1_INTEGER **max)
{
if (!ossl_assert(aor != NULL))
return 0;
switch (aor->type) {
case ASIdOrRange_id:
*min = aor->u.id;
*max = aor->u.id;
return 1;
case ASIdOrRange_range:
*min = aor->u.range->min;
*max = aor->u.range->max;
return 1;
}
return 0;
}
/*
* Check whether an ASIdentifierChoice is in canonical form.
*/
static int ASIdentifierChoice_is_canonical(ASIdentifierChoice *choice)
{
ASN1_INTEGER *a_max_plus_one = NULL;
BIGNUM *bn = NULL;
int i, ret = 0;
/*
* Empty element or inheritance is canonical.
*/
if (choice == NULL || choice->type == ASIdentifierChoice_inherit)
return 1;
/*
* If not a list, or if empty list, it's broken.
*/
if (choice->type != ASIdentifierChoice_asIdsOrRanges ||
sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0)
return 0;
/*
* It's a list, check it.
*/
for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) {
ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1);
ASN1_INTEGER *a_min = NULL, *a_max = NULL, *b_min = NULL, *b_max =
NULL;
if (!extract_min_max(a, &a_min, &a_max)
|| !extract_min_max(b, &b_min, &b_max))
goto done;
/*
* Punt misordered list, overlapping start, or inverted range.
*/
if (ASN1_INTEGER_cmp(a_min, b_min) >= 0 ||
ASN1_INTEGER_cmp(a_min, a_max) > 0 ||
ASN1_INTEGER_cmp(b_min, b_max) > 0)
goto done;
/*
* Calculate a_max + 1 to check for adjacency.
*/
if ((bn == NULL && (bn = BN_new()) == NULL) ||
ASN1_INTEGER_to_BN(a_max, bn) == NULL ||
!BN_add_word(bn, 1) ||
(a_max_plus_one =
BN_to_ASN1_INTEGER(bn, a_max_plus_one)) == NULL) {
X509V3err(X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL,
ERR_R_MALLOC_FAILURE);
goto done;
}
/*
* Punt if adjacent or overlapping.
*/
if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) >= 0)
goto done;
}
/*
* Check for inverted range.
*/
i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1;
{
ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
ASN1_INTEGER *a_min, *a_max;
if (a != NULL && a->type == ASIdOrRange_range) {
if (!extract_min_max(a, &a_min, &a_max)
|| ASN1_INTEGER_cmp(a_min, a_max) > 0)
goto done;
}
}
ret = 1;
done:
ASN1_INTEGER_free(a_max_plus_one);
BN_free(bn);
return ret;
}
/*
* Check whether an ASIdentifier extension is in canonical form.
*/
int X509v3_asid_is_canonical(ASIdentifiers *asid)
{
return (asid == NULL ||
(ASIdentifierChoice_is_canonical(asid->asnum) &&
ASIdentifierChoice_is_canonical(asid->rdi)));
}
/*
* Whack an ASIdentifierChoice into canonical form.
*/
static int ASIdentifierChoice_canonize(ASIdentifierChoice *choice)
{
ASN1_INTEGER *a_max_plus_one = NULL;
BIGNUM *bn = NULL;
int i, ret = 0;
/*
* Nothing to do for empty element or inheritance.
*/
if (choice == NULL || choice->type == ASIdentifierChoice_inherit)
return 1;
/*
* If not a list, or if empty list, it's broken.
*/
if (choice->type != ASIdentifierChoice_asIdsOrRanges ||
sk_ASIdOrRange_num(choice->u.asIdsOrRanges) == 0) {
X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE,
X509V3_R_EXTENSION_VALUE_ERROR);
return 0;
}
/*
* We have a non-empty list. Sort it.
*/
sk_ASIdOrRange_sort(choice->u.asIdsOrRanges);
/*
* Now check for errors and suboptimal encoding, rejecting the
* former and fixing the latter.
*/
for (i = 0; i < sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1; i++) {
ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
ASIdOrRange *b = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i + 1);
ASN1_INTEGER *a_min = NULL, *a_max = NULL, *b_min = NULL, *b_max =
NULL;
if (!extract_min_max(a, &a_min, &a_max)
|| !extract_min_max(b, &b_min, &b_max))
goto done;
/*
* Make sure we're properly sorted (paranoia).
*/
if (!ossl_assert(ASN1_INTEGER_cmp(a_min, b_min) <= 0))
goto done;
/*
* Punt inverted ranges.
*/
if (ASN1_INTEGER_cmp(a_min, a_max) > 0 ||
ASN1_INTEGER_cmp(b_min, b_max) > 0)
goto done;
/*
* Check for overlaps.
*/
if (ASN1_INTEGER_cmp(a_max, b_min) >= 0) {
X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE,
X509V3_R_EXTENSION_VALUE_ERROR);
goto done;
}
/*
* Calculate a_max + 1 to check for adjacency.
*/
if ((bn == NULL && (bn = BN_new()) == NULL) ||
ASN1_INTEGER_to_BN(a_max, bn) == NULL ||
!BN_add_word(bn, 1) ||
(a_max_plus_one =
BN_to_ASN1_INTEGER(bn, a_max_plus_one)) == NULL) {
X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE,
ERR_R_MALLOC_FAILURE);
goto done;
}
/*
* If a and b are adjacent, merge them.
*/
if (ASN1_INTEGER_cmp(a_max_plus_one, b_min) == 0) {
ASRange *r;
switch (a->type) {
case ASIdOrRange_id:
if ((r = OPENSSL_malloc(sizeof(*r))) == NULL) {
X509V3err(X509V3_F_ASIDENTIFIERCHOICE_CANONIZE,
ERR_R_MALLOC_FAILURE);
goto done;
}
r->min = a_min;
r->max = b_max;
a->type = ASIdOrRange_range;
a->u.range = r;
break;
case ASIdOrRange_range:
ASN1_INTEGER_free(a->u.range->max);
a->u.range->max = b_max;
break;
}
switch (b->type) {
case ASIdOrRange_id:
b->u.id = NULL;
break;
case ASIdOrRange_range:
b->u.range->max = NULL;
break;
}
ASIdOrRange_free(b);
(void)sk_ASIdOrRange_delete(choice->u.asIdsOrRanges, i + 1);
i--;
continue;
}
}
/*
* Check for final inverted range.
*/
i = sk_ASIdOrRange_num(choice->u.asIdsOrRanges) - 1;
{
ASIdOrRange *a = sk_ASIdOrRange_value(choice->u.asIdsOrRanges, i);
ASN1_INTEGER *a_min, *a_max;
if (a != NULL && a->type == ASIdOrRange_range) {
if (!extract_min_max(a, &a_min, &a_max)
|| ASN1_INTEGER_cmp(a_min, a_max) > 0)
goto done;
}
}
/* Paranoia */
if (!ossl_assert(ASIdentifierChoice_is_canonical(choice)))
goto done;
ret = 1;
done:
ASN1_INTEGER_free(a_max_plus_one);
BN_free(bn);
return ret;
}
/*
* Whack an ASIdentifier extension into canonical form.
*/
int X509v3_asid_canonize(ASIdentifiers *asid)
{
return (asid == NULL ||
(ASIdentifierChoice_canonize(asid->asnum) &&
ASIdentifierChoice_canonize(asid->rdi)));
}
/*
* v2i method for an ASIdentifier extension.
*/
static void *v2i_ASIdentifiers(const struct v3_ext_method *method,
struct v3_ext_ctx *ctx,
STACK_OF(CONF_VALUE) *values)
{
ASN1_INTEGER *min = NULL, *max = NULL;
ASIdentifiers *asid = NULL;
int i;
if ((asid = ASIdentifiers_new()) == NULL) {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
CONF_VALUE *val = sk_CONF_VALUE_value(values, i);
int i1 = 0, i2 = 0, i3 = 0, is_range = 0, which = 0;
/*
* Figure out whether this is an AS or an RDI.
*/
if (!name_cmp(val->name, "AS")) {
which = V3_ASID_ASNUM;
} else if (!name_cmp(val->name, "RDI")) {
which = V3_ASID_RDI;
} else {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS,
X509V3_R_EXTENSION_NAME_ERROR);
X509V3_conf_err(val);
goto err;
}
/*
* Handle inheritance.
*/
if (strcmp(val->value, "inherit") == 0) {
if (X509v3_asid_add_inherit(asid, which))
continue;
X509V3err(X509V3_F_V2I_ASIDENTIFIERS,
X509V3_R_INVALID_INHERITANCE);
X509V3_conf_err(val);
goto err;
}
/*
* Number, range, or mistake, pick it apart and figure out which.
*/
i1 = strspn(val->value, "0123456789");
if (val->value[i1] == '\0') {
is_range = 0;
} else {
is_range = 1;
i2 = i1 + strspn(val->value + i1, " \t");
if (val->value[i2] != '-') {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS,
X509V3_R_INVALID_ASNUMBER);
X509V3_conf_err(val);
goto err;
}
i2++;
i2 = i2 + strspn(val->value + i2, " \t");
i3 = i2 + strspn(val->value + i2, "0123456789");
if (val->value[i3] != '\0') {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS,
X509V3_R_INVALID_ASRANGE);
X509V3_conf_err(val);
goto err;
}
}
/*
* Syntax is ok, read and add it.
*/
if (!is_range) {
if (!X509V3_get_value_int(val, &min)) {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
goto err;
}
} else {
char *s = OPENSSL_strdup(val->value);
if (s == NULL) {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
goto err;
}
s[i1] = '\0';
min = s2i_ASN1_INTEGER(NULL, s);
max = s2i_ASN1_INTEGER(NULL, s + i2);
OPENSSL_free(s);
if (min == NULL || max == NULL) {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
goto err;
}
if (ASN1_INTEGER_cmp(min, max) > 0) {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS,
X509V3_R_EXTENSION_VALUE_ERROR);
goto err;
}
}
if (!X509v3_asid_add_id_or_range(asid, which, min, max)) {
X509V3err(X509V3_F_V2I_ASIDENTIFIERS, ERR_R_MALLOC_FAILURE);
goto err;
}
min = max = NULL;
}
/*
* Canonize the result, then we're done.
*/
if (!X509v3_asid_canonize(asid))
goto err;
return asid;
err:
ASIdentifiers_free(asid);
ASN1_INTEGER_free(min);
ASN1_INTEGER_free(max);
return NULL;
}
/*
* OpenSSL dispatch.
*/
const X509V3_EXT_METHOD v3_asid = {
NID_sbgp_autonomousSysNum, /* nid */
0, /* flags */
ASN1_ITEM_ref(ASIdentifiers), /* template */
0, 0, 0, 0, /* old functions, ignored */
0, /* i2s */
0, /* s2i */
0, /* i2v */
v2i_ASIdentifiers, /* v2i */
i2r_ASIdentifiers, /* i2r */
0, /* r2i */
NULL /* extension-specific data */
};
/*
* Figure out whether extension uses inheritance.
*/
int X509v3_asid_inherits(ASIdentifiers *asid)
{
return (asid != NULL &&
((asid->asnum != NULL &&
asid->asnum->type == ASIdentifierChoice_inherit) ||
(asid->rdi != NULL &&
asid->rdi->type == ASIdentifierChoice_inherit)));
}
/*
* Figure out whether parent contains child.
*/
static int asid_contains(ASIdOrRanges *parent, ASIdOrRanges *child)
{
ASN1_INTEGER *p_min = NULL, *p_max = NULL, *c_min = NULL, *c_max = NULL;
int p, c;
if (child == NULL || parent == child)
return 1;
if (parent == NULL)
return 0;
p = 0;
for (c = 0; c < sk_ASIdOrRange_num(child); c++) {
if (!extract_min_max(sk_ASIdOrRange_value(child, c), &c_min, &c_max))
return 0;
for (;; p++) {
if (p >= sk_ASIdOrRange_num(parent))
return 0;
if (!extract_min_max(sk_ASIdOrRange_value(parent, p), &p_min,
&p_max))
return 0;
if (ASN1_INTEGER_cmp(p_max, c_max) < 0)
continue;
if (ASN1_INTEGER_cmp(p_min, c_min) > 0)
return 0;
break;
}
}
return 1;
}
/*
* Test whether a is a subset of b.
*/
int X509v3_asid_subset(ASIdentifiers *a, ASIdentifiers *b)
{
return (a == NULL ||
a == b ||
(b != NULL &&
!X509v3_asid_inherits(a) &&
!X509v3_asid_inherits(b) &&
asid_contains(b->asnum->u.asIdsOrRanges,
a->asnum->u.asIdsOrRanges) &&
asid_contains(b->rdi->u.asIdsOrRanges,
a->rdi->u.asIdsOrRanges)));
}
/*
* Validation error handling via callback.
*/
#define validation_err(_err_) \
do { \
if (ctx != NULL) { \
ctx->error = _err_; \
ctx->error_depth = i; \
ctx->current_cert = x; \
ret = ctx->verify_cb(0, ctx); \
} else { \
ret = 0; \
} \
if (!ret) \
goto done; \
} while (0)
/*
* Core code for RFC 3779 3.3 path validation.
*/
static int asid_validate_path_internal(X509_STORE_CTX *ctx,
STACK_OF(X509) *chain,
ASIdentifiers *ext)
{
ASIdOrRanges *child_as = NULL, *child_rdi = NULL;
int i, ret = 1, inherit_as = 0, inherit_rdi = 0;
X509 *x;
if (!ossl_assert(chain != NULL && sk_X509_num(chain) > 0)
|| !ossl_assert(ctx != NULL || ext != NULL)
|| !ossl_assert(ctx == NULL || ctx->verify_cb != NULL)) {
if (ctx != NULL)
ctx->error = X509_V_ERR_UNSPECIFIED;
return 0;
}
/*
* Figure out where to start. If we don't have an extension to
* check, we're done. Otherwise, check canonical form and
* set up for walking up the chain.
*/
if (ext != NULL) {
i = -1;
x = NULL;
} else {
i = 0;
x = sk_X509_value(chain, i);
if ((ext = x->rfc3779_asid) == NULL)
goto done;
}
if (!X509v3_asid_is_canonical(ext))
validation_err(X509_V_ERR_INVALID_EXTENSION);
if (ext->asnum != NULL) {
switch (ext->asnum->type) {
case ASIdentifierChoice_inherit:
inherit_as = 1;
break;
case ASIdentifierChoice_asIdsOrRanges:
child_as = ext->asnum->u.asIdsOrRanges;
break;
}
}
if (ext->rdi != NULL) {
switch (ext->rdi->type) {
case ASIdentifierChoice_inherit:
inherit_rdi = 1;
break;
case ASIdentifierChoice_asIdsOrRanges:
child_rdi = ext->rdi->u.asIdsOrRanges;
break;
}
}
/*
* Now walk up the chain. Extensions must be in canonical form, no
* cert may list resources that its parent doesn't list.
*/
for (i++; i < sk_X509_num(chain); i++) {
x = sk_X509_value(chain, i);
if (!ossl_assert(x != NULL)) {
if (ctx != NULL)
ctx->error = X509_V_ERR_UNSPECIFIED;
return 0;
}
if (x->rfc3779_asid == NULL) {
if (child_as != NULL || child_rdi != NULL)
validation_err(X509_V_ERR_UNNESTED_RESOURCE);
continue;
}
if (!X509v3_asid_is_canonical(x->rfc3779_asid))
validation_err(X509_V_ERR_INVALID_EXTENSION);
if (x->rfc3779_asid->asnum == NULL && child_as != NULL) {
validation_err(X509_V_ERR_UNNESTED_RESOURCE);
child_as = NULL;
inherit_as = 0;
}
if (x->rfc3779_asid->asnum != NULL &&
x->rfc3779_asid->asnum->type ==
ASIdentifierChoice_asIdsOrRanges) {
if (inherit_as
|| asid_contains(x->rfc3779_asid->asnum->u.asIdsOrRanges,
child_as)) {
child_as = x->rfc3779_asid->asnum->u.asIdsOrRanges;
inherit_as = 0;
} else {
validation_err(X509_V_ERR_UNNESTED_RESOURCE);
}
}
if (x->rfc3779_asid->rdi == NULL && child_rdi != NULL) {
validation_err(X509_V_ERR_UNNESTED_RESOURCE);
child_rdi = NULL;
inherit_rdi = 0;
}
if (x->rfc3779_asid->rdi != NULL &&
x->rfc3779_asid->rdi->type == ASIdentifierChoice_asIdsOrRanges) {
if (inherit_rdi ||
asid_contains(x->rfc3779_asid->rdi->u.asIdsOrRanges,
child_rdi)) {
child_rdi = x->rfc3779_asid->rdi->u.asIdsOrRanges;
inherit_rdi = 0;
} else {
validation_err(X509_V_ERR_UNNESTED_RESOURCE);
}
}
}
/*
* Trust anchor can't inherit.
*/
if (!ossl_assert(x != NULL)) {
if (ctx != NULL)
ctx->error = X509_V_ERR_UNSPECIFIED;
return 0;
}
if (x->rfc3779_asid != NULL) {
if (x->rfc3779_asid->asnum != NULL &&
x->rfc3779_asid->asnum->type == ASIdentifierChoice_inherit)
validation_err(X509_V_ERR_UNNESTED_RESOURCE);
if (x->rfc3779_asid->rdi != NULL &&
x->rfc3779_asid->rdi->type == ASIdentifierChoice_inherit)
validation_err(X509_V_ERR_UNNESTED_RESOURCE);
}
done:
return ret;
}
#undef validation_err
/*
* RFC 3779 3.3 path validation -- called from X509_verify_cert().
*/
int X509v3_asid_validate_path(X509_STORE_CTX *ctx)
{
if (ctx->chain == NULL
|| sk_X509_num(ctx->chain) == 0
|| ctx->verify_cb == NULL) {
ctx->error = X509_V_ERR_UNSPECIFIED;
return 0;
}
return asid_validate_path_internal(ctx, ctx->chain, NULL);
}
/*
* RFC 3779 3.3 path validation of an extension.
* Test whether chain covers extension.
*/
int X509v3_asid_validate_resource_set(STACK_OF(X509) *chain,
ASIdentifiers *ext, int allow_inheritance)
{
if (ext == NULL)
return 1;
if (chain == NULL || sk_X509_num(chain) == 0)
return 0;
if (!allow_inheritance && X509v3_asid_inherits(ext))
return 0;
return asid_validate_path_internal(NULL, chain, ext);
}
#endif /* OPENSSL_NO_RFC3779 */

View file

@ -0,0 +1,84 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
BASIC_CONSTRAINTS *bcons,
STACK_OF(CONF_VALUE)
*extlist);
static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *values);
const X509V3_EXT_METHOD v3_bcons = {
NID_basic_constraints, 0,
ASN1_ITEM_ref(BASIC_CONSTRAINTS),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V) i2v_BASIC_CONSTRAINTS,
(X509V3_EXT_V2I)v2i_BASIC_CONSTRAINTS,
NULL, NULL,
NULL
};
ASN1_SEQUENCE(BASIC_CONSTRAINTS) = {
ASN1_OPT(BASIC_CONSTRAINTS, ca, ASN1_FBOOLEAN),
ASN1_OPT(BASIC_CONSTRAINTS, pathlen, ASN1_INTEGER)
} ASN1_SEQUENCE_END(BASIC_CONSTRAINTS)
IMPLEMENT_ASN1_FUNCTIONS(BASIC_CONSTRAINTS)
static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
BASIC_CONSTRAINTS *bcons,
STACK_OF(CONF_VALUE)
*extlist)
{
X509V3_add_value_bool("CA", bcons->ca, &extlist);
X509V3_add_value_int("pathlen", bcons->pathlen, &extlist);
return extlist;
}
static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *values)
{
BASIC_CONSTRAINTS *bcons = NULL;
CONF_VALUE *val;
int i;
if ((bcons = BASIC_CONSTRAINTS_new()) == NULL) {
X509V3err(X509V3_F_V2I_BASIC_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
val = sk_CONF_VALUE_value(values, i);
if (strcmp(val->name, "CA") == 0) {
if (!X509V3_get_value_bool(val, &bcons->ca))
goto err;
} else if (strcmp(val->name, "pathlen") == 0) {
if (!X509V3_get_value_int(val, &bcons->pathlen))
goto err;
} else {
X509V3err(X509V3_F_V2I_BASIC_CONSTRAINTS, X509V3_R_INVALID_NAME);
X509V3_conf_err(val);
goto err;
}
}
return bcons;
err:
BASIC_CONSTRAINTS_free(bcons);
return NULL;
}

View file

@ -0,0 +1,93 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static BIT_STRING_BITNAME ns_cert_type_table[] = {
{0, "SSL Client", "client"},
{1, "SSL Server", "server"},
{2, "S/MIME", "email"},
{3, "Object Signing", "objsign"},
{4, "Unused", "reserved"},
{5, "SSL CA", "sslCA"},
{6, "S/MIME CA", "emailCA"},
{7, "Object Signing CA", "objCA"},
{-1, NULL, NULL}
};
static BIT_STRING_BITNAME key_usage_type_table[] = {
{0, "Digital Signature", "digitalSignature"},
{1, "Non Repudiation", "nonRepudiation"},
{2, "Key Encipherment", "keyEncipherment"},
{3, "Data Encipherment", "dataEncipherment"},
{4, "Key Agreement", "keyAgreement"},
{5, "Certificate Sign", "keyCertSign"},
{6, "CRL Sign", "cRLSign"},
{7, "Encipher Only", "encipherOnly"},
{8, "Decipher Only", "decipherOnly"},
{-1, NULL, NULL}
};
const X509V3_EXT_METHOD v3_nscert =
EXT_BITSTRING(NID_netscape_cert_type, ns_cert_type_table);
const X509V3_EXT_METHOD v3_key_usage =
EXT_BITSTRING(NID_key_usage, key_usage_type_table);
STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
ASN1_BIT_STRING *bits,
STACK_OF(CONF_VALUE) *ret)
{
BIT_STRING_BITNAME *bnam;
for (bnam = method->usr_data; bnam->lname; bnam++) {
if (ASN1_BIT_STRING_get_bit(bits, bnam->bitnum))
X509V3_add_value(bnam->lname, NULL, &ret);
}
return ret;
}
ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval)
{
CONF_VALUE *val;
ASN1_BIT_STRING *bs;
int i;
BIT_STRING_BITNAME *bnam;
if ((bs = ASN1_BIT_STRING_new()) == NULL) {
X509V3err(X509V3_F_V2I_ASN1_BIT_STRING, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
val = sk_CONF_VALUE_value(nval, i);
for (bnam = method->usr_data; bnam->lname; bnam++) {
if (strcmp(bnam->sname, val->name) == 0
|| strcmp(bnam->lname, val->name) == 0) {
if (!ASN1_BIT_STRING_set_bit(bs, bnam->bitnum, 1)) {
X509V3err(X509V3_F_V2I_ASN1_BIT_STRING,
ERR_R_MALLOC_FAILURE);
ASN1_BIT_STRING_free(bs);
return NULL;
}
break;
}
}
if (!bnam->lname) {
X509V3err(X509V3_F_V2I_ASN1_BIT_STRING,
X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT);
X509V3_conf_err(val);
ASN1_BIT_STRING_free(bs);
return NULL;
}
}
return bs;
}

View file

@ -0,0 +1,511 @@
/*
* Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/* extension creation utilities */
#include <stdio.h>
#include "internal/ctype.h"
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/x509.h>
#include "internal/x509_int.h"
#include <openssl/x509v3.h>
static int v3_check_critical(const char **value);
static int v3_check_generic(const char **value);
static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid,
int crit, const char *value);
static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value,
int crit, int type,
X509V3_CTX *ctx);
static char *conf_lhash_get_string(void *db, const char *section, const char *value);
static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, const char *section);
static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method,
int ext_nid, int crit, void *ext_struc);
static unsigned char *generic_asn1(const char *value, X509V3_CTX *ctx,
long *ext_len);
/* CONF *conf: Config file */
/* char *name: Name */
/* char *value: Value */
X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, const char *name,
const char *value)
{
int crit;
int ext_type;
X509_EXTENSION *ret;
crit = v3_check_critical(&value);
if ((ext_type = v3_check_generic(&value)))
return v3_generic_extension(name, value, crit, ext_type, ctx);
ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value);
if (!ret) {
X509V3err(X509V3_F_X509V3_EXT_NCONF, X509V3_R_ERROR_IN_EXTENSION);
ERR_add_error_data(4, "name=", name, ", value=", value);
}
return ret;
}
/* CONF *conf: Config file */
/* char *value: Value */
X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid,
const char *value)
{
int crit;
int ext_type;
crit = v3_check_critical(&value);
if ((ext_type = v3_check_generic(&value)))
return v3_generic_extension(OBJ_nid2sn(ext_nid),
value, crit, ext_type, ctx);
return do_ext_nconf(conf, ctx, ext_nid, crit, value);
}
/* CONF *conf: Config file */
/* char *value: Value */
static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid,
int crit, const char *value)
{
const X509V3_EXT_METHOD *method;
X509_EXTENSION *ext;
STACK_OF(CONF_VALUE) *nval;
void *ext_struc;
if (ext_nid == NID_undef) {
X509V3err(X509V3_F_DO_EXT_NCONF, X509V3_R_UNKNOWN_EXTENSION_NAME);
return NULL;
}
if ((method = X509V3_EXT_get_nid(ext_nid)) == NULL) {
X509V3err(X509V3_F_DO_EXT_NCONF, X509V3_R_UNKNOWN_EXTENSION);
return NULL;
}
/* Now get internal extension representation based on type */
if (method->v2i) {
if (*value == '@')
nval = NCONF_get_section(conf, value + 1);
else
nval = X509V3_parse_list(value);
if (nval == NULL || sk_CONF_VALUE_num(nval) <= 0) {
X509V3err(X509V3_F_DO_EXT_NCONF,
X509V3_R_INVALID_EXTENSION_STRING);
ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=",
value);
if (*value != '@')
sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
return NULL;
}
ext_struc = method->v2i(method, ctx, nval);
if (*value != '@')
sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
if (!ext_struc)
return NULL;
} else if (method->s2i) {
if ((ext_struc = method->s2i(method, ctx, value)) == NULL)
return NULL;
} else if (method->r2i) {
if (!ctx->db || !ctx->db_meth) {
X509V3err(X509V3_F_DO_EXT_NCONF, X509V3_R_NO_CONFIG_DATABASE);
return NULL;
}
if ((ext_struc = method->r2i(method, ctx, value)) == NULL)
return NULL;
} else {
X509V3err(X509V3_F_DO_EXT_NCONF,
X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED);
ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid));
return NULL;
}
ext = do_ext_i2d(method, ext_nid, crit, ext_struc);
if (method->it)
ASN1_item_free(ext_struc, ASN1_ITEM_ptr(method->it));
else
method->ext_free(ext_struc);
return ext;
}
static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method,
int ext_nid, int crit, void *ext_struc)
{
unsigned char *ext_der = NULL;
int ext_len;
ASN1_OCTET_STRING *ext_oct = NULL;
X509_EXTENSION *ext;
/* Convert internal representation to DER */
if (method->it) {
ext_der = NULL;
ext_len =
ASN1_item_i2d(ext_struc, &ext_der, ASN1_ITEM_ptr(method->it));
if (ext_len < 0)
goto merr;
} else {
unsigned char *p;
ext_len = method->i2d(ext_struc, NULL);
if ((ext_der = OPENSSL_malloc(ext_len)) == NULL)
goto merr;
p = ext_der;
method->i2d(ext_struc, &p);
}
if ((ext_oct = ASN1_OCTET_STRING_new()) == NULL)
goto merr;
ext_oct->data = ext_der;
ext_der = NULL;
ext_oct->length = ext_len;
ext = X509_EXTENSION_create_by_NID(NULL, ext_nid, crit, ext_oct);
if (!ext)
goto merr;
ASN1_OCTET_STRING_free(ext_oct);
return ext;
merr:
X509V3err(X509V3_F_DO_EXT_I2D, ERR_R_MALLOC_FAILURE);
OPENSSL_free(ext_der);
ASN1_OCTET_STRING_free(ext_oct);
return NULL;
}
/* Given an internal structure, nid and critical flag create an extension */
X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc)
{
const X509V3_EXT_METHOD *method;
if ((method = X509V3_EXT_get_nid(ext_nid)) == NULL) {
X509V3err(X509V3_F_X509V3_EXT_I2D, X509V3_R_UNKNOWN_EXTENSION);
return NULL;
}
return do_ext_i2d(method, ext_nid, crit, ext_struc);
}
/* Check the extension string for critical flag */
static int v3_check_critical(const char **value)
{
const char *p = *value;
if ((strlen(p) < 9) || strncmp(p, "critical,", 9))
return 0;
p += 9;
while (ossl_isspace(*p))
p++;
*value = p;
return 1;
}
/* Check extension string for generic extension and return the type */
static int v3_check_generic(const char **value)
{
int gen_type = 0;
const char *p = *value;
if ((strlen(p) >= 4) && strncmp(p, "DER:", 4) == 0) {
p += 4;
gen_type = 1;
} else if ((strlen(p) >= 5) && strncmp(p, "ASN1:", 5) == 0) {
p += 5;
gen_type = 2;
} else
return 0;
while (ossl_isspace(*p))
p++;
*value = p;
return gen_type;
}
/* Create a generic extension: for now just handle DER type */
static X509_EXTENSION *v3_generic_extension(const char *ext, const char *value,
int crit, int gen_type,
X509V3_CTX *ctx)
{
unsigned char *ext_der = NULL;
long ext_len = 0;
ASN1_OBJECT *obj = NULL;
ASN1_OCTET_STRING *oct = NULL;
X509_EXTENSION *extension = NULL;
if ((obj = OBJ_txt2obj(ext, 0)) == NULL) {
X509V3err(X509V3_F_V3_GENERIC_EXTENSION,
X509V3_R_EXTENSION_NAME_ERROR);
ERR_add_error_data(2, "name=", ext);
goto err;
}
if (gen_type == 1)
ext_der = OPENSSL_hexstr2buf(value, &ext_len);
else if (gen_type == 2)
ext_der = generic_asn1(value, ctx, &ext_len);
if (ext_der == NULL) {
X509V3err(X509V3_F_V3_GENERIC_EXTENSION,
X509V3_R_EXTENSION_VALUE_ERROR);
ERR_add_error_data(2, "value=", value);
goto err;
}
if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
X509V3err(X509V3_F_V3_GENERIC_EXTENSION, ERR_R_MALLOC_FAILURE);
goto err;
}
oct->data = ext_der;
oct->length = ext_len;
ext_der = NULL;
extension = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct);
err:
ASN1_OBJECT_free(obj);
ASN1_OCTET_STRING_free(oct);
OPENSSL_free(ext_der);
return extension;
}
static unsigned char *generic_asn1(const char *value, X509V3_CTX *ctx,
long *ext_len)
{
ASN1_TYPE *typ;
unsigned char *ext_der = NULL;
typ = ASN1_generate_v3(value, ctx);
if (typ == NULL)
return NULL;
*ext_len = i2d_ASN1_TYPE(typ, &ext_der);
ASN1_TYPE_free(typ);
return ext_der;
}
static void delete_ext(STACK_OF(X509_EXTENSION) *sk, X509_EXTENSION *dext)
{
int idx;
ASN1_OBJECT *obj;
obj = X509_EXTENSION_get_object(dext);
while ((idx = X509v3_get_ext_by_OBJ(sk, obj, -1)) >= 0) {
X509_EXTENSION *tmpext = X509v3_get_ext(sk, idx);
X509v3_delete_ext(sk, idx);
X509_EXTENSION_free(tmpext);
}
}
/*
* This is the main function: add a bunch of extensions based on a config
* file section to an extension STACK.
*/
int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, const char *section,
STACK_OF(X509_EXTENSION) **sk)
{
X509_EXTENSION *ext;
STACK_OF(CONF_VALUE) *nval;
CONF_VALUE *val;
int i;
if ((nval = NCONF_get_section(conf, section)) == NULL)
return 0;
for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
val = sk_CONF_VALUE_value(nval, i);
if ((ext = X509V3_EXT_nconf(conf, ctx, val->name, val->value)) == NULL)
return 0;
if (ctx->flags == X509V3_CTX_REPLACE)
delete_ext(*sk, ext);
if (sk != NULL) {
if (X509v3_add_ext(sk, ext, -1) == NULL) {
X509_EXTENSION_free(ext);
return 0;
}
}
X509_EXTENSION_free(ext);
}
return 1;
}
/*
* Convenience functions to add extensions to a certificate, CRL and request
*/
int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section,
X509 *cert)
{
STACK_OF(X509_EXTENSION) **sk = NULL;
if (cert)
sk = &cert->cert_info.extensions;
return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
}
/* Same as above but for a CRL */
int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section,
X509_CRL *crl)
{
STACK_OF(X509_EXTENSION) **sk = NULL;
if (crl)
sk = &crl->crl.extensions;
return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
}
/* Add extensions to certificate request */
int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, const char *section,
X509_REQ *req)
{
STACK_OF(X509_EXTENSION) *extlist = NULL, **sk = NULL;
int i;
if (req)
sk = &extlist;
i = X509V3_EXT_add_nconf_sk(conf, ctx, section, sk);
if (!i || !sk)
return i;
i = X509_REQ_add_extensions(req, extlist);
sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free);
return i;
}
/* Config database functions */
char *X509V3_get_string(X509V3_CTX *ctx, const char *name, const char *section)
{
if (!ctx->db || !ctx->db_meth || !ctx->db_meth->get_string) {
X509V3err(X509V3_F_X509V3_GET_STRING, X509V3_R_OPERATION_NOT_DEFINED);
return NULL;
}
if (ctx->db_meth->get_string)
return ctx->db_meth->get_string(ctx->db, name, section);
return NULL;
}
STACK_OF(CONF_VALUE) *X509V3_get_section(X509V3_CTX *ctx, const char *section)
{
if (!ctx->db || !ctx->db_meth || !ctx->db_meth->get_section) {
X509V3err(X509V3_F_X509V3_GET_SECTION,
X509V3_R_OPERATION_NOT_DEFINED);
return NULL;
}
if (ctx->db_meth->get_section)
return ctx->db_meth->get_section(ctx->db, section);
return NULL;
}
void X509V3_string_free(X509V3_CTX *ctx, char *str)
{
if (!str)
return;
if (ctx->db_meth->free_string)
ctx->db_meth->free_string(ctx->db, str);
}
void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section)
{
if (!section)
return;
if (ctx->db_meth->free_section)
ctx->db_meth->free_section(ctx->db, section);
}
static char *nconf_get_string(void *db, const char *section, const char *value)
{
return NCONF_get_string(db, section, value);
}
static STACK_OF(CONF_VALUE) *nconf_get_section(void *db, const char *section)
{
return NCONF_get_section(db, section);
}
static X509V3_CONF_METHOD nconf_method = {
nconf_get_string,
nconf_get_section,
NULL,
NULL
};
void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf)
{
ctx->db_meth = &nconf_method;
ctx->db = conf;
}
void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req,
X509_CRL *crl, int flags)
{
ctx->issuer_cert = issuer;
ctx->subject_cert = subj;
ctx->crl = crl;
ctx->subject_req = req;
ctx->flags = flags;
}
/* Old conf compatibility functions */
X509_EXTENSION *X509V3_EXT_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
const char *name, const char *value)
{
CONF ctmp;
CONF_set_nconf(&ctmp, conf);
return X509V3_EXT_nconf(&ctmp, ctx, name, value);
}
/* LHASH *conf: Config file */
/* char *value: Value */
X509_EXTENSION *X509V3_EXT_conf_nid(LHASH_OF(CONF_VALUE) *conf,
X509V3_CTX *ctx, int ext_nid, const char *value)
{
CONF ctmp;
CONF_set_nconf(&ctmp, conf);
return X509V3_EXT_nconf_nid(&ctmp, ctx, ext_nid, value);
}
static char *conf_lhash_get_string(void *db, const char *section, const char *value)
{
return CONF_get_string(db, section, value);
}
static STACK_OF(CONF_VALUE) *conf_lhash_get_section(void *db, const char *section)
{
return CONF_get_section(db, section);
}
static X509V3_CONF_METHOD conf_lhash_method = {
conf_lhash_get_string,
conf_lhash_get_section,
NULL,
NULL
};
void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH_OF(CONF_VALUE) *lhash)
{
ctx->db_meth = &conf_lhash_method;
ctx->db = lhash;
}
int X509V3_EXT_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
const char *section, X509 *cert)
{
CONF ctmp;
CONF_set_nconf(&ctmp, conf);
return X509V3_EXT_add_nconf(&ctmp, ctx, section, cert);
}
/* Same as above but for a CRL */
int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
const char *section, X509_CRL *crl)
{
CONF ctmp;
CONF_set_nconf(&ctmp, conf);
return X509V3_EXT_CRL_add_nconf(&ctmp, ctx, section, crl);
}
/* Add extensions to certificate request */
int X509V3_EXT_REQ_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx,
const char *section, X509_REQ *req)
{
CONF ctmp;
CONF_set_nconf(&ctmp, conf);
return X509V3_EXT_REQ_add_nconf(&ctmp, ctx, section, req);
}

View file

@ -0,0 +1,491 @@
/*
* Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include "pcy_int.h"
#include "ext_dat.h"
/* Certificate policies extension support: this one is a bit complex... */
static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol,
BIO *out, int indent);
static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *value);
static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
int indent);
static void print_notice(BIO *out, USERNOTICE *notice, int indent);
static POLICYINFO *policy_section(X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *polstrs, int ia5org);
static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *unot, int ia5org);
static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos);
static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len);
static int displaytext_get_tag_len(const char *tagstr);
const X509V3_EXT_METHOD v3_cpols = {
NID_certificate_policies, 0, ASN1_ITEM_ref(CERTIFICATEPOLICIES),
0, 0, 0, 0,
0, 0,
0, 0,
(X509V3_EXT_I2R)i2r_certpol,
(X509V3_EXT_R2I)r2i_certpol,
NULL
};
ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO)
ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES)
IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
ASN1_SEQUENCE(POLICYINFO) = {
ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT),
ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO)
} ASN1_SEQUENCE_END(POLICYINFO)
IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO)
ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY);
ASN1_ADB(POLICYQUALINFO) = {
ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)),
ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE))
} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL);
ASN1_SEQUENCE(POLICYQUALINFO) = {
ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT),
ASN1_ADB_OBJECT(POLICYQUALINFO)
} ASN1_SEQUENCE_END(POLICYQUALINFO)
IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO)
ASN1_SEQUENCE(USERNOTICE) = {
ASN1_OPT(USERNOTICE, noticeref, NOTICEREF),
ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT)
} ASN1_SEQUENCE_END(USERNOTICE)
IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE)
ASN1_SEQUENCE(NOTICEREF) = {
ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT),
ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER)
} ASN1_SEQUENCE_END(NOTICEREF)
IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF)
static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *value)
{
STACK_OF(POLICYINFO) *pols;
char *pstr;
POLICYINFO *pol;
ASN1_OBJECT *pobj;
STACK_OF(CONF_VALUE) *vals = X509V3_parse_list(value);
CONF_VALUE *cnf;
const int num = sk_CONF_VALUE_num(vals);
int i, ia5org;
if (vals == NULL) {
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_X509V3_LIB);
return NULL;
}
pols = sk_POLICYINFO_new_reserve(NULL, num);
if (pols == NULL) {
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
goto err;
}
ia5org = 0;
for (i = 0; i < num; i++) {
cnf = sk_CONF_VALUE_value(vals, i);
if (cnf->value || !cnf->name) {
X509V3err(X509V3_F_R2I_CERTPOL,
X509V3_R_INVALID_POLICY_IDENTIFIER);
X509V3_conf_err(cnf);
goto err;
}
pstr = cnf->name;
if (strcmp(pstr, "ia5org") == 0) {
ia5org = 1;
continue;
} else if (*pstr == '@') {
STACK_OF(CONF_VALUE) *polsect;
polsect = X509V3_get_section(ctx, pstr + 1);
if (!polsect) {
X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_SECTION);
X509V3_conf_err(cnf);
goto err;
}
pol = policy_section(ctx, polsect, ia5org);
X509V3_section_free(ctx, polsect);
if (pol == NULL)
goto err;
} else {
if ((pobj = OBJ_txt2obj(cnf->name, 0)) == NULL) {
X509V3err(X509V3_F_R2I_CERTPOL,
X509V3_R_INVALID_OBJECT_IDENTIFIER);
X509V3_conf_err(cnf);
goto err;
}
pol = POLICYINFO_new();
if (pol == NULL) {
ASN1_OBJECT_free(pobj);
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
goto err;
}
pol->policyid = pobj;
}
if (!sk_POLICYINFO_push(pols, pol)) {
POLICYINFO_free(pol);
X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
goto err;
}
}
sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
return pols;
err:
sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
return NULL;
}
static POLICYINFO *policy_section(X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *polstrs, int ia5org)
{
int i;
CONF_VALUE *cnf;
POLICYINFO *pol;
POLICYQUALINFO *qual;
if ((pol = POLICYINFO_new()) == NULL)
goto merr;
for (i = 0; i < sk_CONF_VALUE_num(polstrs); i++) {
cnf = sk_CONF_VALUE_value(polstrs, i);
if (strcmp(cnf->name, "policyIdentifier") == 0) {
ASN1_OBJECT *pobj;
if ((pobj = OBJ_txt2obj(cnf->value, 0)) == NULL) {
X509V3err(X509V3_F_POLICY_SECTION,
X509V3_R_INVALID_OBJECT_IDENTIFIER);
X509V3_conf_err(cnf);
goto err;
}
pol->policyid = pobj;
} else if (!name_cmp(cnf->name, "CPS")) {
if (pol->qualifiers == NULL)
pol->qualifiers = sk_POLICYQUALINFO_new_null();
if ((qual = POLICYQUALINFO_new()) == NULL)
goto merr;
if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
goto merr;
if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_cps)) == NULL) {
X509V3err(X509V3_F_POLICY_SECTION, ERR_R_INTERNAL_ERROR);
goto err;
}
if ((qual->d.cpsuri = ASN1_IA5STRING_new()) == NULL)
goto merr;
if (!ASN1_STRING_set(qual->d.cpsuri, cnf->value,
strlen(cnf->value)))
goto merr;
} else if (!name_cmp(cnf->name, "userNotice")) {
STACK_OF(CONF_VALUE) *unot;
if (*cnf->value != '@') {
X509V3err(X509V3_F_POLICY_SECTION,
X509V3_R_EXPECTED_A_SECTION_NAME);
X509V3_conf_err(cnf);
goto err;
}
unot = X509V3_get_section(ctx, cnf->value + 1);
if (!unot) {
X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_INVALID_SECTION);
X509V3_conf_err(cnf);
goto err;
}
qual = notice_section(ctx, unot, ia5org);
X509V3_section_free(ctx, unot);
if (!qual)
goto err;
if (!pol->qualifiers)
pol->qualifiers = sk_POLICYQUALINFO_new_null();
if (!sk_POLICYQUALINFO_push(pol->qualifiers, qual))
goto merr;
} else {
X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_INVALID_OPTION);
X509V3_conf_err(cnf);
goto err;
}
}
if (!pol->policyid) {
X509V3err(X509V3_F_POLICY_SECTION, X509V3_R_NO_POLICY_IDENTIFIER);
goto err;
}
return pol;
merr:
X509V3err(X509V3_F_POLICY_SECTION, ERR_R_MALLOC_FAILURE);
err:
POLICYINFO_free(pol);
return NULL;
}
static int displaytext_get_tag_len(const char *tagstr)
{
char *colon = strchr(tagstr, ':');
return (colon == NULL) ? -1 : colon - tagstr;
}
static int displaytext_str2tag(const char *tagstr, unsigned int *tag_len)
{
int len;
*tag_len = 0;
len = displaytext_get_tag_len(tagstr);
if (len == -1)
return V_ASN1_VISIBLESTRING;
*tag_len = len;
if (len == sizeof("UTF8") - 1 && strncmp(tagstr, "UTF8", len) == 0)
return V_ASN1_UTF8STRING;
if (len == sizeof("UTF8String") - 1 && strncmp(tagstr, "UTF8String", len) == 0)
return V_ASN1_UTF8STRING;
if (len == sizeof("BMP") - 1 && strncmp(tagstr, "BMP", len) == 0)
return V_ASN1_BMPSTRING;
if (len == sizeof("BMPSTRING") - 1 && strncmp(tagstr, "BMPSTRING", len) == 0)
return V_ASN1_BMPSTRING;
if (len == sizeof("VISIBLE") - 1 && strncmp(tagstr, "VISIBLE", len) == 0)
return V_ASN1_VISIBLESTRING;
if (len == sizeof("VISIBLESTRING") - 1 && strncmp(tagstr, "VISIBLESTRING", len) == 0)
return V_ASN1_VISIBLESTRING;
*tag_len = 0;
return V_ASN1_VISIBLESTRING;
}
static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *unot, int ia5org)
{
int i, ret, len, tag;
unsigned int tag_len;
CONF_VALUE *cnf;
USERNOTICE *not;
POLICYQUALINFO *qual;
char *value = NULL;
if ((qual = POLICYQUALINFO_new()) == NULL)
goto merr;
if ((qual->pqualid = OBJ_nid2obj(NID_id_qt_unotice)) == NULL) {
X509V3err(X509V3_F_NOTICE_SECTION, ERR_R_INTERNAL_ERROR);
goto err;
}
if ((not = USERNOTICE_new()) == NULL)
goto merr;
qual->d.usernotice = not;
for (i = 0; i < sk_CONF_VALUE_num(unot); i++) {
cnf = sk_CONF_VALUE_value(unot, i);
value = cnf->value;
if (strcmp(cnf->name, "explicitText") == 0) {
tag = displaytext_str2tag(value, &tag_len);
if ((not->exptext = ASN1_STRING_type_new(tag)) == NULL)
goto merr;
if (tag_len != 0)
value += tag_len + 1;
len = strlen(value);
if (!ASN1_STRING_set(not->exptext, value, len))
goto merr;
} else if (strcmp(cnf->name, "organization") == 0) {
NOTICEREF *nref;
if (!not->noticeref) {
if ((nref = NOTICEREF_new()) == NULL)
goto merr;
not->noticeref = nref;
} else
nref = not->noticeref;
if (ia5org)
nref->organization->type = V_ASN1_IA5STRING;
else
nref->organization->type = V_ASN1_VISIBLESTRING;
if (!ASN1_STRING_set(nref->organization, cnf->value,
strlen(cnf->value)))
goto merr;
} else if (strcmp(cnf->name, "noticeNumbers") == 0) {
NOTICEREF *nref;
STACK_OF(CONF_VALUE) *nos;
if (!not->noticeref) {
if ((nref = NOTICEREF_new()) == NULL)
goto merr;
not->noticeref = nref;
} else
nref = not->noticeref;
nos = X509V3_parse_list(cnf->value);
if (!nos || !sk_CONF_VALUE_num(nos)) {
X509V3err(X509V3_F_NOTICE_SECTION, X509V3_R_INVALID_NUMBERS);
X509V3_conf_err(cnf);
sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
goto err;
}
ret = nref_nos(nref->noticenos, nos);
sk_CONF_VALUE_pop_free(nos, X509V3_conf_free);
if (!ret)
goto err;
} else {
X509V3err(X509V3_F_NOTICE_SECTION, X509V3_R_INVALID_OPTION);
X509V3_conf_err(cnf);
goto err;
}
}
if (not->noticeref &&
(!not->noticeref->noticenos || !not->noticeref->organization)) {
X509V3err(X509V3_F_NOTICE_SECTION,
X509V3_R_NEED_ORGANIZATION_AND_NUMBERS);
goto err;
}
return qual;
merr:
X509V3err(X509V3_F_NOTICE_SECTION, ERR_R_MALLOC_FAILURE);
err:
POLICYQUALINFO_free(qual);
return NULL;
}
static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos)
{
CONF_VALUE *cnf;
ASN1_INTEGER *aint;
int i;
for (i = 0; i < sk_CONF_VALUE_num(nos); i++) {
cnf = sk_CONF_VALUE_value(nos, i);
if ((aint = s2i_ASN1_INTEGER(NULL, cnf->name)) == NULL) {
X509V3err(X509V3_F_NREF_NOS, X509V3_R_INVALID_NUMBER);
goto err;
}
if (!sk_ASN1_INTEGER_push(nnums, aint))
goto merr;
}
return 1;
merr:
ASN1_INTEGER_free(aint);
X509V3err(X509V3_F_NREF_NOS, ERR_R_MALLOC_FAILURE);
err:
return 0;
}
static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol,
BIO *out, int indent)
{
int i;
POLICYINFO *pinfo;
/* First print out the policy OIDs */
for (i = 0; i < sk_POLICYINFO_num(pol); i++) {
pinfo = sk_POLICYINFO_value(pol, i);
BIO_printf(out, "%*sPolicy: ", indent, "");
i2a_ASN1_OBJECT(out, pinfo->policyid);
BIO_puts(out, "\n");
if (pinfo->qualifiers)
print_qualifiers(out, pinfo->qualifiers, indent + 2);
}
return 1;
}
static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
int indent)
{
POLICYQUALINFO *qualinfo;
int i;
for (i = 0; i < sk_POLICYQUALINFO_num(quals); i++) {
qualinfo = sk_POLICYQUALINFO_value(quals, i);
switch (OBJ_obj2nid(qualinfo->pqualid)) {
case NID_id_qt_cps:
BIO_printf(out, "%*sCPS: %s\n", indent, "",
qualinfo->d.cpsuri->data);
break;
case NID_id_qt_unotice:
BIO_printf(out, "%*sUser Notice:\n", indent, "");
print_notice(out, qualinfo->d.usernotice, indent + 2);
break;
default:
BIO_printf(out, "%*sUnknown Qualifier: ", indent + 2, "");
i2a_ASN1_OBJECT(out, qualinfo->pqualid);
BIO_puts(out, "\n");
break;
}
}
}
static void print_notice(BIO *out, USERNOTICE *notice, int indent)
{
int i;
if (notice->noticeref) {
NOTICEREF *ref;
ref = notice->noticeref;
BIO_printf(out, "%*sOrganization: %s\n", indent, "",
ref->organization->data);
BIO_printf(out, "%*sNumber%s: ", indent, "",
sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "");
for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
ASN1_INTEGER *num;
char *tmp;
num = sk_ASN1_INTEGER_value(ref->noticenos, i);
if (i)
BIO_puts(out, ", ");
if (num == NULL)
BIO_puts(out, "(null)");
else {
tmp = i2s_ASN1_INTEGER(NULL, num);
if (tmp == NULL)
return;
BIO_puts(out, tmp);
OPENSSL_free(tmp);
}
}
BIO_puts(out, "\n");
}
if (notice->exptext)
BIO_printf(out, "%*sExplicit Text: %s\n", indent, "",
notice->exptext->data);
}
void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent)
{
const X509_POLICY_DATA *dat = node->data;
BIO_printf(out, "%*sPolicy: ", indent, "");
i2a_ASN1_OBJECT(out, dat->valid_policy);
BIO_puts(out, "\n");
BIO_printf(out, "%*s%s\n", indent + 2, "",
node_data_critical(dat) ? "Critical" : "Non Critical");
if (dat->qualifier_set)
print_qualifiers(out, dat->qualifier_set, indent + 2);
else
BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, "");
}

View file

@ -0,0 +1,506 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include "internal/x509_int.h"
#include "ext_dat.h"
static void *v2i_crld(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
int indent);
const X509V3_EXT_METHOD v3_crld = {
NID_crl_distribution_points, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
0, 0, 0, 0,
0, 0,
0,
v2i_crld,
i2r_crldp, 0,
NULL
};
const X509V3_EXT_METHOD v3_freshest_crl = {
NID_freshest_crl, 0, ASN1_ITEM_ref(CRL_DIST_POINTS),
0, 0, 0, 0,
0, 0,
0,
v2i_crld,
i2r_crldp, 0,
NULL
};
static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx,
char *sect)
{
STACK_OF(CONF_VALUE) *gnsect;
STACK_OF(GENERAL_NAME) *gens;
if (*sect == '@')
gnsect = X509V3_get_section(ctx, sect + 1);
else
gnsect = X509V3_parse_list(sect);
if (!gnsect) {
X509V3err(X509V3_F_GNAMES_FROM_SECTNAME, X509V3_R_SECTION_NOT_FOUND);
return NULL;
}
gens = v2i_GENERAL_NAMES(NULL, ctx, gnsect);
if (*sect == '@')
X509V3_section_free(ctx, gnsect);
else
sk_CONF_VALUE_pop_free(gnsect, X509V3_conf_free);
return gens;
}
static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx,
CONF_VALUE *cnf)
{
STACK_OF(GENERAL_NAME) *fnm = NULL;
STACK_OF(X509_NAME_ENTRY) *rnm = NULL;
if (strncmp(cnf->name, "fullname", 9) == 0) {
fnm = gnames_from_sectname(ctx, cnf->value);
if (!fnm)
goto err;
} else if (strcmp(cnf->name, "relativename") == 0) {
int ret;
STACK_OF(CONF_VALUE) *dnsect;
X509_NAME *nm;
nm = X509_NAME_new();
if (nm == NULL)
return -1;
dnsect = X509V3_get_section(ctx, cnf->value);
if (!dnsect) {
X509V3err(X509V3_F_SET_DIST_POINT_NAME,
X509V3_R_SECTION_NOT_FOUND);
return -1;
}
ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC);
X509V3_section_free(ctx, dnsect);
rnm = nm->entries;
nm->entries = NULL;
X509_NAME_free(nm);
if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0)
goto err;
/*
* Since its a name fragment can't have more than one RDNSequence
*/
if (sk_X509_NAME_ENTRY_value(rnm,
sk_X509_NAME_ENTRY_num(rnm) - 1)->set) {
X509V3err(X509V3_F_SET_DIST_POINT_NAME,
X509V3_R_INVALID_MULTIPLE_RDNS);
goto err;
}
} else
return 0;
if (*pdp) {
X509V3err(X509V3_F_SET_DIST_POINT_NAME,
X509V3_R_DISTPOINT_ALREADY_SET);
goto err;
}
*pdp = DIST_POINT_NAME_new();
if (*pdp == NULL)
goto err;
if (fnm) {
(*pdp)->type = 0;
(*pdp)->name.fullname = fnm;
} else {
(*pdp)->type = 1;
(*pdp)->name.relativename = rnm;
}
return 1;
err:
sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free);
sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free);
return -1;
}
static const BIT_STRING_BITNAME reason_flags[] = {
{0, "Unused", "unused"},
{1, "Key Compromise", "keyCompromise"},
{2, "CA Compromise", "CACompromise"},
{3, "Affiliation Changed", "affiliationChanged"},
{4, "Superseded", "superseded"},
{5, "Cessation Of Operation", "cessationOfOperation"},
{6, "Certificate Hold", "certificateHold"},
{7, "Privilege Withdrawn", "privilegeWithdrawn"},
{8, "AA Compromise", "AACompromise"},
{-1, NULL, NULL}
};
static int set_reasons(ASN1_BIT_STRING **preas, char *value)
{
STACK_OF(CONF_VALUE) *rsk = NULL;
const BIT_STRING_BITNAME *pbn;
const char *bnam;
int i, ret = 0;
rsk = X509V3_parse_list(value);
if (rsk == NULL)
return 0;
if (*preas != NULL)
goto err;
for (i = 0; i < sk_CONF_VALUE_num(rsk); i++) {
bnam = sk_CONF_VALUE_value(rsk, i)->name;
if (*preas == NULL) {
*preas = ASN1_BIT_STRING_new();
if (*preas == NULL)
goto err;
}
for (pbn = reason_flags; pbn->lname; pbn++) {
if (strcmp(pbn->sname, bnam) == 0) {
if (!ASN1_BIT_STRING_set_bit(*preas, pbn->bitnum, 1))
goto err;
break;
}
}
if (!pbn->lname)
goto err;
}
ret = 1;
err:
sk_CONF_VALUE_pop_free(rsk, X509V3_conf_free);
return ret;
}
static int print_reasons(BIO *out, const char *rname,
ASN1_BIT_STRING *rflags, int indent)
{
int first = 1;
const BIT_STRING_BITNAME *pbn;
BIO_printf(out, "%*s%s:\n%*s", indent, "", rname, indent + 2, "");
for (pbn = reason_flags; pbn->lname; pbn++) {
if (ASN1_BIT_STRING_get_bit(rflags, pbn->bitnum)) {
if (first)
first = 0;
else
BIO_puts(out, ", ");
BIO_puts(out, pbn->lname);
}
}
if (first)
BIO_puts(out, "<EMPTY>\n");
else
BIO_puts(out, "\n");
return 1;
}
static DIST_POINT *crldp_from_section(X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval)
{
int i;
CONF_VALUE *cnf;
DIST_POINT *point = DIST_POINT_new();
if (point == NULL)
goto err;
for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
int ret;
cnf = sk_CONF_VALUE_value(nval, i);
ret = set_dist_point_name(&point->distpoint, ctx, cnf);
if (ret > 0)
continue;
if (ret < 0)
goto err;
if (strcmp(cnf->name, "reasons") == 0) {
if (!set_reasons(&point->reasons, cnf->value))
goto err;
} else if (strcmp(cnf->name, "CRLissuer") == 0) {
point->CRLissuer = gnames_from_sectname(ctx, cnf->value);
if (!point->CRLissuer)
goto err;
}
}
return point;
err:
DIST_POINT_free(point);
return NULL;
}
static void *v2i_crld(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
{
STACK_OF(DIST_POINT) *crld;
GENERAL_NAMES *gens = NULL;
GENERAL_NAME *gen = NULL;
CONF_VALUE *cnf;
const int num = sk_CONF_VALUE_num(nval);
int i;
crld = sk_DIST_POINT_new_reserve(NULL, num);
if (crld == NULL)
goto merr;
for (i = 0; i < num; i++) {
DIST_POINT *point;
cnf = sk_CONF_VALUE_value(nval, i);
if (!cnf->value) {
STACK_OF(CONF_VALUE) *dpsect;
dpsect = X509V3_get_section(ctx, cnf->name);
if (!dpsect)
goto err;
point = crldp_from_section(ctx, dpsect);
X509V3_section_free(ctx, dpsect);
if (!point)
goto err;
sk_DIST_POINT_push(crld, point); /* no failure as it was reserved */
} else {
if ((gen = v2i_GENERAL_NAME(method, ctx, cnf)) == NULL)
goto err;
if ((gens = GENERAL_NAMES_new()) == NULL)
goto merr;
if (!sk_GENERAL_NAME_push(gens, gen))
goto merr;
gen = NULL;
if ((point = DIST_POINT_new()) == NULL)
goto merr;
sk_DIST_POINT_push(crld, point); /* no failure as it was reserved */
if ((point->distpoint = DIST_POINT_NAME_new()) == NULL)
goto merr;
point->distpoint->name.fullname = gens;
point->distpoint->type = 0;
gens = NULL;
}
}
return crld;
merr:
X509V3err(X509V3_F_V2I_CRLD, ERR_R_MALLOC_FAILURE);
err:
GENERAL_NAME_free(gen);
GENERAL_NAMES_free(gens);
sk_DIST_POINT_pop_free(crld, DIST_POINT_free);
return NULL;
}
static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
void *exarg)
{
DIST_POINT_NAME *dpn = (DIST_POINT_NAME *)*pval;
switch (operation) {
case ASN1_OP_NEW_POST:
dpn->dpname = NULL;
break;
case ASN1_OP_FREE_POST:
X509_NAME_free(dpn->dpname);
break;
}
return 1;
}
ASN1_CHOICE_cb(DIST_POINT_NAME, dpn_cb) = {
ASN1_IMP_SEQUENCE_OF(DIST_POINT_NAME, name.fullname, GENERAL_NAME, 0),
ASN1_IMP_SET_OF(DIST_POINT_NAME, name.relativename, X509_NAME_ENTRY, 1)
} ASN1_CHOICE_END_cb(DIST_POINT_NAME, DIST_POINT_NAME, type)
IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT_NAME)
ASN1_SEQUENCE(DIST_POINT) = {
ASN1_EXP_OPT(DIST_POINT, distpoint, DIST_POINT_NAME, 0),
ASN1_IMP_OPT(DIST_POINT, reasons, ASN1_BIT_STRING, 1),
ASN1_IMP_SEQUENCE_OF_OPT(DIST_POINT, CRLissuer, GENERAL_NAME, 2)
} ASN1_SEQUENCE_END(DIST_POINT)
IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT)
ASN1_ITEM_TEMPLATE(CRL_DIST_POINTS) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CRLDistributionPoints, DIST_POINT)
ASN1_ITEM_TEMPLATE_END(CRL_DIST_POINTS)
IMPLEMENT_ASN1_FUNCTIONS(CRL_DIST_POINTS)
ASN1_SEQUENCE(ISSUING_DIST_POINT) = {
ASN1_EXP_OPT(ISSUING_DIST_POINT, distpoint, DIST_POINT_NAME, 0),
ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyuser, ASN1_FBOOLEAN, 1),
ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyCA, ASN1_FBOOLEAN, 2),
ASN1_IMP_OPT(ISSUING_DIST_POINT, onlysomereasons, ASN1_BIT_STRING, 3),
ASN1_IMP_OPT(ISSUING_DIST_POINT, indirectCRL, ASN1_FBOOLEAN, 4),
ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyattr, ASN1_FBOOLEAN, 5)
} ASN1_SEQUENCE_END(ISSUING_DIST_POINT)
IMPLEMENT_ASN1_FUNCTIONS(ISSUING_DIST_POINT)
static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out,
int indent);
static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
const X509V3_EXT_METHOD v3_idp = {
NID_issuing_distribution_point, X509V3_EXT_MULTILINE,
ASN1_ITEM_ref(ISSUING_DIST_POINT),
0, 0, 0, 0,
0, 0,
0,
v2i_idp,
i2r_idp, 0,
NULL
};
static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval)
{
ISSUING_DIST_POINT *idp = NULL;
CONF_VALUE *cnf;
char *name, *val;
int i, ret;
idp = ISSUING_DIST_POINT_new();
if (idp == NULL)
goto merr;
for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
cnf = sk_CONF_VALUE_value(nval, i);
name = cnf->name;
val = cnf->value;
ret = set_dist_point_name(&idp->distpoint, ctx, cnf);
if (ret > 0)
continue;
if (ret < 0)
goto err;
if (strcmp(name, "onlyuser") == 0) {
if (!X509V3_get_value_bool(cnf, &idp->onlyuser))
goto err;
} else if (strcmp(name, "onlyCA") == 0) {
if (!X509V3_get_value_bool(cnf, &idp->onlyCA))
goto err;
} else if (strcmp(name, "onlyAA") == 0) {
if (!X509V3_get_value_bool(cnf, &idp->onlyattr))
goto err;
} else if (strcmp(name, "indirectCRL") == 0) {
if (!X509V3_get_value_bool(cnf, &idp->indirectCRL))
goto err;
} else if (strcmp(name, "onlysomereasons") == 0) {
if (!set_reasons(&idp->onlysomereasons, val))
goto err;
} else {
X509V3err(X509V3_F_V2I_IDP, X509V3_R_INVALID_NAME);
X509V3_conf_err(cnf);
goto err;
}
}
return idp;
merr:
X509V3err(X509V3_F_V2I_IDP, ERR_R_MALLOC_FAILURE);
err:
ISSUING_DIST_POINT_free(idp);
return NULL;
}
static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent)
{
int i;
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
BIO_printf(out, "%*s", indent + 2, "");
GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i));
BIO_puts(out, "\n");
}
return 1;
}
static int print_distpoint(BIO *out, DIST_POINT_NAME *dpn, int indent)
{
if (dpn->type == 0) {
BIO_printf(out, "%*sFull Name:\n", indent, "");
print_gens(out, dpn->name.fullname, indent);
} else {
X509_NAME ntmp;
ntmp.entries = dpn->name.relativename;
BIO_printf(out, "%*sRelative Name:\n%*s", indent, "", indent + 2, "");
X509_NAME_print_ex(out, &ntmp, 0, XN_FLAG_ONELINE);
BIO_puts(out, "\n");
}
return 1;
}
static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out,
int indent)
{
ISSUING_DIST_POINT *idp = pidp;
if (idp->distpoint)
print_distpoint(out, idp->distpoint, indent);
if (idp->onlyuser > 0)
BIO_printf(out, "%*sOnly User Certificates\n", indent, "");
if (idp->onlyCA > 0)
BIO_printf(out, "%*sOnly CA Certificates\n", indent, "");
if (idp->indirectCRL > 0)
BIO_printf(out, "%*sIndirect CRL\n", indent, "");
if (idp->onlysomereasons)
print_reasons(out, "Only Some Reasons", idp->onlysomereasons, indent);
if (idp->onlyattr > 0)
BIO_printf(out, "%*sOnly Attribute Certificates\n", indent, "");
if (!idp->distpoint && (idp->onlyuser <= 0) && (idp->onlyCA <= 0)
&& (idp->indirectCRL <= 0) && !idp->onlysomereasons
&& (idp->onlyattr <= 0))
BIO_printf(out, "%*s<EMPTY>\n", indent, "");
return 1;
}
static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out,
int indent)
{
STACK_OF(DIST_POINT) *crld = pcrldp;
DIST_POINT *point;
int i;
for (i = 0; i < sk_DIST_POINT_num(crld); i++) {
BIO_puts(out, "\n");
point = sk_DIST_POINT_value(crld, i);
if (point->distpoint)
print_distpoint(out, point->distpoint, indent);
if (point->reasons)
print_reasons(out, "Reasons", point->reasons, indent);
if (point->CRLissuer) {
BIO_printf(out, "%*sCRL Issuer:\n", indent, "");
print_gens(out, point->CRLissuer, indent);
}
}
return 1;
}
int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname)
{
int i;
STACK_OF(X509_NAME_ENTRY) *frag;
X509_NAME_ENTRY *ne;
if (!dpn || (dpn->type != 1))
return 1;
frag = dpn->name.relativename;
dpn->dpname = X509_NAME_dup(iname);
if (!dpn->dpname)
return 0;
for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++) {
ne = sk_X509_NAME_ENTRY_value(frag, i);
if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1)) {
X509_NAME_free(dpn->dpname);
dpn->dpname = NULL;
return 0;
}
}
/* generate cached encoding of name */
if (i2d_X509_NAME(dpn->dpname, NULL) < 0) {
X509_NAME_free(dpn->dpname);
dpn->dpname = NULL;
return 0;
}
return 1;
}

View file

@ -0,0 +1,53 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/x509v3.h>
#include "ext_dat.h"
static ENUMERATED_NAMES crl_reasons[] = {
{CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"},
{CRL_REASON_KEY_COMPROMISE, "Key Compromise", "keyCompromise"},
{CRL_REASON_CA_COMPROMISE, "CA Compromise", "CACompromise"},
{CRL_REASON_AFFILIATION_CHANGED, "Affiliation Changed",
"affiliationChanged"},
{CRL_REASON_SUPERSEDED, "Superseded", "superseded"},
{CRL_REASON_CESSATION_OF_OPERATION,
"Cessation Of Operation", "cessationOfOperation"},
{CRL_REASON_CERTIFICATE_HOLD, "Certificate Hold", "certificateHold"},
{CRL_REASON_REMOVE_FROM_CRL, "Remove From CRL", "removeFromCRL"},
{CRL_REASON_PRIVILEGE_WITHDRAWN, "Privilege Withdrawn",
"privilegeWithdrawn"},
{CRL_REASON_AA_COMPROMISE, "AA Compromise", "AACompromise"},
{-1, NULL, NULL}
};
const X509V3_EXT_METHOD v3_crl_reason = {
NID_crl_reason, 0, ASN1_ITEM_ref(ASN1_ENUMERATED),
0, 0, 0, 0,
(X509V3_EXT_I2S)i2s_ASN1_ENUMERATED_TABLE,
0,
0, 0, 0, 0,
crl_reasons
};
char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method,
const ASN1_ENUMERATED *e)
{
ENUMERATED_NAMES *enam;
long strval;
strval = ASN1_ENUMERATED_get(e);
for (enam = method->usr_data; enam->lname; enam++) {
if (strval == enam->bitnum)
return OPENSSL_strdup(enam->lname);
}
return i2s_ASN1_ENUMERATED(method, e);
}

View file

@ -0,0 +1,103 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD
*method, void *eku, STACK_OF(CONF_VALUE)
*extlist);
const X509V3_EXT_METHOD v3_ext_ku = {
NID_ext_key_usage, 0,
ASN1_ITEM_ref(EXTENDED_KEY_USAGE),
0, 0, 0, 0,
0, 0,
i2v_EXTENDED_KEY_USAGE,
v2i_EXTENDED_KEY_USAGE,
0, 0,
NULL
};
/* NB OCSP acceptable responses also is a SEQUENCE OF OBJECT */
const X509V3_EXT_METHOD v3_ocsp_accresp = {
NID_id_pkix_OCSP_acceptableResponses, 0,
ASN1_ITEM_ref(EXTENDED_KEY_USAGE),
0, 0, 0, 0,
0, 0,
i2v_EXTENDED_KEY_USAGE,
v2i_EXTENDED_KEY_USAGE,
0, 0,
NULL
};
ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT)
ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE)
IMPLEMENT_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE)
static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD
*method, void *a, STACK_OF(CONF_VALUE)
*ext_list)
{
EXTENDED_KEY_USAGE *eku = a;
int i;
ASN1_OBJECT *obj;
char obj_tmp[80];
for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
obj = sk_ASN1_OBJECT_value(eku, i);
i2t_ASN1_OBJECT(obj_tmp, 80, obj);
X509V3_add_value(NULL, obj_tmp, &ext_list);
}
return ext_list;
}
static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval)
{
EXTENDED_KEY_USAGE *extku;
char *extval;
ASN1_OBJECT *objtmp;
CONF_VALUE *val;
const int num = sk_CONF_VALUE_num(nval);
int i;
extku = sk_ASN1_OBJECT_new_reserve(NULL, num);
if (extku == NULL) {
X509V3err(X509V3_F_V2I_EXTENDED_KEY_USAGE, ERR_R_MALLOC_FAILURE);
sk_ASN1_OBJECT_free(extku);
return NULL;
}
for (i = 0; i < num; i++) {
val = sk_CONF_VALUE_value(nval, i);
if (val->value)
extval = val->value;
else
extval = val->name;
if ((objtmp = OBJ_txt2obj(extval, 0)) == NULL) {
sk_ASN1_OBJECT_pop_free(extku, ASN1_OBJECT_free);
X509V3err(X509V3_F_V2I_EXTENDED_KEY_USAGE,
X509V3_R_INVALID_OBJECT_IDENTIFIER);
X509V3_conf_err(val);
return NULL;
}
sk_ASN1_OBJECT_push(extku, objtmp); /* no failure as it was reserved */
}
return extku;
}

View file

@ -0,0 +1,201 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
ASN1_SEQUENCE(OTHERNAME) = {
ASN1_SIMPLE(OTHERNAME, type_id, ASN1_OBJECT),
/* Maybe have a true ANY DEFINED BY later */
ASN1_EXP(OTHERNAME, value, ASN1_ANY, 0)
} ASN1_SEQUENCE_END(OTHERNAME)
IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME)
ASN1_SEQUENCE(EDIPARTYNAME) = {
ASN1_IMP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0),
ASN1_IMP_OPT(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1)
} ASN1_SEQUENCE_END(EDIPARTYNAME)
IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME)
ASN1_CHOICE(GENERAL_NAME) = {
ASN1_IMP(GENERAL_NAME, d.otherName, OTHERNAME, GEN_OTHERNAME),
ASN1_IMP(GENERAL_NAME, d.rfc822Name, ASN1_IA5STRING, GEN_EMAIL),
ASN1_IMP(GENERAL_NAME, d.dNSName, ASN1_IA5STRING, GEN_DNS),
/* Don't decode this */
ASN1_IMP(GENERAL_NAME, d.x400Address, ASN1_SEQUENCE, GEN_X400),
/* X509_NAME is a CHOICE type so use EXPLICIT */
ASN1_EXP(GENERAL_NAME, d.directoryName, X509_NAME, GEN_DIRNAME),
ASN1_IMP(GENERAL_NAME, d.ediPartyName, EDIPARTYNAME, GEN_EDIPARTY),
ASN1_IMP(GENERAL_NAME, d.uniformResourceIdentifier, ASN1_IA5STRING, GEN_URI),
ASN1_IMP(GENERAL_NAME, d.iPAddress, ASN1_OCTET_STRING, GEN_IPADD),
ASN1_IMP(GENERAL_NAME, d.registeredID, ASN1_OBJECT, GEN_RID)
} ASN1_CHOICE_END(GENERAL_NAME)
IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAME)
ASN1_ITEM_TEMPLATE(GENERAL_NAMES) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, GENERAL_NAME)
ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES)
IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES)
GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a)
{
return (GENERAL_NAME *)ASN1_dup((i2d_of_void *)i2d_GENERAL_NAME,
(d2i_of_void *)d2i_GENERAL_NAME,
(char *)a);
}
/* Returns 0 if they are equal, != 0 otherwise. */
int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b)
{
int result = -1;
if (!a || !b || a->type != b->type)
return -1;
switch (a->type) {
case GEN_X400:
case GEN_EDIPARTY:
result = ASN1_TYPE_cmp(a->d.other, b->d.other);
break;
case GEN_OTHERNAME:
result = OTHERNAME_cmp(a->d.otherName, b->d.otherName);
break;
case GEN_EMAIL:
case GEN_DNS:
case GEN_URI:
result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5);
break;
case GEN_DIRNAME:
result = X509_NAME_cmp(a->d.dirn, b->d.dirn);
break;
case GEN_IPADD:
result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip);
break;
case GEN_RID:
result = OBJ_cmp(a->d.rid, b->d.rid);
break;
}
return result;
}
/* Returns 0 if they are equal, != 0 otherwise. */
int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b)
{
int result = -1;
if (!a || !b)
return -1;
/* Check their type first. */
if ((result = OBJ_cmp(a->type_id, b->type_id)) != 0)
return result;
/* Check the value. */
result = ASN1_TYPE_cmp(a->value, b->value);
return result;
}
void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value)
{
switch (type) {
case GEN_X400:
case GEN_EDIPARTY:
a->d.other = value;
break;
case GEN_OTHERNAME:
a->d.otherName = value;
break;
case GEN_EMAIL:
case GEN_DNS:
case GEN_URI:
a->d.ia5 = value;
break;
case GEN_DIRNAME:
a->d.dirn = value;
break;
case GEN_IPADD:
a->d.ip = value;
break;
case GEN_RID:
a->d.rid = value;
break;
}
a->type = type;
}
void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype)
{
if (ptype)
*ptype = a->type;
switch (a->type) {
case GEN_X400:
case GEN_EDIPARTY:
return a->d.other;
case GEN_OTHERNAME:
return a->d.otherName;
case GEN_EMAIL:
case GEN_DNS:
case GEN_URI:
return a->d.ia5;
case GEN_DIRNAME:
return a->d.dirn;
case GEN_IPADD:
return a->d.ip;
case GEN_RID:
return a->d.rid;
default:
return NULL;
}
}
int GENERAL_NAME_set0_othername(GENERAL_NAME *gen,
ASN1_OBJECT *oid, ASN1_TYPE *value)
{
OTHERNAME *oth;
oth = OTHERNAME_new();
if (oth == NULL)
return 0;
ASN1_TYPE_free(oth->value);
oth->type_id = oid;
oth->value = value;
GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth);
return 1;
}
int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen,
ASN1_OBJECT **poid, ASN1_TYPE **pvalue)
{
if (gen->type != GEN_OTHERNAME)
return 0;
if (poid)
*poid = gen->d.otherName->type_id;
if (pvalue)
*pvalue = gen->d.otherName->value;
return 1;
}

View file

@ -0,0 +1,65 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
const X509V3_EXT_METHOD v3_ns_ia5_list[8] = {
EXT_IA5STRING(NID_netscape_base_url),
EXT_IA5STRING(NID_netscape_revocation_url),
EXT_IA5STRING(NID_netscape_ca_revocation_url),
EXT_IA5STRING(NID_netscape_renewal_url),
EXT_IA5STRING(NID_netscape_ca_policy_url),
EXT_IA5STRING(NID_netscape_ssl_server_name),
EXT_IA5STRING(NID_netscape_comment),
EXT_END
};
char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5)
{
char *tmp;
if (!ia5 || !ia5->length)
return NULL;
if ((tmp = OPENSSL_malloc(ia5->length + 1)) == NULL) {
X509V3err(X509V3_F_I2S_ASN1_IA5STRING, ERR_R_MALLOC_FAILURE);
return NULL;
}
memcpy(tmp, ia5->data, ia5->length);
tmp[ia5->length] = 0;
return tmp;
}
ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *str)
{
ASN1_IA5STRING *ia5;
if (!str) {
X509V3err(X509V3_F_S2I_ASN1_IA5STRING,
X509V3_R_INVALID_NULL_ARGUMENT);
return NULL;
}
if ((ia5 = ASN1_IA5STRING_new()) == NULL)
goto err;
if (!ASN1_STRING_set((ASN1_STRING *)ia5, str, strlen(str))) {
ASN1_IA5STRING_free(ia5);
return NULL;
}
#ifdef CHARSET_EBCDIC
ebcdic2ascii(ia5->data, ia5->data, ia5->length);
#endif /* CHARSET_EBCDIC */
return ia5;
err:
X509V3err(X509V3_F_S2I_ASN1_IA5STRING, ERR_R_MALLOC_FAILURE);
return NULL;
}

View file

@ -0,0 +1,162 @@
/*
* Copyright 1999-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD
*method, AUTHORITY_INFO_ACCESS
*ainfo, STACK_OF(CONF_VALUE)
*ret);
static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD
*method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE)
*nval);
const X509V3_EXT_METHOD v3_info = { NID_info_access, X509V3_EXT_MULTILINE,
ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V) i2v_AUTHORITY_INFO_ACCESS,
(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS,
0, 0,
NULL
};
const X509V3_EXT_METHOD v3_sinfo = { NID_sinfo_access, X509V3_EXT_MULTILINE,
ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V) i2v_AUTHORITY_INFO_ACCESS,
(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS,
0, 0,
NULL
};
ASN1_SEQUENCE(ACCESS_DESCRIPTION) = {
ASN1_SIMPLE(ACCESS_DESCRIPTION, method, ASN1_OBJECT),
ASN1_SIMPLE(ACCESS_DESCRIPTION, location, GENERAL_NAME)
} ASN1_SEQUENCE_END(ACCESS_DESCRIPTION)
IMPLEMENT_ASN1_FUNCTIONS(ACCESS_DESCRIPTION)
ASN1_ITEM_TEMPLATE(AUTHORITY_INFO_ACCESS) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, ACCESS_DESCRIPTION)
ASN1_ITEM_TEMPLATE_END(AUTHORITY_INFO_ACCESS)
IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS)
static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(
X509V3_EXT_METHOD *method, AUTHORITY_INFO_ACCESS *ainfo,
STACK_OF(CONF_VALUE) *ret)
{
ACCESS_DESCRIPTION *desc;
int i, nlen;
char objtmp[80], *ntmp;
CONF_VALUE *vtmp;
STACK_OF(CONF_VALUE) *tret = ret;
for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) {
STACK_OF(CONF_VALUE) *tmp;
desc = sk_ACCESS_DESCRIPTION_value(ainfo, i);
tmp = i2v_GENERAL_NAME(method, desc->location, tret);
if (tmp == NULL)
goto err;
tret = tmp;
vtmp = sk_CONF_VALUE_value(tret, i);
i2t_ASN1_OBJECT(objtmp, sizeof(objtmp), desc->method);
nlen = strlen(objtmp) + 3 + strlen(vtmp->name) + 1;
ntmp = OPENSSL_malloc(nlen);
if (ntmp == NULL)
goto err;
BIO_snprintf(ntmp, nlen, "%s - %s", objtmp, vtmp->name);
OPENSSL_free(vtmp->name);
vtmp->name = ntmp;
}
if (ret == NULL && tret == NULL)
return sk_CONF_VALUE_new_null();
return tret;
err:
X509V3err(X509V3_F_I2V_AUTHORITY_INFO_ACCESS, ERR_R_MALLOC_FAILURE);
if (ret == NULL && tret != NULL)
sk_CONF_VALUE_pop_free(tret, X509V3_conf_free);
return NULL;
}
static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD
*method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE)
*nval)
{
AUTHORITY_INFO_ACCESS *ainfo = NULL;
CONF_VALUE *cnf, ctmp;
ACCESS_DESCRIPTION *acc;
int i, objlen;
const int num = sk_CONF_VALUE_num(nval);
char *objtmp, *ptmp;
if ((ainfo = sk_ACCESS_DESCRIPTION_new_reserve(NULL, num)) == NULL) {
X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (i = 0; i < num; i++) {
cnf = sk_CONF_VALUE_value(nval, i);
if ((acc = ACCESS_DESCRIPTION_new()) == NULL) {
X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS,
ERR_R_MALLOC_FAILURE);
goto err;
}
sk_ACCESS_DESCRIPTION_push(ainfo, acc); /* Cannot fail due to reserve */
ptmp = strchr(cnf->name, ';');
if (!ptmp) {
X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS,
X509V3_R_INVALID_SYNTAX);
goto err;
}
objlen = ptmp - cnf->name;
ctmp.name = ptmp + 1;
ctmp.value = cnf->value;
if (!v2i_GENERAL_NAME_ex(acc->location, method, ctx, &ctmp, 0))
goto err;
if ((objtmp = OPENSSL_strndup(cnf->name, objlen)) == NULL) {
X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS,
ERR_R_MALLOC_FAILURE);
goto err;
}
acc->method = OBJ_txt2obj(objtmp, 0);
if (!acc->method) {
X509V3err(X509V3_F_V2I_AUTHORITY_INFO_ACCESS,
X509V3_R_BAD_OBJECT);
ERR_add_error_data(2, "value=", objtmp);
OPENSSL_free(objtmp);
goto err;
}
OPENSSL_free(objtmp);
}
return ainfo;
err:
sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free);
return NULL;
}
int i2a_ACCESS_DESCRIPTION(BIO *bp, const ACCESS_DESCRIPTION *a)
{
i2a_ASN1_OBJECT(bp, a->method);
return 2;
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/x509v3.h>
#include "ext_dat.h"
const X509V3_EXT_METHOD v3_crl_num = {
NID_crl_number, 0, ASN1_ITEM_ref(ASN1_INTEGER),
0, 0, 0, 0,
(X509V3_EXT_I2S)i2s_ASN1_INTEGER,
0,
0, 0, 0, 0, NULL
};
const X509V3_EXT_METHOD v3_delta_crl = {
NID_delta_crl, 0, ASN1_ITEM_ref(ASN1_INTEGER),
0, 0, 0, 0,
(X509V3_EXT_I2S)i2s_ASN1_INTEGER,
0,
0, 0, 0, 0, NULL
};
static void *s2i_asn1_int(X509V3_EXT_METHOD *meth, X509V3_CTX *ctx,
const char *value)
{
return s2i_ASN1_INTEGER(meth, value);
}
const X509V3_EXT_METHOD v3_inhibit_anyp = {
NID_inhibit_any_policy, 0, ASN1_ITEM_ref(ASN1_INTEGER),
0, 0, 0, 0,
(X509V3_EXT_I2S)i2s_ASN1_INTEGER,
(X509V3_EXT_S2I)s2i_asn1_int,
0, 0, 0, 0, NULL
};

View file

@ -0,0 +1,303 @@
/*
* Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/* X509 v3 extension utilities */
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
static int ext_cmp(const X509V3_EXT_METHOD *const *a,
const X509V3_EXT_METHOD *const *b);
static void ext_list_free(X509V3_EXT_METHOD *ext);
int X509V3_EXT_add(X509V3_EXT_METHOD *ext)
{
if (ext_list == NULL
&& (ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp)) == NULL) {
X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE);
return 0;
}
if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
X509V3err(X509V3_F_X509V3_EXT_ADD, ERR_R_MALLOC_FAILURE);
return 0;
}
return 1;
}
static int ext_cmp(const X509V3_EXT_METHOD *const *a,
const X509V3_EXT_METHOD *const *b)
{
return ((*a)->ext_nid - (*b)->ext_nid);
}
DECLARE_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *,
const X509V3_EXT_METHOD *, ext);
IMPLEMENT_OBJ_BSEARCH_CMP_FN(const X509V3_EXT_METHOD *,
const X509V3_EXT_METHOD *, ext);
#include "standard_exts.h"
const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid)
{
X509V3_EXT_METHOD tmp;
const X509V3_EXT_METHOD *t = &tmp, *const *ret;
int idx;
if (nid < 0)
return NULL;
tmp.ext_nid = nid;
ret = OBJ_bsearch_ext(&t, standard_exts, STANDARD_EXTENSION_COUNT);
if (ret)
return *ret;
if (!ext_list)
return NULL;
idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp);
return sk_X509V3_EXT_METHOD_value(ext_list, idx);
}
const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext)
{
int nid;
if ((nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext))) == NID_undef)
return NULL;
return X509V3_EXT_get_nid(nid);
}
int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist)
{
for (; extlist->ext_nid != -1; extlist++)
if (!X509V3_EXT_add(extlist))
return 0;
return 1;
}
int X509V3_EXT_add_alias(int nid_to, int nid_from)
{
const X509V3_EXT_METHOD *ext;
X509V3_EXT_METHOD *tmpext;
if ((ext = X509V3_EXT_get_nid(nid_from)) == NULL) {
X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, X509V3_R_EXTENSION_NOT_FOUND);
return 0;
}
if ((tmpext = OPENSSL_malloc(sizeof(*tmpext))) == NULL) {
X509V3err(X509V3_F_X509V3_EXT_ADD_ALIAS, ERR_R_MALLOC_FAILURE);
return 0;
}
*tmpext = *ext;
tmpext->ext_nid = nid_to;
tmpext->ext_flags |= X509V3_EXT_DYNAMIC;
return X509V3_EXT_add(tmpext);
}
void X509V3_EXT_cleanup(void)
{
sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free);
ext_list = NULL;
}
static void ext_list_free(X509V3_EXT_METHOD *ext)
{
if (ext->ext_flags & X509V3_EXT_DYNAMIC)
OPENSSL_free(ext);
}
/*
* Legacy function: we don't need to add standard extensions any more because
* they are now kept in ext_dat.h.
*/
int X509V3_add_standard_extensions(void)
{
return 1;
}
/* Return an extension internal structure */
void *X509V3_EXT_d2i(X509_EXTENSION *ext)
{
const X509V3_EXT_METHOD *method;
const unsigned char *p;
ASN1_STRING *extvalue;
int extlen;
if ((method = X509V3_EXT_get(ext)) == NULL)
return NULL;
extvalue = X509_EXTENSION_get_data(ext);
p = ASN1_STRING_get0_data(extvalue);
extlen = ASN1_STRING_length(extvalue);
if (method->it)
return ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it));
return method->d2i(NULL, &p, extlen);
}
/*-
* Get critical flag and decoded version of extension from a NID.
* The "idx" variable returns the last found extension and can
* be used to retrieve multiple extensions of the same NID.
* However multiple extensions with the same NID is usually
* due to a badly encoded certificate so if idx is NULL we
* choke if multiple extensions exist.
* The "crit" variable is set to the critical value.
* The return value is the decoded extension or NULL on
* error. The actual error can have several different causes,
* the value of *crit reflects the cause:
* >= 0, extension found but not decoded (reflects critical value).
* -1 extension not found.
* -2 extension occurs more than once.
*/
void *X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit,
int *idx)
{
int lastpos, i;
X509_EXTENSION *ex, *found_ex = NULL;
if (!x) {
if (idx)
*idx = -1;
if (crit)
*crit = -1;
return NULL;
}
if (idx)
lastpos = *idx + 1;
else
lastpos = 0;
if (lastpos < 0)
lastpos = 0;
for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) {
ex = sk_X509_EXTENSION_value(x, i);
if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) == nid) {
if (idx) {
*idx = i;
found_ex = ex;
break;
} else if (found_ex) {
/* Found more than one */
if (crit)
*crit = -2;
return NULL;
}
found_ex = ex;
}
}
if (found_ex) {
/* Found it */
if (crit)
*crit = X509_EXTENSION_get_critical(found_ex);
return X509V3_EXT_d2i(found_ex);
}
/* Extension not found */
if (idx)
*idx = -1;
if (crit)
*crit = -1;
return NULL;
}
/*
* This function is a general extension append, replace and delete utility.
* The precise operation is governed by the 'flags' value. The 'crit' and
* 'value' arguments (if relevant) are the extensions internal structure.
*/
int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
int crit, unsigned long flags)
{
int errcode, extidx = -1;
X509_EXTENSION *ext = NULL, *extmp;
STACK_OF(X509_EXTENSION) *ret = NULL;
unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
/*
* If appending we don't care if it exists, otherwise look for existing
* extension.
*/
if (ext_op != X509V3_ADD_APPEND)
extidx = X509v3_get_ext_by_NID(*x, nid, -1);
/* See if extension exists */
if (extidx >= 0) {
/* If keep existing, nothing to do */
if (ext_op == X509V3_ADD_KEEP_EXISTING)
return 1;
/* If default then its an error */
if (ext_op == X509V3_ADD_DEFAULT) {
errcode = X509V3_R_EXTENSION_EXISTS;
goto err;
}
/* If delete, just delete it */
if (ext_op == X509V3_ADD_DELETE) {
if (!sk_X509_EXTENSION_delete(*x, extidx))
return -1;
return 1;
}
} else {
/*
* If replace existing or delete, error since extension must exist
*/
if ((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
(ext_op == X509V3_ADD_DELETE)) {
errcode = X509V3_R_EXTENSION_NOT_FOUND;
goto err;
}
}
/*
* If we get this far then we have to create an extension: could have
* some flags for alternative encoding schemes...
*/
ext = X509V3_EXT_i2d(nid, crit, value);
if (!ext) {
X509V3err(X509V3_F_X509V3_ADD1_I2D,
X509V3_R_ERROR_CREATING_EXTENSION);
return 0;
}
/* If extension exists replace it.. */
if (extidx >= 0) {
extmp = sk_X509_EXTENSION_value(*x, extidx);
X509_EXTENSION_free(extmp);
if (!sk_X509_EXTENSION_set(*x, extidx, ext))
return -1;
return 1;
}
ret = *x;
if (*x == NULL
&& (ret = sk_X509_EXTENSION_new_null()) == NULL)
goto m_fail;
if (!sk_X509_EXTENSION_push(ret, ext))
goto m_fail;
*x = ret;
return 1;
m_fail:
/* X509V3err(X509V3_F_X509V3_ADD1_I2D, ERR_R_MALLOC_FAILURE); */
if (ret != *x)
sk_X509_EXTENSION_free(ret);
X509_EXTENSION_free(ext);
return -1;
err:
if (!(flags & X509V3_ADD_SILENT))
X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode);
return 0;
}

View file

@ -0,0 +1,675 @@
/*
* Copyright 2003-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include <stdio.h>
#include "internal/asn1_int.h"
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "internal/x509_int.h"
#include "ext_dat.h"
static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
BIO *bp, int ind);
static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
STACK_OF(GENERAL_SUBTREE) *trees, BIO *bp,
int ind, const char *name);
static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip);
static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc);
static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen);
static int nc_dn(X509_NAME *sub, X509_NAME *nm);
static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns);
static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml);
static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base);
static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base);
const X509V3_EXT_METHOD v3_name_constraints = {
NID_name_constraints, 0,
ASN1_ITEM_ref(NAME_CONSTRAINTS),
0, 0, 0, 0,
0, 0,
0, v2i_NAME_CONSTRAINTS,
i2r_NAME_CONSTRAINTS, 0,
NULL
};
ASN1_SEQUENCE(GENERAL_SUBTREE) = {
ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME),
ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0),
ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1)
} ASN1_SEQUENCE_END(GENERAL_SUBTREE)
ASN1_SEQUENCE(NAME_CONSTRAINTS) = {
ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees,
GENERAL_SUBTREE, 0),
ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees,
GENERAL_SUBTREE, 1),
} ASN1_SEQUENCE_END(NAME_CONSTRAINTS)
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
/*
* We cannot use strncasecmp here because that applies locale specific rules.
* For example in Turkish 'I' is not the uppercase character for 'i'. We need to
* do a simple ASCII case comparison ignoring the locale (that is why we use
* numeric constants below).
*/
static int ia5ncasecmp(const char *s1, const char *s2, size_t n)
{
for (; n > 0; n--, s1++, s2++) {
if (*s1 != *s2) {
unsigned char c1 = (unsigned char)*s1, c2 = (unsigned char)*s2;
/* Convert to lower case */
if (c1 >= 0x41 /* A */ && c1 <= 0x5A /* Z */)
c1 += 0x20;
if (c2 >= 0x41 /* A */ && c2 <= 0x5A /* Z */)
c2 += 0x20;
if (c1 == c2)
continue;
if (c1 < c2)
return -1;
/* c1 > c2 */
return 1;
} else if (*s1 == 0) {
/* If we get here we know that *s2 == 0 too */
return 0;
}
}
return 0;
}
static int ia5casecmp(const char *s1, const char *s2)
{
return ia5ncasecmp(s1, s2, SIZE_MAX);
}
static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
{
int i;
CONF_VALUE tval, *val;
STACK_OF(GENERAL_SUBTREE) **ptree = NULL;
NAME_CONSTRAINTS *ncons = NULL;
GENERAL_SUBTREE *sub = NULL;
ncons = NAME_CONSTRAINTS_new();
if (ncons == NULL)
goto memerr;
for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
val = sk_CONF_VALUE_value(nval, i);
if (strncmp(val->name, "permitted", 9) == 0 && val->name[9]) {
ptree = &ncons->permittedSubtrees;
tval.name = val->name + 10;
} else if (strncmp(val->name, "excluded", 8) == 0 && val->name[8]) {
ptree = &ncons->excludedSubtrees;
tval.name = val->name + 9;
} else {
X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, X509V3_R_INVALID_SYNTAX);
goto err;
}
tval.value = val->value;
sub = GENERAL_SUBTREE_new();
if (sub == NULL)
goto memerr;
if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1))
goto err;
if (*ptree == NULL)
*ptree = sk_GENERAL_SUBTREE_new_null();
if (*ptree == NULL || !sk_GENERAL_SUBTREE_push(*ptree, sub))
goto memerr;
sub = NULL;
}
return ncons;
memerr:
X509V3err(X509V3_F_V2I_NAME_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
err:
NAME_CONSTRAINTS_free(ncons);
GENERAL_SUBTREE_free(sub);
return NULL;
}
static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a,
BIO *bp, int ind)
{
NAME_CONSTRAINTS *ncons = a;
do_i2r_name_constraints(method, ncons->permittedSubtrees,
bp, ind, "Permitted");
do_i2r_name_constraints(method, ncons->excludedSubtrees,
bp, ind, "Excluded");
return 1;
}
static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method,
STACK_OF(GENERAL_SUBTREE) *trees,
BIO *bp, int ind, const char *name)
{
GENERAL_SUBTREE *tree;
int i;
if (sk_GENERAL_SUBTREE_num(trees) > 0)
BIO_printf(bp, "%*s%s:\n", ind, "", name);
for (i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) {
tree = sk_GENERAL_SUBTREE_value(trees, i);
BIO_printf(bp, "%*s", ind + 2, "");
if (tree->base->type == GEN_IPADD)
print_nc_ipadd(bp, tree->base->d.ip);
else
GENERAL_NAME_print(bp, tree->base);
BIO_puts(bp, "\n");
}
return 1;
}
static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
{
int i, len;
unsigned char *p;
p = ip->data;
len = ip->length;
BIO_puts(bp, "IP:");
if (len == 8) {
BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d",
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
} else if (len == 32) {
for (i = 0; i < 16; i++) {
BIO_printf(bp, "%X", p[0] << 8 | p[1]);
p += 2;
if (i == 7)
BIO_puts(bp, "/");
else if (i != 15)
BIO_puts(bp, ":");
}
} else
BIO_printf(bp, "IP Address:<invalid>");
return 1;
}
#define NAME_CHECK_MAX (1 << 20)
static int add_lengths(int *out, int a, int b)
{
/* sk_FOO_num(NULL) returns -1 but is effectively 0 when iterating. */
if (a < 0)
a = 0;
if (b < 0)
b = 0;
if (a > INT_MAX - b)
return 0;
*out = a + b;
return 1;
}
/*-
* Check a certificate conforms to a specified set of constraints.
* Return values:
* X509_V_OK: All constraints obeyed.
* X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation.
* X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation.
* X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type.
* X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type.
* X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax.
* X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name
*/
int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc)
{
int r, i, name_count, constraint_count;
X509_NAME *nm;
nm = X509_get_subject_name(x);
/*
* Guard against certificates with an excessive number of names or
* constraints causing a computationally expensive name constraints check.
*/
if (!add_lengths(&name_count, X509_NAME_entry_count(nm),
sk_GENERAL_NAME_num(x->altname))
|| !add_lengths(&constraint_count,
sk_GENERAL_SUBTREE_num(nc->permittedSubtrees),
sk_GENERAL_SUBTREE_num(nc->excludedSubtrees))
|| (name_count > 0 && constraint_count > NAME_CHECK_MAX / name_count))
return X509_V_ERR_UNSPECIFIED;
if (X509_NAME_entry_count(nm) > 0) {
GENERAL_NAME gntmp;
gntmp.type = GEN_DIRNAME;
gntmp.d.directoryName = nm;
r = nc_match(&gntmp, nc);
if (r != X509_V_OK)
return r;
gntmp.type = GEN_EMAIL;
/* Process any email address attributes in subject name */
for (i = -1;;) {
const X509_NAME_ENTRY *ne;
i = X509_NAME_get_index_by_NID(nm, NID_pkcs9_emailAddress, i);
if (i == -1)
break;
ne = X509_NAME_get_entry(nm, i);
gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne);
if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING)
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
r = nc_match(&gntmp, nc);
if (r != X509_V_OK)
return r;
}
}
for (i = 0; i < sk_GENERAL_NAME_num(x->altname); i++) {
GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, i);
r = nc_match(gen, nc);
if (r != X509_V_OK)
return r;
}
return X509_V_OK;
}
static int cn2dnsid(ASN1_STRING *cn, unsigned char **dnsid, size_t *idlen)
{
int utf8_length;
unsigned char *utf8_value;
int i;
int isdnsname = 0;
/* Don't leave outputs uninitialized */
*dnsid = NULL;
*idlen = 0;
/*-
* Per RFC 6125, DNS-IDs representing internationalized domain names appear
* in certificates in A-label encoded form:
*
* https://tools.ietf.org/html/rfc6125#section-6.4.2
*
* The same applies to CNs which are intended to represent DNS names.
* However, while in the SAN DNS-IDs are IA5Strings, as CNs they may be
* needlessly encoded in 16-bit Unicode. We perform a conversion to UTF-8
* to ensure that we get an ASCII representation of any CNs that are
* representable as ASCII, but just not encoded as ASCII. The UTF-8 form
* may contain some non-ASCII octets, and that's fine, such CNs are not
* valid legacy DNS names.
*
* Note, 'int' is the return type of ASN1_STRING_to_UTF8() so that's what
* we must use for 'utf8_length'.
*/
if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, cn)) < 0)
return X509_V_ERR_OUT_OF_MEM;
/*
* Some certificates have had names that include a *trailing* NUL byte.
* Remove these harmless NUL characters. They would otherwise yield false
* alarms with the following embedded NUL check.
*/
while (utf8_length > 0 && utf8_value[utf8_length - 1] == '\0')
--utf8_length;
/* Reject *embedded* NULs */
if ((size_t)utf8_length != strlen((char *)utf8_value)) {
OPENSSL_free(utf8_value);
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
}
/*
* XXX: Deviation from strict DNS name syntax, also check names with '_'
* Check DNS name syntax, any '-' or '.' must be internal,
* and on either side of each '.' we can't have a '-' or '.'.
*
* If the name has just one label, we don't consider it a DNS name. This
* means that "CN=sometld" cannot be precluded by DNS name constraints, but
* that is not a problem.
*/
for (i = 0; i < utf8_length; ++i) {
unsigned char c = utf8_value[i];
if ((c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| c == '_')
continue;
/* Dot and hyphen cannot be first or last. */
if (i > 0 && i < utf8_length - 1) {
if (c == '-')
continue;
/*
* Next to a dot the preceding and following characters must not be
* another dot or a hyphen. Otherwise, record that the name is
* plausible, since it has two or more labels.
*/
if (c == '.'
&& utf8_value[i + 1] != '.'
&& utf8_value[i - 1] != '-'
&& utf8_value[i + 1] != '-') {
isdnsname = 1;
continue;
}
}
isdnsname = 0;
break;
}
if (isdnsname) {
*dnsid = utf8_value;
*idlen = (size_t)utf8_length;
return X509_V_OK;
}
OPENSSL_free(utf8_value);
return X509_V_OK;
}
/*
* Check CN against DNS-ID name constraints.
*/
int NAME_CONSTRAINTS_check_CN(X509 *x, NAME_CONSTRAINTS *nc)
{
int r, i;
X509_NAME *nm = X509_get_subject_name(x);
ASN1_STRING stmp;
GENERAL_NAME gntmp;
stmp.flags = 0;
stmp.type = V_ASN1_IA5STRING;
gntmp.type = GEN_DNS;
gntmp.d.dNSName = &stmp;
/* Process any commonName attributes in subject name */
for (i = -1;;) {
X509_NAME_ENTRY *ne;
ASN1_STRING *cn;
unsigned char *idval;
size_t idlen;
i = X509_NAME_get_index_by_NID(nm, NID_commonName, i);
if (i == -1)
break;
ne = X509_NAME_get_entry(nm, i);
cn = X509_NAME_ENTRY_get_data(ne);
/* Only process attributes that look like host names */
if ((r = cn2dnsid(cn, &idval, &idlen)) != X509_V_OK)
return r;
if (idlen == 0)
continue;
stmp.length = idlen;
stmp.data = idval;
r = nc_match(&gntmp, nc);
OPENSSL_free(idval);
if (r != X509_V_OK)
return r;
}
return X509_V_OK;
}
static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc)
{
GENERAL_SUBTREE *sub;
int i, r, match = 0;
/*
* Permitted subtrees: if any subtrees exist of matching the type at
* least one subtree must match.
*/
for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) {
sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
if (gen->type != sub->base->type)
continue;
if (sub->minimum || sub->maximum)
return X509_V_ERR_SUBTREE_MINMAX;
/* If we already have a match don't bother trying any more */
if (match == 2)
continue;
if (match == 0)
match = 1;
r = nc_match_single(gen, sub->base);
if (r == X509_V_OK)
match = 2;
else if (r != X509_V_ERR_PERMITTED_VIOLATION)
return r;
}
if (match == 1)
return X509_V_ERR_PERMITTED_VIOLATION;
/* Excluded subtrees: must not match any of these */
for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) {
sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i);
if (gen->type != sub->base->type)
continue;
if (sub->minimum || sub->maximum)
return X509_V_ERR_SUBTREE_MINMAX;
r = nc_match_single(gen, sub->base);
if (r == X509_V_OK)
return X509_V_ERR_EXCLUDED_VIOLATION;
else if (r != X509_V_ERR_PERMITTED_VIOLATION)
return r;
}
return X509_V_OK;
}
static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base)
{
switch (base->type) {
case GEN_DIRNAME:
return nc_dn(gen->d.directoryName, base->d.directoryName);
case GEN_DNS:
return nc_dns(gen->d.dNSName, base->d.dNSName);
case GEN_EMAIL:
return nc_email(gen->d.rfc822Name, base->d.rfc822Name);
case GEN_URI:
return nc_uri(gen->d.uniformResourceIdentifier,
base->d.uniformResourceIdentifier);
case GEN_IPADD:
return nc_ip(gen->d.iPAddress, base->d.iPAddress);
default:
return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
}
}
/*
* directoryName name constraint matching. The canonical encoding of
* X509_NAME makes this comparison easy. It is matched if the subtree is a
* subset of the name.
*/
static int nc_dn(X509_NAME *nm, X509_NAME *base)
{
/* Ensure canonical encodings are up to date. */
if (nm->modified && i2d_X509_NAME(nm, NULL) < 0)
return X509_V_ERR_OUT_OF_MEM;
if (base->modified && i2d_X509_NAME(base, NULL) < 0)
return X509_V_ERR_OUT_OF_MEM;
if (base->canon_enclen > nm->canon_enclen)
return X509_V_ERR_PERMITTED_VIOLATION;
if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen))
return X509_V_ERR_PERMITTED_VIOLATION;
return X509_V_OK;
}
static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base)
{
char *baseptr = (char *)base->data;
char *dnsptr = (char *)dns->data;
/* Empty matches everything */
if (!*baseptr)
return X509_V_OK;
/*
* Otherwise can add zero or more components on the left so compare RHS
* and if dns is longer and expect '.' as preceding character.
*/
if (dns->length > base->length) {
dnsptr += dns->length - base->length;
if (*baseptr != '.' && dnsptr[-1] != '.')
return X509_V_ERR_PERMITTED_VIOLATION;
}
if (ia5casecmp(baseptr, dnsptr))
return X509_V_ERR_PERMITTED_VIOLATION;
return X509_V_OK;
}
static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base)
{
const char *baseptr = (char *)base->data;
const char *emlptr = (char *)eml->data;
const char *baseat = strchr(baseptr, '@');
const char *emlat = strchr(emlptr, '@');
if (!emlat)
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
/* Special case: initial '.' is RHS match */
if (!baseat && (*baseptr == '.')) {
if (eml->length > base->length) {
emlptr += eml->length - base->length;
if (ia5casecmp(baseptr, emlptr) == 0)
return X509_V_OK;
}
return X509_V_ERR_PERMITTED_VIOLATION;
}
/* If we have anything before '@' match local part */
if (baseat) {
if (baseat != baseptr) {
if ((baseat - baseptr) != (emlat - emlptr))
return X509_V_ERR_PERMITTED_VIOLATION;
/* Case sensitive match of local part */
if (strncmp(baseptr, emlptr, emlat - emlptr))
return X509_V_ERR_PERMITTED_VIOLATION;
}
/* Position base after '@' */
baseptr = baseat + 1;
}
emlptr = emlat + 1;
/* Just have hostname left to match: case insensitive */
if (ia5casecmp(baseptr, emlptr))
return X509_V_ERR_PERMITTED_VIOLATION;
return X509_V_OK;
}
static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base)
{
const char *baseptr = (char *)base->data;
const char *hostptr = (char *)uri->data;
const char *p = strchr(hostptr, ':');
int hostlen;
/* Check for foo:// and skip past it */
if (!p || (p[1] != '/') || (p[2] != '/'))
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
hostptr = p + 3;
/* Determine length of hostname part of URI */
/* Look for a port indicator as end of hostname first */
p = strchr(hostptr, ':');
/* Otherwise look for trailing slash */
if (!p)
p = strchr(hostptr, '/');
if (!p)
hostlen = strlen(hostptr);
else
hostlen = p - hostptr;
if (hostlen == 0)
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
/* Special case: initial '.' is RHS match */
if (*baseptr == '.') {
if (hostlen > base->length) {
p = hostptr + hostlen - base->length;
if (ia5ncasecmp(p, baseptr, base->length) == 0)
return X509_V_OK;
}
return X509_V_ERR_PERMITTED_VIOLATION;
}
if ((base->length != (int)hostlen)
|| ia5ncasecmp(hostptr, baseptr, hostlen))
return X509_V_ERR_PERMITTED_VIOLATION;
return X509_V_OK;
}
static int nc_ip(ASN1_OCTET_STRING *ip, ASN1_OCTET_STRING *base)
{
int hostlen, baselen, i;
unsigned char *hostptr, *baseptr, *maskptr;
hostptr = ip->data;
hostlen = ip->length;
baseptr = base->data;
baselen = base->length;
/* Invalid if not IPv4 or IPv6 */
if (!((hostlen == 4) || (hostlen == 16)))
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
if (!((baselen == 8) || (baselen == 32)))
return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
/* Do not match IPv4 with IPv6 */
if (hostlen * 2 != baselen)
return X509_V_ERR_PERMITTED_VIOLATION;
maskptr = base->data + hostlen;
/* Considering possible not aligned base ipAddress */
/* Not checking for wrong mask definition: i.e.: 255.0.255.0 */
for (i = 0; i < hostlen; i++)
if ((hostptr[i] & maskptr[i]) != (baseptr[i] & maskptr[i]))
return X509_V_ERR_PERMITTED_VIOLATION;
return X509_V_OK;
}

View file

@ -0,0 +1,325 @@
/*
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* This file is dual-licensed and is also available under the following
* terms:
*
* Copyright (c) 2004 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* 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. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 INSTITUTE OR 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.
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext,
BIO *out, int indent);
static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, char *str);
const X509V3_EXT_METHOD v3_pci =
{ NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION),
0, 0, 0, 0,
0, 0,
NULL, NULL,
(X509V3_EXT_I2R)i2r_pci,
(X509V3_EXT_R2I)r2i_pci,
NULL,
};
static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci,
BIO *out, int indent)
{
BIO_printf(out, "%*sPath Length Constraint: ", indent, "");
if (pci->pcPathLengthConstraint)
i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint);
else
BIO_printf(out, "infinite");
BIO_puts(out, "\n");
BIO_printf(out, "%*sPolicy Language: ", indent, "");
i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage);
BIO_puts(out, "\n");
if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data)
BIO_printf(out, "%*sPolicy Text: %s\n", indent, "",
pci->proxyPolicy->policy->data);
return 1;
}
static int process_pci_value(CONF_VALUE *val,
ASN1_OBJECT **language, ASN1_INTEGER **pathlen,
ASN1_OCTET_STRING **policy)
{
int free_policy = 0;
if (strcmp(val->name, "language") == 0) {
if (*language) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE,
X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED);
X509V3_conf_err(val);
return 0;
}
if ((*language = OBJ_txt2obj(val->value, 0)) == NULL) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE,
X509V3_R_INVALID_OBJECT_IDENTIFIER);
X509V3_conf_err(val);
return 0;
}
} else if (strcmp(val->name, "pathlen") == 0) {
if (*pathlen) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE,
X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED);
X509V3_conf_err(val);
return 0;
}
if (!X509V3_get_value_int(val, pathlen)) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE,
X509V3_R_POLICY_PATH_LENGTH);
X509V3_conf_err(val);
return 0;
}
} else if (strcmp(val->name, "policy") == 0) {
unsigned char *tmp_data = NULL;
long val_len;
if (!*policy) {
*policy = ASN1_OCTET_STRING_new();
if (*policy == NULL) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
X509V3_conf_err(val);
return 0;
}
free_policy = 1;
}
if (strncmp(val->value, "hex:", 4) == 0) {
unsigned char *tmp_data2 =
OPENSSL_hexstr2buf(val->value + 4, &val_len);
if (!tmp_data2) {
X509V3_conf_err(val);
goto err;
}
tmp_data = OPENSSL_realloc((*policy)->data,
(*policy)->length + val_len + 1);
if (tmp_data) {
(*policy)->data = tmp_data;
memcpy(&(*policy)->data[(*policy)->length],
tmp_data2, val_len);
(*policy)->length += val_len;
(*policy)->data[(*policy)->length] = '\0';
} else {
OPENSSL_free(tmp_data2);
/*
* realloc failure implies the original data space is b0rked
* too!
*/
OPENSSL_free((*policy)->data);
(*policy)->data = NULL;
(*policy)->length = 0;
X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
X509V3_conf_err(val);
goto err;
}
OPENSSL_free(tmp_data2);
} else if (strncmp(val->value, "file:", 5) == 0) {
unsigned char buf[2048];
int n;
BIO *b = BIO_new_file(val->value + 5, "r");
if (!b) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB);
X509V3_conf_err(val);
goto err;
}
while ((n = BIO_read(b, buf, sizeof(buf))) > 0
|| (n == 0 && BIO_should_retry(b))) {
if (!n)
continue;
tmp_data = OPENSSL_realloc((*policy)->data,
(*policy)->length + n + 1);
if (!tmp_data) {
OPENSSL_free((*policy)->data);
(*policy)->data = NULL;
(*policy)->length = 0;
X509V3err(X509V3_F_PROCESS_PCI_VALUE,
ERR_R_MALLOC_FAILURE);
X509V3_conf_err(val);
BIO_free_all(b);
goto err;
}
(*policy)->data = tmp_data;
memcpy(&(*policy)->data[(*policy)->length], buf, n);
(*policy)->length += n;
(*policy)->data[(*policy)->length] = '\0';
}
BIO_free_all(b);
if (n < 0) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_BIO_LIB);
X509V3_conf_err(val);
goto err;
}
} else if (strncmp(val->value, "text:", 5) == 0) {
val_len = strlen(val->value + 5);
tmp_data = OPENSSL_realloc((*policy)->data,
(*policy)->length + val_len + 1);
if (tmp_data) {
(*policy)->data = tmp_data;
memcpy(&(*policy)->data[(*policy)->length],
val->value + 5, val_len);
(*policy)->length += val_len;
(*policy)->data[(*policy)->length] = '\0';
} else {
/*
* realloc failure implies the original data space is b0rked
* too!
*/
OPENSSL_free((*policy)->data);
(*policy)->data = NULL;
(*policy)->length = 0;
X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
X509V3_conf_err(val);
goto err;
}
} else {
X509V3err(X509V3_F_PROCESS_PCI_VALUE,
X509V3_R_INCORRECT_POLICY_SYNTAX_TAG);
X509V3_conf_err(val);
goto err;
}
if (!tmp_data) {
X509V3err(X509V3_F_PROCESS_PCI_VALUE, ERR_R_MALLOC_FAILURE);
X509V3_conf_err(val);
goto err;
}
}
return 1;
err:
if (free_policy) {
ASN1_OCTET_STRING_free(*policy);
*policy = NULL;
}
return 0;
}
static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, char *value)
{
PROXY_CERT_INFO_EXTENSION *pci = NULL;
STACK_OF(CONF_VALUE) *vals;
ASN1_OBJECT *language = NULL;
ASN1_INTEGER *pathlen = NULL;
ASN1_OCTET_STRING *policy = NULL;
int i, j;
vals = X509V3_parse_list(value);
for (i = 0; i < sk_CONF_VALUE_num(vals); i++) {
CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i);
if (!cnf->name || (*cnf->name != '@' && !cnf->value)) {
X509V3err(X509V3_F_R2I_PCI,
X509V3_R_INVALID_PROXY_POLICY_SETTING);
X509V3_conf_err(cnf);
goto err;
}
if (*cnf->name == '@') {
STACK_OF(CONF_VALUE) *sect;
int success_p = 1;
sect = X509V3_get_section(ctx, cnf->name + 1);
if (!sect) {
X509V3err(X509V3_F_R2I_PCI, X509V3_R_INVALID_SECTION);
X509V3_conf_err(cnf);
goto err;
}
for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) {
success_p =
process_pci_value(sk_CONF_VALUE_value(sect, j),
&language, &pathlen, &policy);
}
X509V3_section_free(ctx, sect);
if (!success_p)
goto err;
} else {
if (!process_pci_value(cnf, &language, &pathlen, &policy)) {
X509V3_conf_err(cnf);
goto err;
}
}
}
/* Language is mandatory */
if (!language) {
X509V3err(X509V3_F_R2I_PCI,
X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED);
goto err;
}
i = OBJ_obj2nid(language);
if ((i == NID_Independent || i == NID_id_ppl_inheritAll) && policy) {
X509V3err(X509V3_F_R2I_PCI,
X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY);
goto err;
}
pci = PROXY_CERT_INFO_EXTENSION_new();
if (pci == NULL) {
X509V3err(X509V3_F_R2I_PCI, ERR_R_MALLOC_FAILURE);
goto err;
}
pci->proxyPolicy->policyLanguage = language;
language = NULL;
pci->proxyPolicy->policy = policy;
policy = NULL;
pci->pcPathLengthConstraint = pathlen;
pathlen = NULL;
goto end;
err:
ASN1_OBJECT_free(language);
ASN1_INTEGER_free(pathlen);
pathlen = NULL;
ASN1_OCTET_STRING_free(policy);
policy = NULL;
PROXY_CERT_INFO_EXTENSION_free(pci);
pci = NULL;
end:
sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
return pci;
}

View file

@ -0,0 +1,64 @@
/*
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/*
* This file is dual-licensed and is also available under the following
* terms:
*
* Copyright (c) 2004 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* 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. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 INSTITUTE OR 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.
*/
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
ASN1_SEQUENCE(PROXY_POLICY) =
{
ASN1_SIMPLE(PROXY_POLICY,policyLanguage,ASN1_OBJECT),
ASN1_OPT(PROXY_POLICY,policy,ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(PROXY_POLICY)
IMPLEMENT_ASN1_FUNCTIONS(PROXY_POLICY)
ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION) =
{
ASN1_OPT(PROXY_CERT_INFO_EXTENSION,pcPathLengthConstraint,ASN1_INTEGER),
ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION,proxyPolicy,PROXY_POLICY)
} ASN1_SEQUENCE_END(PROXY_CERT_INFO_EXTENSION)
IMPLEMENT_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION)

View file

@ -0,0 +1,91 @@
/*
* Copyright 2003-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static STACK_OF(CONF_VALUE) *i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD
*method, void *bcons, STACK_OF(CONF_VALUE)
*extlist);
static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *values);
const X509V3_EXT_METHOD v3_policy_constraints = {
NID_policy_constraints, 0,
ASN1_ITEM_ref(POLICY_CONSTRAINTS),
0, 0, 0, 0,
0, 0,
i2v_POLICY_CONSTRAINTS,
v2i_POLICY_CONSTRAINTS,
NULL, NULL,
NULL
};
ASN1_SEQUENCE(POLICY_CONSTRAINTS) = {
ASN1_IMP_OPT(POLICY_CONSTRAINTS, requireExplicitPolicy, ASN1_INTEGER,0),
ASN1_IMP_OPT(POLICY_CONSTRAINTS, inhibitPolicyMapping, ASN1_INTEGER,1)
} ASN1_SEQUENCE_END(POLICY_CONSTRAINTS)
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS)
static STACK_OF(CONF_VALUE) *i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD
*method, void *a, STACK_OF(CONF_VALUE)
*extlist)
{
POLICY_CONSTRAINTS *pcons = a;
X509V3_add_value_int("Require Explicit Policy",
pcons->requireExplicitPolicy, &extlist);
X509V3_add_value_int("Inhibit Policy Mapping",
pcons->inhibitPolicyMapping, &extlist);
return extlist;
}
static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *values)
{
POLICY_CONSTRAINTS *pcons = NULL;
CONF_VALUE *val;
int i;
if ((pcons = POLICY_CONSTRAINTS_new()) == NULL) {
X509V3err(X509V3_F_V2I_POLICY_CONSTRAINTS, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (i = 0; i < sk_CONF_VALUE_num(values); i++) {
val = sk_CONF_VALUE_value(values, i);
if (strcmp(val->name, "requireExplicitPolicy") == 0) {
if (!X509V3_get_value_int(val, &pcons->requireExplicitPolicy))
goto err;
} else if (strcmp(val->name, "inhibitPolicyMapping") == 0) {
if (!X509V3_get_value_int(val, &pcons->inhibitPolicyMapping))
goto err;
} else {
X509V3err(X509V3_F_V2I_POLICY_CONSTRAINTS, X509V3_R_INVALID_NAME);
X509V3_conf_err(val);
goto err;
}
}
if (!pcons->inhibitPolicyMapping && !pcons->requireExplicitPolicy) {
X509V3err(X509V3_F_V2I_POLICY_CONSTRAINTS,
X509V3_R_ILLEGAL_EMPTY_EXTENSION);
goto err;
}
return pcons;
err:
POLICY_CONSTRAINTS_free(pcons);
return NULL;
}

View file

@ -0,0 +1,52 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method,
PKEY_USAGE_PERIOD *usage, BIO *out,
int indent);
const X509V3_EXT_METHOD v3_pkey_usage_period = {
NID_private_key_usage_period, 0, ASN1_ITEM_ref(PKEY_USAGE_PERIOD),
0, 0, 0, 0,
0, 0, 0, 0,
(X509V3_EXT_I2R)i2r_PKEY_USAGE_PERIOD, NULL,
NULL
};
ASN1_SEQUENCE(PKEY_USAGE_PERIOD) = {
ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notBefore, ASN1_GENERALIZEDTIME, 0),
ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notAfter, ASN1_GENERALIZEDTIME, 1)
} ASN1_SEQUENCE_END(PKEY_USAGE_PERIOD)
IMPLEMENT_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD)
static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method,
PKEY_USAGE_PERIOD *usage, BIO *out,
int indent)
{
BIO_printf(out, "%*s", indent, "");
if (usage->notBefore) {
BIO_write(out, "Not Before: ", 12);
ASN1_GENERALIZEDTIME_print(out, usage->notBefore);
if (usage->notAfter)
BIO_write(out, ", ", 2);
}
if (usage->notAfter) {
BIO_write(out, "Not After: ", 11);
ASN1_GENERALIZEDTIME_print(out, usage->notAfter);
}
return 1;
}

View file

@ -0,0 +1,112 @@
/*
* Copyright 2003-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
static STACK_OF(CONF_VALUE) *i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD
*method, void *pmps, STACK_OF(CONF_VALUE)
*extlist);
const X509V3_EXT_METHOD v3_policy_mappings = {
NID_policy_mappings, 0,
ASN1_ITEM_ref(POLICY_MAPPINGS),
0, 0, 0, 0,
0, 0,
i2v_POLICY_MAPPINGS,
v2i_POLICY_MAPPINGS,
0, 0,
NULL
};
ASN1_SEQUENCE(POLICY_MAPPING) = {
ASN1_SIMPLE(POLICY_MAPPING, issuerDomainPolicy, ASN1_OBJECT),
ASN1_SIMPLE(POLICY_MAPPING, subjectDomainPolicy, ASN1_OBJECT)
} ASN1_SEQUENCE_END(POLICY_MAPPING)
ASN1_ITEM_TEMPLATE(POLICY_MAPPINGS) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, POLICY_MAPPINGS,
POLICY_MAPPING)
ASN1_ITEM_TEMPLATE_END(POLICY_MAPPINGS)
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING)
static STACK_OF(CONF_VALUE) *i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD
*method, void *a, STACK_OF(CONF_VALUE)
*ext_list)
{
POLICY_MAPPINGS *pmaps = a;
POLICY_MAPPING *pmap;
int i;
char obj_tmp1[80];
char obj_tmp2[80];
for (i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) {
pmap = sk_POLICY_MAPPING_value(pmaps, i);
i2t_ASN1_OBJECT(obj_tmp1, 80, pmap->issuerDomainPolicy);
i2t_ASN1_OBJECT(obj_tmp2, 80, pmap->subjectDomainPolicy);
X509V3_add_value(obj_tmp1, obj_tmp2, &ext_list);
}
return ext_list;
}
static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
{
POLICY_MAPPING *pmap = NULL;
ASN1_OBJECT *obj1 = NULL, *obj2 = NULL;
CONF_VALUE *val;
POLICY_MAPPINGS *pmaps;
const int num = sk_CONF_VALUE_num(nval);
int i;
if ((pmaps = sk_POLICY_MAPPING_new_reserve(NULL, num)) == NULL) {
X509V3err(X509V3_F_V2I_POLICY_MAPPINGS, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (i = 0; i < num; i++) {
val = sk_CONF_VALUE_value(nval, i);
if (!val->value || !val->name) {
X509V3err(X509V3_F_V2I_POLICY_MAPPINGS,
X509V3_R_INVALID_OBJECT_IDENTIFIER);
X509V3_conf_err(val);
goto err;
}
obj1 = OBJ_txt2obj(val->name, 0);
obj2 = OBJ_txt2obj(val->value, 0);
if (!obj1 || !obj2) {
X509V3err(X509V3_F_V2I_POLICY_MAPPINGS,
X509V3_R_INVALID_OBJECT_IDENTIFIER);
X509V3_conf_err(val);
goto err;
}
pmap = POLICY_MAPPING_new();
if (pmap == NULL) {
X509V3err(X509V3_F_V2I_POLICY_MAPPINGS, ERR_R_MALLOC_FAILURE);
goto err;
}
pmap->issuerDomainPolicy = obj1;
pmap->subjectDomainPolicy = obj2;
obj1 = obj2 = NULL;
sk_POLICY_MAPPING_push(pmaps, pmap); /* no failure as it was reserved */
}
return pmaps;
err:
ASN1_OBJECT_free(obj1);
ASN1_OBJECT_free(obj2);
sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free);
return NULL;
}

View file

@ -0,0 +1,210 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
/* X509 v3 extension utilities */
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/x509v3.h>
/* Extension printing routines */
static int unknown_ext_print(BIO *out, const unsigned char *ext, int extlen,
unsigned long flag, int indent, int supported);
/* Print out a name+value stack */
void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent,
int ml)
{
int i;
CONF_VALUE *nval;
if (!val)
return;
if (!ml || !sk_CONF_VALUE_num(val)) {
BIO_printf(out, "%*s", indent, "");
if (!sk_CONF_VALUE_num(val))
BIO_puts(out, "<EMPTY>\n");
}
for (i = 0; i < sk_CONF_VALUE_num(val); i++) {
if (ml)
BIO_printf(out, "%*s", indent, "");
else if (i > 0)
BIO_printf(out, ", ");
nval = sk_CONF_VALUE_value(val, i);
if (!nval->name)
BIO_puts(out, nval->value);
else if (!nval->value)
BIO_puts(out, nval->name);
#ifndef CHARSET_EBCDIC
else
BIO_printf(out, "%s:%s", nval->name, nval->value);
#else
else {
int len;
char *tmp;
len = strlen(nval->value) + 1;
tmp = OPENSSL_malloc(len);
if (tmp != NULL) {
ascii2ebcdic(tmp, nval->value, len);
BIO_printf(out, "%s:%s", nval->name, tmp);
OPENSSL_free(tmp);
}
}
#endif
if (ml)
BIO_puts(out, "\n");
}
}
/* Main routine: print out a general extension */
int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag,
int indent)
{
void *ext_str = NULL;
char *value = NULL;
ASN1_OCTET_STRING *extoct;
const unsigned char *p;
int extlen;
const X509V3_EXT_METHOD *method;
STACK_OF(CONF_VALUE) *nval = NULL;
int ok = 1;
extoct = X509_EXTENSION_get_data(ext);
p = ASN1_STRING_get0_data(extoct);
extlen = ASN1_STRING_length(extoct);
if ((method = X509V3_EXT_get(ext)) == NULL)
return unknown_ext_print(out, p, extlen, flag, indent, 0);
if (method->it)
ext_str = ASN1_item_d2i(NULL, &p, extlen, ASN1_ITEM_ptr(method->it));
else
ext_str = method->d2i(NULL, &p, extlen);
if (!ext_str)
return unknown_ext_print(out, p, extlen, flag, indent, 1);
if (method->i2s) {
if ((value = method->i2s(method, ext_str)) == NULL) {
ok = 0;
goto err;
}
#ifndef CHARSET_EBCDIC
BIO_printf(out, "%*s%s", indent, "", value);
#else
{
int len;
char *tmp;
len = strlen(value) + 1;
tmp = OPENSSL_malloc(len);
if (tmp != NULL) {
ascii2ebcdic(tmp, value, len);
BIO_printf(out, "%*s%s", indent, "", tmp);
OPENSSL_free(tmp);
}
}
#endif
} else if (method->i2v) {
if ((nval = method->i2v(method, ext_str, NULL)) == NULL) {
ok = 0;
goto err;
}
X509V3_EXT_val_prn(out, nval, indent,
method->ext_flags & X509V3_EXT_MULTILINE);
} else if (method->i2r) {
if (!method->i2r(method, ext_str, out, indent))
ok = 0;
} else
ok = 0;
err:
sk_CONF_VALUE_pop_free(nval, X509V3_conf_free);
OPENSSL_free(value);
if (method->it)
ASN1_item_free(ext_str, ASN1_ITEM_ptr(method->it));
else
method->ext_free(ext_str);
return ok;
}
int X509V3_extensions_print(BIO *bp, const char *title,
const STACK_OF(X509_EXTENSION) *exts,
unsigned long flag, int indent)
{
int i, j;
if (sk_X509_EXTENSION_num(exts) <= 0)
return 1;
if (title) {
BIO_printf(bp, "%*s%s:\n", indent, "", title);
indent += 4;
}
for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
X509_EXTENSION *ex;
ex = sk_X509_EXTENSION_value(exts, i);
if (indent && BIO_printf(bp, "%*s", indent, "") <= 0)
return 0;
obj = X509_EXTENSION_get_object(ex);
i2a_ASN1_OBJECT(bp, obj);
j = X509_EXTENSION_get_critical(ex);
if (BIO_printf(bp, ": %s\n", j ? "critical" : "") <= 0)
return 0;
if (!X509V3_EXT_print(bp, ex, flag, indent + 4)) {
BIO_printf(bp, "%*s", indent + 4, "");
ASN1_STRING_print(bp, X509_EXTENSION_get_data(ex));
}
if (BIO_write(bp, "\n", 1) <= 0)
return 0;
}
return 1;
}
static int unknown_ext_print(BIO *out, const unsigned char *ext, int extlen,
unsigned long flag, int indent, int supported)
{
switch (flag & X509V3_EXT_UNKNOWN_MASK) {
case X509V3_EXT_DEFAULT:
return 0;
case X509V3_EXT_ERROR_UNKNOWN:
if (supported)
BIO_printf(out, "%*s<Parse Error>", indent, "");
else
BIO_printf(out, "%*s<Not Supported>", indent, "");
return 1;
case X509V3_EXT_PARSE_UNKNOWN:
return ASN1_parse_dump(out, ext, extlen, indent, -1);
case X509V3_EXT_DUMP_UNKNOWN:
return BIO_dump_indent(out, (const char *)ext, extlen, indent);
default:
return 1;
}
}
#ifndef OPENSSL_NO_STDIO
int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent)
{
BIO *bio_tmp;
int ret;
if ((bio_tmp = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL)
return 0;
ret = X509V3_EXT_print(bio_tmp, ext, flag, indent);
BIO_free(bio_tmp);
return ret;
}
#endif

View file

@ -0,0 +1,890 @@
/*
* Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include "internal/numbers.h"
#include <openssl/x509v3.h>
#include <openssl/x509_vfy.h>
#include "internal/x509_int.h"
#include "internal/tsan_assist.h"
static void x509v3_cache_extensions(X509 *x);
static int check_ssl_ca(const X509 *x);
static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int purpose_smime(const X509 *x, int ca);
static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
int ca);
static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b);
static void xptable_free(X509_PURPOSE *p);
static X509_PURPOSE xstandard[] = {
{X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0,
check_purpose_ssl_client, "SSL client", "sslclient", NULL},
{X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
check_purpose_ssl_server, "SSL server", "sslserver", NULL},
{X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0,
check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
{X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign,
"S/MIME signing", "smimesign", NULL},
{X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0,
check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
{X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign,
"CRL signing", "crlsign", NULL},
{X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, "Any Purpose", "any",
NULL},
{X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper,
"OCSP helper", "ocsphelper", NULL},
{X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0,
check_purpose_timestamp_sign, "Time Stamp signing", "timestampsign",
NULL},
};
#define X509_PURPOSE_COUNT OSSL_NELEM(xstandard)
static STACK_OF(X509_PURPOSE) *xptable = NULL;
static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b)
{
return (*a)->purpose - (*b)->purpose;
}
/*
* As much as I'd like to make X509_check_purpose use a "const" X509* I
* really can't because it does recalculate hashes and do other non-const
* things.
*/
int X509_check_purpose(X509 *x, int id, int ca)
{
int idx;
const X509_PURPOSE *pt;
x509v3_cache_extensions(x);
/* Return if side-effect only call */
if (id == -1)
return 1;
idx = X509_PURPOSE_get_by_id(id);
if (idx == -1)
return -1;
pt = X509_PURPOSE_get0(idx);
return pt->check_purpose(pt, x, ca);
}
int X509_PURPOSE_set(int *p, int purpose)
{
if (X509_PURPOSE_get_by_id(purpose) == -1) {
X509V3err(X509V3_F_X509_PURPOSE_SET, X509V3_R_INVALID_PURPOSE);
return 0;
}
*p = purpose;
return 1;
}
int X509_PURPOSE_get_count(void)
{
if (!xptable)
return X509_PURPOSE_COUNT;
return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
}
X509_PURPOSE *X509_PURPOSE_get0(int idx)
{
if (idx < 0)
return NULL;
if (idx < (int)X509_PURPOSE_COUNT)
return xstandard + idx;
return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
}
int X509_PURPOSE_get_by_sname(const char *sname)
{
int i;
X509_PURPOSE *xptmp;
for (i = 0; i < X509_PURPOSE_get_count(); i++) {
xptmp = X509_PURPOSE_get0(i);
if (strcmp(xptmp->sname, sname) == 0)
return i;
}
return -1;
}
int X509_PURPOSE_get_by_id(int purpose)
{
X509_PURPOSE tmp;
int idx;
if ((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX))
return purpose - X509_PURPOSE_MIN;
if (xptable == NULL)
return -1;
tmp.purpose = purpose;
idx = sk_X509_PURPOSE_find(xptable, &tmp);
if (idx < 0)
return -1;
return idx + X509_PURPOSE_COUNT;
}
int X509_PURPOSE_add(int id, int trust, int flags,
int (*ck) (const X509_PURPOSE *, const X509 *, int),
const char *name, const char *sname, void *arg)
{
int idx;
X509_PURPOSE *ptmp;
/*
* This is set according to what we change: application can't set it
*/
flags &= ~X509_PURPOSE_DYNAMIC;
/* This will always be set for application modified trust entries */
flags |= X509_PURPOSE_DYNAMIC_NAME;
/* Get existing entry if any */
idx = X509_PURPOSE_get_by_id(id);
/* Need a new entry */
if (idx == -1) {
if ((ptmp = OPENSSL_malloc(sizeof(*ptmp))) == NULL) {
X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
return 0;
}
ptmp->flags = X509_PURPOSE_DYNAMIC;
} else
ptmp = X509_PURPOSE_get0(idx);
/* OPENSSL_free existing name if dynamic */
if (ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
OPENSSL_free(ptmp->name);
OPENSSL_free(ptmp->sname);
}
/* dup supplied name */
ptmp->name = OPENSSL_strdup(name);
ptmp->sname = OPENSSL_strdup(sname);
if (!ptmp->name || !ptmp->sname) {
X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
goto err;
}
/* Keep the dynamic flag of existing entry */
ptmp->flags &= X509_PURPOSE_DYNAMIC;
/* Set all other flags */
ptmp->flags |= flags;
ptmp->purpose = id;
ptmp->trust = trust;
ptmp->check_purpose = ck;
ptmp->usr_data = arg;
/* If its a new entry manage the dynamic table */
if (idx == -1) {
if (xptable == NULL
&& (xptable = sk_X509_PURPOSE_new(xp_cmp)) == NULL) {
X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
X509V3err(X509V3_F_X509_PURPOSE_ADD, ERR_R_MALLOC_FAILURE);
goto err;
}
}
return 1;
err:
if (idx == -1) {
OPENSSL_free(ptmp->name);
OPENSSL_free(ptmp->sname);
OPENSSL_free(ptmp);
}
return 0;
}
static void xptable_free(X509_PURPOSE *p)
{
if (!p)
return;
if (p->flags & X509_PURPOSE_DYNAMIC) {
if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
OPENSSL_free(p->name);
OPENSSL_free(p->sname);
}
OPENSSL_free(p);
}
}
void X509_PURPOSE_cleanup(void)
{
sk_X509_PURPOSE_pop_free(xptable, xptable_free);
xptable = NULL;
}
int X509_PURPOSE_get_id(const X509_PURPOSE *xp)
{
return xp->purpose;
}
char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp)
{
return xp->name;
}
char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp)
{
return xp->sname;
}
int X509_PURPOSE_get_trust(const X509_PURPOSE *xp)
{
return xp->trust;
}
static int nid_cmp(const int *a, const int *b)
{
return *a - *b;
}
DECLARE_OBJ_BSEARCH_CMP_FN(int, int, nid);
IMPLEMENT_OBJ_BSEARCH_CMP_FN(int, int, nid);
int X509_supported_extension(X509_EXTENSION *ex)
{
/*
* This table is a list of the NIDs of supported extensions: that is
* those which are used by the verify process. If an extension is
* critical and doesn't appear in this list then the verify process will
* normally reject the certificate. The list must be kept in numerical
* order because it will be searched using bsearch.
*/
static const int supported_nids[] = {
NID_netscape_cert_type, /* 71 */
NID_key_usage, /* 83 */
NID_subject_alt_name, /* 85 */
NID_basic_constraints, /* 87 */
NID_certificate_policies, /* 89 */
NID_crl_distribution_points, /* 103 */
NID_ext_key_usage, /* 126 */
#ifndef OPENSSL_NO_RFC3779
NID_sbgp_ipAddrBlock, /* 290 */
NID_sbgp_autonomousSysNum, /* 291 */
#endif
NID_policy_constraints, /* 401 */
NID_proxyCertInfo, /* 663 */
NID_name_constraints, /* 666 */
NID_policy_mappings, /* 747 */
NID_inhibit_any_policy /* 748 */
};
int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
if (ex_nid == NID_undef)
return 0;
if (OBJ_bsearch_nid(&ex_nid, supported_nids, OSSL_NELEM(supported_nids)))
return 1;
return 0;
}
static void setup_dp(X509 *x, DIST_POINT *dp)
{
X509_NAME *iname = NULL;
int i;
if (dp->reasons) {
if (dp->reasons->length > 0)
dp->dp_reasons = dp->reasons->data[0];
if (dp->reasons->length > 1)
dp->dp_reasons |= (dp->reasons->data[1] << 8);
dp->dp_reasons &= CRLDP_ALL_REASONS;
} else
dp->dp_reasons = CRLDP_ALL_REASONS;
if (!dp->distpoint || (dp->distpoint->type != 1))
return;
for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) {
GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i);
if (gen->type == GEN_DIRNAME) {
iname = gen->d.directoryName;
break;
}
}
if (!iname)
iname = X509_get_issuer_name(x);
DIST_POINT_set_dpname(dp->distpoint, iname);
}
static void setup_crldp(X509 *x)
{
int i;
x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL);
for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++)
setup_dp(x, sk_DIST_POINT_value(x->crldp, i));
}
#define V1_ROOT (EXFLAG_V1|EXFLAG_SS)
#define ku_reject(x, usage) \
(((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage)))
#define xku_reject(x, usage) \
(((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage)))
#define ns_reject(x, usage) \
(((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage)))
static void x509v3_cache_extensions(X509 *x)
{
BASIC_CONSTRAINTS *bs;
PROXY_CERT_INFO_EXTENSION *pci;
ASN1_BIT_STRING *usage;
ASN1_BIT_STRING *ns;
EXTENDED_KEY_USAGE *extusage;
X509_EXTENSION *ex;
int i;
#ifdef tsan_ld_acq
/* fast lock-free check, see end of the function for details. */
if (tsan_ld_acq((TSAN_QUALIFIER int *)&x->ex_cached))
return;
#endif
CRYPTO_THREAD_write_lock(x->lock);
if (x->ex_flags & EXFLAG_SET) {
CRYPTO_THREAD_unlock(x->lock);
return;
}
X509_digest(x, EVP_sha1(), x->sha1_hash, NULL);
/* V1 should mean no extensions ... */
if (!X509_get_version(x))
x->ex_flags |= EXFLAG_V1;
/* Handle basic constraints */
if ((bs = X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) {
if (bs->ca)
x->ex_flags |= EXFLAG_CA;
if (bs->pathlen) {
if ((bs->pathlen->type == V_ASN1_NEG_INTEGER)
|| !bs->ca) {
x->ex_flags |= EXFLAG_INVALID;
x->ex_pathlen = 0;
} else
x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen);
} else
x->ex_pathlen = -1;
BASIC_CONSTRAINTS_free(bs);
x->ex_flags |= EXFLAG_BCONS;
}
/* Handle proxy certificates */
if ((pci = X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
if (x->ex_flags & EXFLAG_CA
|| X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0
|| X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) {
x->ex_flags |= EXFLAG_INVALID;
}
if (pci->pcPathLengthConstraint) {
x->ex_pcpathlen = ASN1_INTEGER_get(pci->pcPathLengthConstraint);
} else
x->ex_pcpathlen = -1;
PROXY_CERT_INFO_EXTENSION_free(pci);
x->ex_flags |= EXFLAG_PROXY;
}
/* Handle key usage */
if ((usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) {
if (usage->length > 0) {
x->ex_kusage = usage->data[0];
if (usage->length > 1)
x->ex_kusage |= usage->data[1] << 8;
} else
x->ex_kusage = 0;
x->ex_flags |= EXFLAG_KUSAGE;
ASN1_BIT_STRING_free(usage);
}
x->ex_xkusage = 0;
if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) {
x->ex_flags |= EXFLAG_XKUSAGE;
for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) {
switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {
case NID_server_auth:
x->ex_xkusage |= XKU_SSL_SERVER;
break;
case NID_client_auth:
x->ex_xkusage |= XKU_SSL_CLIENT;
break;
case NID_email_protect:
x->ex_xkusage |= XKU_SMIME;
break;
case NID_code_sign:
x->ex_xkusage |= XKU_CODE_SIGN;
break;
case NID_ms_sgc:
case NID_ns_sgc:
x->ex_xkusage |= XKU_SGC;
break;
case NID_OCSP_sign:
x->ex_xkusage |= XKU_OCSP_SIGN;
break;
case NID_time_stamp:
x->ex_xkusage |= XKU_TIMESTAMP;
break;
case NID_dvcs:
x->ex_xkusage |= XKU_DVCS;
break;
case NID_anyExtendedKeyUsage:
x->ex_xkusage |= XKU_ANYEKU;
break;
}
}
sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);
}
if ((ns = X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) {
if (ns->length > 0)
x->ex_nscert = ns->data[0];
else
x->ex_nscert = 0;
x->ex_flags |= EXFLAG_NSCERT;
ASN1_BIT_STRING_free(ns);
}
x->skid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
x->akid = X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
/* Does subject name match issuer ? */
if (!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) {
x->ex_flags |= EXFLAG_SI;
/* If SKID matches AKID also indicate self signed */
if (X509_check_akid(x, x->akid) == X509_V_OK &&
!ku_reject(x, KU_KEY_CERT_SIGN))
x->ex_flags |= EXFLAG_SS;
}
x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
x->nc = X509_get_ext_d2i(x, NID_name_constraints, &i, NULL);
if (!x->nc && (i != -1))
x->ex_flags |= EXFLAG_INVALID;
setup_crldp(x);
#ifndef OPENSSL_NO_RFC3779
x->rfc3779_addr = X509_get_ext_d2i(x, NID_sbgp_ipAddrBlock, NULL, NULL);
x->rfc3779_asid = X509_get_ext_d2i(x, NID_sbgp_autonomousSysNum,
NULL, NULL);
#endif
for (i = 0; i < X509_get_ext_count(x); i++) {
ex = X509_get_ext(x, i);
if (OBJ_obj2nid(X509_EXTENSION_get_object(ex))
== NID_freshest_crl)
x->ex_flags |= EXFLAG_FRESHEST;
if (!X509_EXTENSION_get_critical(ex))
continue;
if (!X509_supported_extension(ex)) {
x->ex_flags |= EXFLAG_CRITICAL;
break;
}
}
x509_init_sig_info(x);
x->ex_flags |= EXFLAG_SET;
#ifdef tsan_st_rel
tsan_st_rel((TSAN_QUALIFIER int *)&x->ex_cached, 1);
/*
* Above store triggers fast lock-free check in the beginning of the
* function. But one has to ensure that the structure is "stable", i.e.
* all stores are visible on all processors. Hence the release fence.
*/
#endif
CRYPTO_THREAD_unlock(x->lock);
}
/*-
* CA checks common to all purposes
* return codes:
* 0 not a CA
* 1 is a CA
* 2 basicConstraints absent so "maybe" a CA
* 3 basicConstraints absent but self signed V1.
* 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
*/
static int check_ca(const X509 *x)
{
/* keyUsage if present should allow cert signing */
if (ku_reject(x, KU_KEY_CERT_SIGN))
return 0;
if (x->ex_flags & EXFLAG_BCONS) {
if (x->ex_flags & EXFLAG_CA)
return 1;
/* If basicConstraints says not a CA then say so */
else
return 0;
} else {
/* we support V1 roots for... uh, I don't really know why. */
if ((x->ex_flags & V1_ROOT) == V1_ROOT)
return 3;
/*
* If key usage present it must have certSign so tolerate it
*/
else if (x->ex_flags & EXFLAG_KUSAGE)
return 4;
/* Older certificates could have Netscape-specific CA types */
else if (x->ex_flags & EXFLAG_NSCERT && x->ex_nscert & NS_ANY_CA)
return 5;
/* can this still be regarded a CA certificate? I doubt it */
return 0;
}
}
void X509_set_proxy_flag(X509 *x)
{
x->ex_flags |= EXFLAG_PROXY;
}
void X509_set_proxy_pathlen(X509 *x, long l)
{
x->ex_pcpathlen = l;
}
int X509_check_ca(X509 *x)
{
x509v3_cache_extensions(x);
return check_ca(x);
}
/* Check SSL CA: common checks for SSL client and server */
static int check_ssl_ca(const X509 *x)
{
int ca_ret;
ca_ret = check_ca(x);
if (!ca_ret)
return 0;
/* check nsCertType if present */
if (ca_ret != 5 || x->ex_nscert & NS_SSL_CA)
return ca_ret;
else
return 0;
}
static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x,
int ca)
{
if (xku_reject(x, XKU_SSL_CLIENT))
return 0;
if (ca)
return check_ssl_ca(x);
/* We need to do digital signatures or key agreement */
if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_KEY_AGREEMENT))
return 0;
/* nsCertType if present should allow SSL client use */
if (ns_reject(x, NS_SSL_CLIENT))
return 0;
return 1;
}
/*
* Key usage needed for TLS/SSL server: digital signature, encipherment or
* key agreement. The ssl code can check this more thoroughly for individual
* key types.
*/
#define KU_TLS \
KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT
static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x,
int ca)
{
if (xku_reject(x, XKU_SSL_SERVER | XKU_SGC))
return 0;
if (ca)
return check_ssl_ca(x);
if (ns_reject(x, NS_SSL_SERVER))
return 0;
if (ku_reject(x, KU_TLS))
return 0;
return 1;
}
static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x,
int ca)
{
int ret;
ret = check_purpose_ssl_server(xp, x, ca);
if (!ret || ca)
return ret;
/* We need to encipher or Netscape complains */
if (ku_reject(x, KU_KEY_ENCIPHERMENT))
return 0;
return ret;
}
/* common S/MIME checks */
static int purpose_smime(const X509 *x, int ca)
{
if (xku_reject(x, XKU_SMIME))
return 0;
if (ca) {
int ca_ret;
ca_ret = check_ca(x);
if (!ca_ret)
return 0;
/* check nsCertType if present */
if (ca_ret != 5 || x->ex_nscert & NS_SMIME_CA)
return ca_ret;
else
return 0;
}
if (x->ex_flags & EXFLAG_NSCERT) {
if (x->ex_nscert & NS_SMIME)
return 1;
/* Workaround for some buggy certificates */
if (x->ex_nscert & NS_SSL_CLIENT)
return 2;
return 0;
}
return 1;
}
static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x,
int ca)
{
int ret;
ret = purpose_smime(x, ca);
if (!ret || ca)
return ret;
if (ku_reject(x, KU_DIGITAL_SIGNATURE | KU_NON_REPUDIATION))
return 0;
return ret;
}
static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x,
int ca)
{
int ret;
ret = purpose_smime(x, ca);
if (!ret || ca)
return ret;
if (ku_reject(x, KU_KEY_ENCIPHERMENT))
return 0;
return ret;
}
static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x,
int ca)
{
if (ca) {
int ca_ret;
if ((ca_ret = check_ca(x)) != 2)
return ca_ret;
else
return 0;
}
if (ku_reject(x, KU_CRL_SIGN))
return 0;
return 1;
}
/*
* OCSP helper: this is *not* a full OCSP check. It just checks that each CA
* is valid. Additional checks must be made on the chain.
*/
static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca)
{
/*
* Must be a valid CA. Should we really support the "I don't know" value
* (2)?
*/
if (ca)
return check_ca(x);
/* leaf certificate is checked in OCSP_verify() */
return 1;
}
static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x,
int ca)
{
int i_ext;
/* If ca is true we must return if this is a valid CA certificate. */
if (ca)
return check_ca(x);
/*
* Check the optional key usage field:
* if Key Usage is present, it must be one of digitalSignature
* and/or nonRepudiation (other values are not consistent and shall
* be rejected).
*/
if ((x->ex_flags & EXFLAG_KUSAGE)
&& ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) ||
!(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE))))
return 0;
/* Only time stamp key usage is permitted and it's required. */
if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP)
return 0;
/* Extended Key Usage MUST be critical */
i_ext = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
if (i_ext >= 0) {
X509_EXTENSION *ext = X509_get_ext((X509 *)x, i_ext);
if (!X509_EXTENSION_get_critical(ext))
return 0;
}
return 1;
}
static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca)
{
return 1;
}
/*-
* Various checks to see if one certificate issued the second.
* This can be used to prune a set of possible issuer certificates
* which have been looked up using some simple method such as by
* subject name.
* These are:
* 1. Check issuer_name(subject) == subject_name(issuer)
* 2. If akid(subject) exists check it matches issuer
* 3. If key_usage(issuer) exists check it supports certificate signing
* returns 0 for OK, positive for reason for mismatch, reasons match
* codes for X509_verify_cert()
*/
int X509_check_issued(X509 *issuer, X509 *subject)
{
if (X509_NAME_cmp(X509_get_subject_name(issuer),
X509_get_issuer_name(subject)))
return X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
x509v3_cache_extensions(issuer);
x509v3_cache_extensions(subject);
if (subject->akid) {
int ret = X509_check_akid(issuer, subject->akid);
if (ret != X509_V_OK)
return ret;
}
if (subject->ex_flags & EXFLAG_PROXY) {
if (ku_reject(issuer, KU_DIGITAL_SIGNATURE))
return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
} else if (ku_reject(issuer, KU_KEY_CERT_SIGN))
return X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
return X509_V_OK;
}
int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid)
{
if (!akid)
return X509_V_OK;
/* Check key ids (if present) */
if (akid->keyid && issuer->skid &&
ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid))
return X509_V_ERR_AKID_SKID_MISMATCH;
/* Check serial number */
if (akid->serial &&
ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial))
return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
/* Check issuer name */
if (akid->issuer) {
/*
* Ugh, for some peculiar reason AKID includes SEQUENCE OF
* GeneralName. So look for a DirName. There may be more than one but
* we only take any notice of the first.
*/
GENERAL_NAMES *gens;
GENERAL_NAME *gen;
X509_NAME *nm = NULL;
int i;
gens = akid->issuer;
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
gen = sk_GENERAL_NAME_value(gens, i);
if (gen->type == GEN_DIRNAME) {
nm = gen->d.dirn;
break;
}
}
if (nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer)))
return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
}
return X509_V_OK;
}
uint32_t X509_get_extension_flags(X509 *x)
{
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, -1);
return x->ex_flags;
}
uint32_t X509_get_key_usage(X509 *x)
{
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, -1);
if (x->ex_flags & EXFLAG_KUSAGE)
return x->ex_kusage;
return UINT32_MAX;
}
uint32_t X509_get_extended_key_usage(X509 *x)
{
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, -1);
if (x->ex_flags & EXFLAG_XKUSAGE)
return x->ex_xkusage;
return UINT32_MAX;
}
const ASN1_OCTET_STRING *X509_get0_subject_key_id(X509 *x)
{
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, -1);
return x->skid;
}
const ASN1_OCTET_STRING *X509_get0_authority_key_id(X509 *x)
{
/* Call for side-effect of computing hash and caching extensions */
X509_check_purpose(x, -1, -1);
return (x->akid != NULL ? x->akid->keyid : NULL);
}
long X509_get_pathlen(X509 *x)
{
/* Called for side effect of caching extensions */
if (X509_check_purpose(x, -1, -1) != 1
|| (x->ex_flags & EXFLAG_BCONS) == 0)
return -1;
return x->ex_pathlen;
}
long X509_get_proxy_pathlen(X509 *x)
{
/* Called for side effect of caching extensions */
if (X509_check_purpose(x, -1, -1) != 1
|| (x->ex_flags & EXFLAG_PROXY) == 0)
return -1;
return x->ex_pcpathlen;
}

View file

@ -0,0 +1,106 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/x509v3.h>
#include "internal/x509_int.h"
#include "ext_dat.h"
static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, char *str);
const X509V3_EXT_METHOD v3_skey_id = {
NID_subject_key_identifier, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING),
0, 0, 0, 0,
(X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING,
(X509V3_EXT_S2I)s2i_skey_id,
0, 0, 0, 0,
NULL
};
char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
const ASN1_OCTET_STRING *oct)
{
return OPENSSL_buf2hexstr(oct->data, oct->length);
}
ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, const char *str)
{
ASN1_OCTET_STRING *oct;
long length;
if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
X509V3err(X509V3_F_S2I_ASN1_OCTET_STRING, ERR_R_MALLOC_FAILURE);
return NULL;
}
if ((oct->data = OPENSSL_hexstr2buf(str, &length)) == NULL) {
ASN1_OCTET_STRING_free(oct);
return NULL;
}
oct->length = length;
return oct;
}
static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, char *str)
{
ASN1_OCTET_STRING *oct;
X509_PUBKEY *pubkey;
const unsigned char *pk;
int pklen;
unsigned char pkey_dig[EVP_MAX_MD_SIZE];
unsigned int diglen;
if (strcmp(str, "hash"))
return s2i_ASN1_OCTET_STRING(method, ctx, str);
if ((oct = ASN1_OCTET_STRING_new()) == NULL) {
X509V3err(X509V3_F_S2I_SKEY_ID, ERR_R_MALLOC_FAILURE);
return NULL;
}
if (ctx && (ctx->flags == CTX_TEST))
return oct;
if (!ctx || (!ctx->subject_req && !ctx->subject_cert)) {
X509V3err(X509V3_F_S2I_SKEY_ID, X509V3_R_NO_PUBLIC_KEY);
goto err;
}
if (ctx->subject_req)
pubkey = ctx->subject_req->req_info.pubkey;
else
pubkey = ctx->subject_cert->cert_info.key;
if (pubkey == NULL) {
X509V3err(X509V3_F_S2I_SKEY_ID, X509V3_R_NO_PUBLIC_KEY);
goto err;
}
X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey);
if (!EVP_Digest(pk, pklen, pkey_dig, &diglen, EVP_sha1(), NULL))
goto err;
if (!ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) {
X509V3err(X509V3_F_S2I_SKEY_ID, ERR_R_MALLOC_FAILURE);
goto err;
}
return oct;
err:
ASN1_OCTET_STRING_free(oct);
return NULL;
}

View file

@ -0,0 +1,226 @@
/*
* Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include "internal/cryptlib.h"
#include <openssl/conf.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
/* Support for Thawte strong extranet extension */
#define SXNET_TEST
static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out,
int indent);
#ifdef SXNET_TEST
static SXNET *sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
#endif
const X509V3_EXT_METHOD v3_sxnet = {
NID_sxnet, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(SXNET),
0, 0, 0, 0,
0, 0,
0,
#ifdef SXNET_TEST
(X509V3_EXT_V2I)sxnet_v2i,
#else
0,
#endif
(X509V3_EXT_I2R)sxnet_i2r,
0,
NULL
};
ASN1_SEQUENCE(SXNETID) = {
ASN1_SIMPLE(SXNETID, zone, ASN1_INTEGER),
ASN1_SIMPLE(SXNETID, user, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(SXNETID)
IMPLEMENT_ASN1_FUNCTIONS(SXNETID)
ASN1_SEQUENCE(SXNET) = {
ASN1_SIMPLE(SXNET, version, ASN1_INTEGER),
ASN1_SEQUENCE_OF(SXNET, ids, SXNETID)
} ASN1_SEQUENCE_END(SXNET)
IMPLEMENT_ASN1_FUNCTIONS(SXNET)
static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out,
int indent)
{
long v;
char *tmp;
SXNETID *id;
int i;
v = ASN1_INTEGER_get(sx->version);
BIO_printf(out, "%*sVersion: %ld (0x%lX)", indent, "", v + 1, v);
for (i = 0; i < sk_SXNETID_num(sx->ids); i++) {
id = sk_SXNETID_value(sx->ids, i);
tmp = i2s_ASN1_INTEGER(NULL, id->zone);
BIO_printf(out, "\n%*sZone: %s, User: ", indent, "", tmp);
OPENSSL_free(tmp);
ASN1_STRING_print(out, id->user);
}
return 1;
}
#ifdef SXNET_TEST
/*
* NBB: this is used for testing only. It should *not* be used for anything
* else because it will just take static IDs from the configuration file and
* they should really be separate values for each user.
*/
static SXNET *sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval)
{
CONF_VALUE *cnf;
SXNET *sx = NULL;
int i;
for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
cnf = sk_CONF_VALUE_value(nval, i);
if (!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1))
return NULL;
}
return sx;
}
#endif
/* Strong Extranet utility functions */
/* Add an id given the zone as an ASCII number */
int SXNET_add_id_asc(SXNET **psx, const char *zone, const char *user, int userlen)
{
ASN1_INTEGER *izone;
if ((izone = s2i_ASN1_INTEGER(NULL, zone)) == NULL) {
X509V3err(X509V3_F_SXNET_ADD_ID_ASC, X509V3_R_ERROR_CONVERTING_ZONE);
return 0;
}
return SXNET_add_id_INTEGER(psx, izone, user, userlen);
}
/* Add an id given the zone as an unsigned long */
int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, const char *user,
int userlen)
{
ASN1_INTEGER *izone;
if ((izone = ASN1_INTEGER_new()) == NULL
|| !ASN1_INTEGER_set(izone, lzone)) {
X509V3err(X509V3_F_SXNET_ADD_ID_ULONG, ERR_R_MALLOC_FAILURE);
ASN1_INTEGER_free(izone);
return 0;
}
return SXNET_add_id_INTEGER(psx, izone, user, userlen);
}
/*
* Add an id given the zone as an ASN1_INTEGER. Note this version uses the
* passed integer and doesn't make a copy so don't free it up afterwards.
*/
int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *zone, const char *user,
int userlen)
{
SXNET *sx = NULL;
SXNETID *id = NULL;
if (!psx || !zone || !user) {
X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER,
X509V3_R_INVALID_NULL_ARGUMENT);
return 0;
}
if (userlen == -1)
userlen = strlen(user);
if (userlen > 64) {
X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER, X509V3_R_USER_TOO_LONG);
return 0;
}
if (*psx == NULL) {
if ((sx = SXNET_new()) == NULL)
goto err;
if (!ASN1_INTEGER_set(sx->version, 0))
goto err;
*psx = sx;
} else
sx = *psx;
if (SXNET_get_id_INTEGER(sx, zone)) {
X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER, X509V3_R_DUPLICATE_ZONE_ID);
return 0;
}
if ((id = SXNETID_new()) == NULL)
goto err;
if (userlen == -1)
userlen = strlen(user);
if (!ASN1_OCTET_STRING_set(id->user, (const unsigned char *)user, userlen))
goto err;
if (!sk_SXNETID_push(sx->ids, id))
goto err;
id->zone = zone;
return 1;
err:
X509V3err(X509V3_F_SXNET_ADD_ID_INTEGER, ERR_R_MALLOC_FAILURE);
SXNETID_free(id);
SXNET_free(sx);
*psx = NULL;
return 0;
}
ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, const char *zone)
{
ASN1_INTEGER *izone;
ASN1_OCTET_STRING *oct;
if ((izone = s2i_ASN1_INTEGER(NULL, zone)) == NULL) {
X509V3err(X509V3_F_SXNET_GET_ID_ASC, X509V3_R_ERROR_CONVERTING_ZONE);
return NULL;
}
oct = SXNET_get_id_INTEGER(sx, izone);
ASN1_INTEGER_free(izone);
return oct;
}
ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone)
{
ASN1_INTEGER *izone;
ASN1_OCTET_STRING *oct;
if ((izone = ASN1_INTEGER_new()) == NULL
|| !ASN1_INTEGER_set(izone, lzone)) {
X509V3err(X509V3_F_SXNET_GET_ID_ULONG, ERR_R_MALLOC_FAILURE);
ASN1_INTEGER_free(izone);
return NULL;
}
oct = SXNET_get_id_INTEGER(sx, izone);
ASN1_INTEGER_free(izone);
return oct;
}
ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone)
{
SXNETID *id;
int i;
for (i = 0; i < sk_SXNETID_num(sx->ids); i++) {
id = sk_SXNETID_value(sx->ids, i);
if (!ASN1_INTEGER_cmp(id->zone, zone))
return id->user;
}
return NULL;
}

View file

@ -0,0 +1,137 @@
/*
* Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "e_os.h"
#include "internal/cryptlib.h"
#include <stdio.h>
#include "internal/o_str.h"
#include <openssl/asn1t.h>
#include <openssl/conf.h>
#include <openssl/x509v3.h>
#include "ext_dat.h"
static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method,
TLS_FEATURE *tls_feature,
STACK_OF(CONF_VALUE) *ext_list);
static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx,
STACK_OF(CONF_VALUE) *nval);
ASN1_ITEM_TEMPLATE(TLS_FEATURE) =
ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, TLS_FEATURE, ASN1_INTEGER)
static_ASN1_ITEM_TEMPLATE_END(TLS_FEATURE)
IMPLEMENT_ASN1_ALLOC_FUNCTIONS(TLS_FEATURE)
const X509V3_EXT_METHOD v3_tls_feature = {
NID_tlsfeature, 0,
ASN1_ITEM_ref(TLS_FEATURE),
0, 0, 0, 0,
0, 0,
(X509V3_EXT_I2V)i2v_TLS_FEATURE,
(X509V3_EXT_V2I)v2i_TLS_FEATURE,
0, 0,
NULL
};
typedef struct {
long num;
const char *name;
} TLS_FEATURE_NAME;
static TLS_FEATURE_NAME tls_feature_tbl[] = {
{ 5, "status_request" },
{ 17, "status_request_v2" }
};
/*
* i2v_TLS_FEATURE converts the TLS_FEATURE structure tls_feature into the
* STACK_OF(CONF_VALUE) structure ext_list. STACK_OF(CONF_VALUE) is the format
* used by the CONF library to represent a multi-valued extension. ext_list is
* returned.
*/
static STACK_OF(CONF_VALUE) *i2v_TLS_FEATURE(const X509V3_EXT_METHOD *method,
TLS_FEATURE *tls_feature,
STACK_OF(CONF_VALUE) *ext_list)
{
int i;
size_t j;
ASN1_INTEGER *ai;
long tlsextid;
for (i = 0; i < sk_ASN1_INTEGER_num(tls_feature); i++) {
ai = sk_ASN1_INTEGER_value(tls_feature, i);
tlsextid = ASN1_INTEGER_get(ai);
for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++)
if (tlsextid == tls_feature_tbl[j].num)
break;
if (j < OSSL_NELEM(tls_feature_tbl))
X509V3_add_value(NULL, tls_feature_tbl[j].name, &ext_list);
else
X509V3_add_value_int(NULL, ai, &ext_list);
}
return ext_list;
}
/*
* v2i_TLS_FEATURE converts the multi-valued extension nval into a TLS_FEATURE
* structure, which is returned if the conversion is successful. In case of
* error, NULL is returned.
*/
static TLS_FEATURE *v2i_TLS_FEATURE(const X509V3_EXT_METHOD *method,
X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval)
{
TLS_FEATURE *tlsf;
char *extval, *endptr;
ASN1_INTEGER *ai;
CONF_VALUE *val;
int i;
size_t j;
long tlsextid;
if ((tlsf = sk_ASN1_INTEGER_new_null()) == NULL) {
X509V3err(X509V3_F_V2I_TLS_FEATURE, ERR_R_MALLOC_FAILURE);
return NULL;
}
for (i = 0; i < sk_CONF_VALUE_num(nval); i++) {
val = sk_CONF_VALUE_value(nval, i);
if (val->value)
extval = val->value;
else
extval = val->name;
for (j = 0; j < OSSL_NELEM(tls_feature_tbl); j++)
if (strcasecmp(extval, tls_feature_tbl[j].name) == 0)
break;
if (j < OSSL_NELEM(tls_feature_tbl))
tlsextid = tls_feature_tbl[j].num;
else {
tlsextid = strtol(extval, &endptr, 10);
if (((*endptr) != '\0') || (extval == endptr) || (tlsextid < 0) ||
(tlsextid > 65535)) {
X509V3err(X509V3_F_V2I_TLS_FEATURE, X509V3_R_INVALID_SYNTAX);
X509V3_conf_err(val);
goto err;
}
}
if ((ai = ASN1_INTEGER_new()) == NULL
|| !ASN1_INTEGER_set(ai, tlsextid)
|| sk_ASN1_INTEGER_push(tlsf, ai) <= 0) {
X509V3err(X509V3_F_V2I_TLS_FEATURE, ERR_R_MALLOC_FAILURE);
goto err;
}
}
return tlsf;
err:
sk_ASN1_INTEGER_pop_free(tlsf, ASN1_INTEGER_free);
return NULL;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,257 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/err.h>
#include <openssl/x509v3err.h>
#ifndef OPENSSL_NO_ERR
static const ERR_STRING_DATA X509V3_str_functs[] = {
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_A2I_GENERAL_NAME, 0),
"a2i_GENERAL_NAME"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_ADDR_VALIDATE_PATH_INTERNAL, 0),
"addr_validate_path_internal"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_ASIDENTIFIERCHOICE_CANONIZE, 0),
"ASIdentifierChoice_canonize"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_ASIDENTIFIERCHOICE_IS_CANONICAL, 0),
"ASIdentifierChoice_is_canonical"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_BIGNUM_TO_STRING, 0),
"bignum_to_string"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_COPY_EMAIL, 0), "copy_email"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_COPY_ISSUER, 0), "copy_issuer"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_DO_DIRNAME, 0), "do_dirname"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_DO_EXT_I2D, 0), "do_ext_i2d"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_DO_EXT_NCONF, 0), "do_ext_nconf"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_GNAMES_FROM_SECTNAME, 0),
"gnames_from_sectname"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_I2S_ASN1_ENUMERATED, 0),
"i2s_ASN1_ENUMERATED"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_I2S_ASN1_IA5STRING, 0),
"i2s_ASN1_IA5STRING"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_I2S_ASN1_INTEGER, 0),
"i2s_ASN1_INTEGER"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_I2V_AUTHORITY_INFO_ACCESS, 0),
"i2v_AUTHORITY_INFO_ACCESS"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_LEVEL_ADD_NODE, 0), "level_add_node"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_NOTICE_SECTION, 0), "notice_section"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_NREF_NOS, 0), "nref_nos"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_POLICY_CACHE_CREATE, 0),
"policy_cache_create"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_POLICY_CACHE_NEW, 0),
"policy_cache_new"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_POLICY_DATA_NEW, 0), "policy_data_new"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_POLICY_SECTION, 0), "policy_section"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_PROCESS_PCI_VALUE, 0),
"process_pci_value"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_R2I_CERTPOL, 0), "r2i_certpol"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_R2I_PCI, 0), "r2i_pci"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_S2I_ASN1_IA5STRING, 0),
"s2i_ASN1_IA5STRING"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_S2I_ASN1_INTEGER, 0),
"s2i_ASN1_INTEGER"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_S2I_ASN1_OCTET_STRING, 0),
"s2i_ASN1_OCTET_STRING"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_S2I_SKEY_ID, 0), "s2i_skey_id"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_SET_DIST_POINT_NAME, 0),
"set_dist_point_name"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_ADD_ID_ASC, 0),
"SXNET_add_id_asc"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_ADD_ID_INTEGER, 0),
"SXNET_add_id_INTEGER"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_ADD_ID_ULONG, 0),
"SXNET_add_id_ulong"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_GET_ID_ASC, 0),
"SXNET_get_id_asc"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_SXNET_GET_ID_ULONG, 0),
"SXNET_get_id_ulong"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_TREE_INIT, 0), "tree_init"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_ASIDENTIFIERS, 0),
"v2i_ASIdentifiers"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_ASN1_BIT_STRING, 0),
"v2i_ASN1_BIT_STRING"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_AUTHORITY_INFO_ACCESS, 0),
"v2i_AUTHORITY_INFO_ACCESS"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_AUTHORITY_KEYID, 0),
"v2i_AUTHORITY_KEYID"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_BASIC_CONSTRAINTS, 0),
"v2i_BASIC_CONSTRAINTS"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_CRLD, 0), "v2i_crld"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_EXTENDED_KEY_USAGE, 0),
"v2i_EXTENDED_KEY_USAGE"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_GENERAL_NAMES, 0),
"v2i_GENERAL_NAMES"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_GENERAL_NAME_EX, 0),
"v2i_GENERAL_NAME_ex"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_IDP, 0), "v2i_idp"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_IPADDRBLOCKS, 0),
"v2i_IPAddrBlocks"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_ISSUER_ALT, 0), "v2i_issuer_alt"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_NAME_CONSTRAINTS, 0),
"v2i_NAME_CONSTRAINTS"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_POLICY_CONSTRAINTS, 0),
"v2i_POLICY_CONSTRAINTS"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_POLICY_MAPPINGS, 0),
"v2i_POLICY_MAPPINGS"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_SUBJECT_ALT, 0), "v2i_subject_alt"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V2I_TLS_FEATURE, 0), "v2i_TLS_FEATURE"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_V3_GENERIC_EXTENSION, 0),
"v3_generic_extension"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_ADD1_I2D, 0), "X509V3_add1_i2d"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_ADD_VALUE, 0),
"X509V3_add_value"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_ADD, 0), "X509V3_EXT_add"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_ADD_ALIAS, 0),
"X509V3_EXT_add_alias"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_I2D, 0), "X509V3_EXT_i2d"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_EXT_NCONF, 0),
"X509V3_EXT_nconf"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_GET_SECTION, 0),
"X509V3_get_section"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_GET_STRING, 0),
"X509V3_get_string"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_GET_VALUE_BOOL, 0),
"X509V3_get_value_bool"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509V3_PARSE_LIST, 0),
"X509V3_parse_list"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509_PURPOSE_ADD, 0),
"X509_PURPOSE_add"},
{ERR_PACK(ERR_LIB_X509V3, X509V3_F_X509_PURPOSE_SET, 0),
"X509_PURPOSE_set"},
{0, NULL}
};
static const ERR_STRING_DATA X509V3_str_reasons[] = {
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BAD_IP_ADDRESS), "bad ip address"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BAD_OBJECT), "bad object"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_DEC2BN_ERROR), "bn dec2bn error"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_TO_ASN1_INTEGER_ERROR),
"bn to asn1 integer error"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DIRNAME_ERROR), "dirname error"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DISTPOINT_ALREADY_SET),
"distpoint already set"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DUPLICATE_ZONE_ID),
"duplicate zone id"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CONVERTING_ZONE),
"error converting zone"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CREATING_EXTENSION),
"error creating extension"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_IN_EXTENSION),
"error in extension"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXPECTED_A_SECTION_NAME),
"expected a section name"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_EXISTS),
"extension exists"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NAME_ERROR),
"extension name error"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NOT_FOUND),
"extension not found"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED),
"extension setting not supported"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_VALUE_ERROR),
"extension value error"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ILLEGAL_EMPTY_EXTENSION),
"illegal empty extension"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG),
"incorrect policy syntax tag"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASNUMBER),
"invalid asnumber"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASRANGE), "invalid asrange"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_BOOLEAN_STRING),
"invalid boolean string"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_EXTENSION_STRING),
"invalid extension string"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_INHERITANCE),
"invalid inheritance"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_IPADDRESS),
"invalid ipaddress"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_MULTIPLE_RDNS),
"invalid multiple rdns"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NAME), "invalid name"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_ARGUMENT),
"invalid null argument"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_NAME),
"invalid null name"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_VALUE),
"invalid null value"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBER), "invalid number"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBERS), "invalid numbers"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OBJECT_IDENTIFIER),
"invalid object identifier"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OPTION), "invalid option"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_POLICY_IDENTIFIER),
"invalid policy identifier"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PROXY_POLICY_SETTING),
"invalid proxy policy setting"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PURPOSE), "invalid purpose"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SAFI), "invalid safi"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SECTION), "invalid section"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SYNTAX), "invalid syntax"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ISSUER_DECODE_ERROR),
"issuer decode error"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_MISSING_VALUE), "missing value"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS),
"need organization and numbers"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_CONFIG_DATABASE),
"no config database"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_CERTIFICATE),
"no issuer certificate"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_DETAILS),
"no issuer details"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_POLICY_IDENTIFIER),
"no policy identifier"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED),
"no proxy cert policy language defined"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PUBLIC_KEY), "no public key"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_SUBJECT_DETAILS),
"no subject details"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OPERATION_NOT_DEFINED),
"operation not defined"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OTHERNAME_ERROR), "othername error"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED),
"policy language already defined"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH),
"policy path length"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED),
"policy path length already defined"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY),
"policy when proxy language requires no policy"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_SECTION_NOT_FOUND),
"section not found"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS),
"unable to get issuer details"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID),
"unable to get issuer keyid"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT),
"unknown bit string argument"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION),
"unknown extension"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION_NAME),
"unknown extension name"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_OPTION), "unknown option"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_OPTION),
"unsupported option"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_TYPE),
"unsupported type"},
{ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_USER_TOO_LONG), "user too long"},
{0, NULL}
};
#endif
int ERR_load_X509V3_strings(void)
{
#ifndef OPENSSL_NO_ERR
if (ERR_func_error_string(X509V3_str_functs[0].error) == NULL) {
ERR_load_strings_const(X509V3_str_functs);
ERR_load_strings_const(X509V3_str_reasons);
}
#endif
return 1;
}