1160814Ssimon/* pcy_cache.c */ 2296341Sdelphij/* 3296341Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4296341Sdelphij * 2004. 5160814Ssimon */ 6160814Ssimon/* ==================================================================== 7160814Ssimon * Copyright (c) 2004 The OpenSSL Project. All rights reserved. 8160814Ssimon * 9160814Ssimon * Redistribution and use in source and binary forms, with or without 10160814Ssimon * modification, are permitted provided that the following conditions 11160814Ssimon * are met: 12160814Ssimon * 13160814Ssimon * 1. Redistributions of source code must retain the above copyright 14296341Sdelphij * notice, this list of conditions and the following disclaimer. 15160814Ssimon * 16160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright 17160814Ssimon * notice, this list of conditions and the following disclaimer in 18160814Ssimon * the documentation and/or other materials provided with the 19160814Ssimon * distribution. 20160814Ssimon * 21160814Ssimon * 3. All advertising materials mentioning features or use of this 22160814Ssimon * software must display the following acknowledgment: 23160814Ssimon * "This product includes software developed by the OpenSSL Project 24160814Ssimon * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25160814Ssimon * 26160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27160814Ssimon * endorse or promote products derived from this software without 28160814Ssimon * prior written permission. For written permission, please contact 29160814Ssimon * licensing@OpenSSL.org. 30160814Ssimon * 31160814Ssimon * 5. Products derived from this software may not be called "OpenSSL" 32160814Ssimon * nor may "OpenSSL" appear in their names without prior written 33160814Ssimon * permission of the OpenSSL Project. 34160814Ssimon * 35160814Ssimon * 6. Redistributions of any form whatsoever must retain the following 36160814Ssimon * acknowledgment: 37160814Ssimon * "This product includes software developed by the OpenSSL Project 38160814Ssimon * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39160814Ssimon * 40160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43160814Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 52160814Ssimon * ==================================================================== 53160814Ssimon * 54160814Ssimon * This product includes cryptographic software written by Eric Young 55160814Ssimon * (eay@cryptsoft.com). This product includes software written by Tim 56160814Ssimon * Hudson (tjh@cryptsoft.com). 57160814Ssimon * 58160814Ssimon */ 59160814Ssimon 60160814Ssimon#include "cryptlib.h" 61160814Ssimon#include <openssl/x509.h> 62160814Ssimon#include <openssl/x509v3.h> 63160814Ssimon 64160814Ssimon#include "pcy_int.h" 65160814Ssimon 66296341Sdelphijstatic int policy_data_cmp(const X509_POLICY_DATA *const *a, 67296341Sdelphij const X509_POLICY_DATA *const *b); 68160814Ssimonstatic int policy_cache_set_int(long *out, ASN1_INTEGER *value); 69160814Ssimon 70296341Sdelphij/* 71296341Sdelphij * Set cache entry according to CertificatePolicies extension. Note: this 72296341Sdelphij * destroys the passed CERTIFICATEPOLICIES structure. 73160814Ssimon */ 74160814Ssimon 75160814Ssimonstatic int policy_cache_create(X509 *x, 76296341Sdelphij CERTIFICATEPOLICIES *policies, int crit) 77296341Sdelphij{ 78296341Sdelphij int i; 79296341Sdelphij int ret = 0; 80296341Sdelphij X509_POLICY_CACHE *cache = x->policy_cache; 81296341Sdelphij X509_POLICY_DATA *data = NULL; 82296341Sdelphij POLICYINFO *policy; 83296341Sdelphij if (sk_POLICYINFO_num(policies) == 0) 84296341Sdelphij goto bad_policy; 85296341Sdelphij cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp); 86296341Sdelphij if (!cache->data) 87296341Sdelphij goto bad_policy; 88296341Sdelphij for (i = 0; i < sk_POLICYINFO_num(policies); i++) { 89296341Sdelphij policy = sk_POLICYINFO_value(policies, i); 90296341Sdelphij data = policy_data_new(policy, NULL, crit); 91296341Sdelphij if (!data) 92296341Sdelphij goto bad_policy; 93296341Sdelphij /* 94296341Sdelphij * Duplicate policy OIDs are illegal: reject if matches found. 95296341Sdelphij */ 96296341Sdelphij if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) { 97296341Sdelphij if (cache->anyPolicy) { 98296341Sdelphij ret = -1; 99296341Sdelphij goto bad_policy; 100296341Sdelphij } 101296341Sdelphij cache->anyPolicy = data; 102296341Sdelphij } else if (sk_X509_POLICY_DATA_find(cache->data, data) != -1) { 103296341Sdelphij ret = -1; 104296341Sdelphij goto bad_policy; 105296341Sdelphij } else if (!sk_X509_POLICY_DATA_push(cache->data, data)) 106296341Sdelphij goto bad_policy; 107296341Sdelphij data = NULL; 108296341Sdelphij } 109296341Sdelphij ret = 1; 110296341Sdelphij bad_policy: 111296341Sdelphij if (ret == -1) 112296341Sdelphij x->ex_flags |= EXFLAG_INVALID_POLICY; 113296341Sdelphij if (data) 114296341Sdelphij policy_data_free(data); 115296341Sdelphij sk_POLICYINFO_pop_free(policies, POLICYINFO_free); 116296341Sdelphij if (ret <= 0) { 117296341Sdelphij sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); 118296341Sdelphij cache->data = NULL; 119296341Sdelphij } 120296341Sdelphij return ret; 121296341Sdelphij} 122160814Ssimon 123160814Ssimonstatic int policy_cache_new(X509 *x) 124296341Sdelphij{ 125296341Sdelphij X509_POLICY_CACHE *cache; 126296341Sdelphij ASN1_INTEGER *ext_any = NULL; 127296341Sdelphij POLICY_CONSTRAINTS *ext_pcons = NULL; 128296341Sdelphij CERTIFICATEPOLICIES *ext_cpols = NULL; 129296341Sdelphij POLICY_MAPPINGS *ext_pmaps = NULL; 130296341Sdelphij int i; 131296341Sdelphij cache = OPENSSL_malloc(sizeof(X509_POLICY_CACHE)); 132296341Sdelphij if (!cache) 133296341Sdelphij return 0; 134296341Sdelphij cache->anyPolicy = NULL; 135296341Sdelphij cache->data = NULL; 136296341Sdelphij cache->any_skip = -1; 137296341Sdelphij cache->explicit_skip = -1; 138296341Sdelphij cache->map_skip = -1; 139160814Ssimon 140296341Sdelphij x->policy_cache = cache; 141160814Ssimon 142296341Sdelphij /* 143296341Sdelphij * Handle requireExplicitPolicy *first*. Need to process this even if we 144296341Sdelphij * don't have any policies. 145296341Sdelphij */ 146296341Sdelphij ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL); 147160814Ssimon 148296341Sdelphij if (!ext_pcons) { 149296341Sdelphij if (i != -1) 150296341Sdelphij goto bad_cache; 151296341Sdelphij } else { 152296341Sdelphij if (!ext_pcons->requireExplicitPolicy 153296341Sdelphij && !ext_pcons->inhibitPolicyMapping) 154296341Sdelphij goto bad_cache; 155296341Sdelphij if (!policy_cache_set_int(&cache->explicit_skip, 156296341Sdelphij ext_pcons->requireExplicitPolicy)) 157296341Sdelphij goto bad_cache; 158296341Sdelphij if (!policy_cache_set_int(&cache->map_skip, 159296341Sdelphij ext_pcons->inhibitPolicyMapping)) 160296341Sdelphij goto bad_cache; 161296341Sdelphij } 162160814Ssimon 163296341Sdelphij /* Process CertificatePolicies */ 164160814Ssimon 165296341Sdelphij ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL); 166296341Sdelphij /* 167296341Sdelphij * If no CertificatePolicies extension or problem decoding then there is 168296341Sdelphij * no point continuing because the valid policies will be NULL. 169296341Sdelphij */ 170296341Sdelphij if (!ext_cpols) { 171296341Sdelphij /* If not absent some problem with extension */ 172296341Sdelphij if (i != -1) 173296341Sdelphij goto bad_cache; 174296341Sdelphij return 1; 175296341Sdelphij } 176160814Ssimon 177296341Sdelphij i = policy_cache_create(x, ext_cpols, i); 178160814Ssimon 179296341Sdelphij /* NB: ext_cpols freed by policy_cache_set_policies */ 180160814Ssimon 181296341Sdelphij if (i <= 0) 182296341Sdelphij return i; 183160814Ssimon 184296341Sdelphij ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL); 185160814Ssimon 186296341Sdelphij if (!ext_pmaps) { 187296341Sdelphij /* If not absent some problem with extension */ 188296341Sdelphij if (i != -1) 189296341Sdelphij goto bad_cache; 190296341Sdelphij } else { 191296341Sdelphij i = policy_cache_set_mapping(x, ext_pmaps); 192296341Sdelphij if (i <= 0) 193296341Sdelphij goto bad_cache; 194296341Sdelphij } 195160814Ssimon 196296341Sdelphij ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL); 197160814Ssimon 198296341Sdelphij if (!ext_any) { 199296341Sdelphij if (i != -1) 200296341Sdelphij goto bad_cache; 201296341Sdelphij } else if (!policy_cache_set_int(&cache->any_skip, ext_any)) 202296341Sdelphij goto bad_cache; 203160814Ssimon 204296341Sdelphij if (0) { 205296341Sdelphij bad_cache: 206296341Sdelphij x->ex_flags |= EXFLAG_INVALID_POLICY; 207296341Sdelphij } 208160814Ssimon 209296341Sdelphij if (ext_pcons) 210296341Sdelphij POLICY_CONSTRAINTS_free(ext_pcons); 211160814Ssimon 212296341Sdelphij if (ext_any) 213296341Sdelphij ASN1_INTEGER_free(ext_any); 214160814Ssimon 215296341Sdelphij return 1; 216160814Ssimon 217160814Ssimon} 218160814Ssimon 219160814Ssimonvoid policy_cache_free(X509_POLICY_CACHE *cache) 220296341Sdelphij{ 221296341Sdelphij if (!cache) 222296341Sdelphij return; 223296341Sdelphij if (cache->anyPolicy) 224296341Sdelphij policy_data_free(cache->anyPolicy); 225296341Sdelphij if (cache->data) 226296341Sdelphij sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); 227296341Sdelphij OPENSSL_free(cache); 228296341Sdelphij} 229160814Ssimon 230160814Ssimonconst X509_POLICY_CACHE *policy_cache_set(X509 *x) 231296341Sdelphij{ 232160814Ssimon 233296341Sdelphij if (x->policy_cache == NULL) { 234296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_X509); 235296341Sdelphij policy_cache_new(x); 236296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_X509); 237296341Sdelphij } 238160814Ssimon 239296341Sdelphij return x->policy_cache; 240160814Ssimon 241296341Sdelphij} 242160814Ssimon 243160814SsimonX509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, 244296341Sdelphij const ASN1_OBJECT *id) 245296341Sdelphij{ 246296341Sdelphij int idx; 247296341Sdelphij X509_POLICY_DATA tmp; 248296341Sdelphij tmp.valid_policy = (ASN1_OBJECT *)id; 249296341Sdelphij idx = sk_X509_POLICY_DATA_find(cache->data, &tmp); 250296341Sdelphij if (idx == -1) 251296341Sdelphij return NULL; 252296341Sdelphij return sk_X509_POLICY_DATA_value(cache->data, idx); 253296341Sdelphij} 254160814Ssimon 255296341Sdelphijstatic int policy_data_cmp(const X509_POLICY_DATA *const *a, 256296341Sdelphij const X509_POLICY_DATA *const *b) 257296341Sdelphij{ 258296341Sdelphij return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy); 259296341Sdelphij} 260160814Ssimon 261160814Ssimonstatic int policy_cache_set_int(long *out, ASN1_INTEGER *value) 262296341Sdelphij{ 263296341Sdelphij if (value == NULL) 264296341Sdelphij return 1; 265296341Sdelphij if (value->type == V_ASN1_NEG_INTEGER) 266296341Sdelphij return 0; 267296341Sdelphij *out = ASN1_INTEGER_get(value); 268296341Sdelphij return 1; 269296341Sdelphij} 270