1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: pcy_cache.c,v 1.2 2021/11/01 20:53:08 tb Exp $ */
28edacedfSDaniel Fojt /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
38edacedfSDaniel Fojt  * project 2004.
48edacedfSDaniel Fojt  */
58edacedfSDaniel Fojt /* ====================================================================
68edacedfSDaniel Fojt  * Copyright (c) 2004 The OpenSSL Project.  All rights reserved.
78edacedfSDaniel Fojt  *
88edacedfSDaniel Fojt  * Redistribution and use in source and binary forms, with or without
98edacedfSDaniel Fojt  * modification, are permitted provided that the following conditions
108edacedfSDaniel Fojt  * are met:
118edacedfSDaniel Fojt  *
128edacedfSDaniel Fojt  * 1. Redistributions of source code must retain the above copyright
138edacedfSDaniel Fojt  *    notice, this list of conditions and the following disclaimer.
148edacedfSDaniel Fojt  *
158edacedfSDaniel Fojt  * 2. Redistributions in binary form must reproduce the above copyright
168edacedfSDaniel Fojt  *    notice, this list of conditions and the following disclaimer in
178edacedfSDaniel Fojt  *    the documentation and/or other materials provided with the
188edacedfSDaniel Fojt  *    distribution.
198edacedfSDaniel Fojt  *
208edacedfSDaniel Fojt  * 3. All advertising materials mentioning features or use of this
218edacedfSDaniel Fojt  *    software must display the following acknowledgment:
228edacedfSDaniel Fojt  *    "This product includes software developed by the OpenSSL Project
238edacedfSDaniel Fojt  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
248edacedfSDaniel Fojt  *
258edacedfSDaniel Fojt  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
268edacedfSDaniel Fojt  *    endorse or promote products derived from this software without
278edacedfSDaniel Fojt  *    prior written permission. For written permission, please contact
288edacedfSDaniel Fojt  *    licensing@OpenSSL.org.
298edacedfSDaniel Fojt  *
308edacedfSDaniel Fojt  * 5. Products derived from this software may not be called "OpenSSL"
318edacedfSDaniel Fojt  *    nor may "OpenSSL" appear in their names without prior written
328edacedfSDaniel Fojt  *    permission of the OpenSSL Project.
338edacedfSDaniel Fojt  *
348edacedfSDaniel Fojt  * 6. Redistributions of any form whatsoever must retain the following
358edacedfSDaniel Fojt  *    acknowledgment:
368edacedfSDaniel Fojt  *    "This product includes software developed by the OpenSSL Project
378edacedfSDaniel Fojt  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
388edacedfSDaniel Fojt  *
398edacedfSDaniel Fojt  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
408edacedfSDaniel Fojt  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
418edacedfSDaniel Fojt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
428edacedfSDaniel Fojt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
438edacedfSDaniel Fojt  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
448edacedfSDaniel Fojt  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
458edacedfSDaniel Fojt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
468edacedfSDaniel Fojt  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
478edacedfSDaniel Fojt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
488edacedfSDaniel Fojt  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
498edacedfSDaniel Fojt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
508edacedfSDaniel Fojt  * OF THE POSSIBILITY OF SUCH DAMAGE.
518edacedfSDaniel Fojt  * ====================================================================
528edacedfSDaniel Fojt  *
538edacedfSDaniel Fojt  * This product includes cryptographic software written by Eric Young
548edacedfSDaniel Fojt  * (eay@cryptsoft.com).  This product includes software written by Tim
558edacedfSDaniel Fojt  * Hudson (tjh@cryptsoft.com).
568edacedfSDaniel Fojt  *
578edacedfSDaniel Fojt  */
588edacedfSDaniel Fojt 
598edacedfSDaniel Fojt #include <openssl/x509.h>
608edacedfSDaniel Fojt #include <openssl/x509v3.h>
618edacedfSDaniel Fojt 
628edacedfSDaniel Fojt #include "pcy_int.h"
63*de0e0e4dSAntonio Huete Jimenez #include "x509_lcl.h"
648edacedfSDaniel Fojt 
658edacedfSDaniel Fojt static int policy_data_cmp(const X509_POLICY_DATA * const *a,
668edacedfSDaniel Fojt     const X509_POLICY_DATA * const *b);
678edacedfSDaniel Fojt static int policy_cache_set_int(long *out, ASN1_INTEGER *value);
688edacedfSDaniel Fojt 
698edacedfSDaniel Fojt /* Set cache entry according to CertificatePolicies extension.
708edacedfSDaniel Fojt  * Note: this destroys the passed CERTIFICATEPOLICIES structure.
718edacedfSDaniel Fojt  */
728edacedfSDaniel Fojt 
738edacedfSDaniel Fojt static int
policy_cache_create(X509 * x,CERTIFICATEPOLICIES * policies,int crit)748edacedfSDaniel Fojt policy_cache_create(X509 *x, CERTIFICATEPOLICIES *policies, int crit)
758edacedfSDaniel Fojt {
768edacedfSDaniel Fojt 	int i;
778edacedfSDaniel Fojt 	int ret = 0;
788edacedfSDaniel Fojt 	X509_POLICY_CACHE *cache = x->policy_cache;
798edacedfSDaniel Fojt 	X509_POLICY_DATA *data = NULL;
808edacedfSDaniel Fojt 	POLICYINFO *policy;
818edacedfSDaniel Fojt 
828edacedfSDaniel Fojt 	if (sk_POLICYINFO_num(policies) == 0)
838edacedfSDaniel Fojt 		goto bad_policy;
848edacedfSDaniel Fojt 	cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp);
858edacedfSDaniel Fojt 	if (!cache->data)
868edacedfSDaniel Fojt 		goto bad_policy;
878edacedfSDaniel Fojt 	for (i = 0; i < sk_POLICYINFO_num(policies); i++) {
888edacedfSDaniel Fojt 		policy = sk_POLICYINFO_value(policies, i);
898edacedfSDaniel Fojt 		data = policy_data_new(policy, NULL, crit);
908edacedfSDaniel Fojt 		if (!data)
918edacedfSDaniel Fojt 			goto bad_policy;
928edacedfSDaniel Fojt 		/* Duplicate policy OIDs are illegal: reject if matches
938edacedfSDaniel Fojt 		 * found.
948edacedfSDaniel Fojt 		 */
958edacedfSDaniel Fojt 		if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
968edacedfSDaniel Fojt 			if (cache->anyPolicy) {
978edacedfSDaniel Fojt 				ret = -1;
988edacedfSDaniel Fojt 				goto bad_policy;
998edacedfSDaniel Fojt 			}
1008edacedfSDaniel Fojt 			cache->anyPolicy = data;
1018edacedfSDaniel Fojt 		} else if (sk_X509_POLICY_DATA_find(cache->data, data) != -1) {
1028edacedfSDaniel Fojt 			ret = -1;
1038edacedfSDaniel Fojt 			goto bad_policy;
1048edacedfSDaniel Fojt 		} else if (!sk_X509_POLICY_DATA_push(cache->data, data))
1058edacedfSDaniel Fojt 			goto bad_policy;
1068edacedfSDaniel Fojt 		data = NULL;
1078edacedfSDaniel Fojt 	}
1088edacedfSDaniel Fojt 	ret = 1;
1098edacedfSDaniel Fojt 
1108edacedfSDaniel Fojt bad_policy:
1118edacedfSDaniel Fojt 	if (ret == -1)
1128edacedfSDaniel Fojt 		x->ex_flags |= EXFLAG_INVALID_POLICY;
1138edacedfSDaniel Fojt 	if (data)
1148edacedfSDaniel Fojt 		policy_data_free(data);
1158edacedfSDaniel Fojt 	sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
1168edacedfSDaniel Fojt 	if (ret <= 0) {
1178edacedfSDaniel Fojt 		sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free);
1188edacedfSDaniel Fojt 		cache->data = NULL;
1198edacedfSDaniel Fojt 	}
1208edacedfSDaniel Fojt 	return ret;
1218edacedfSDaniel Fojt }
1228edacedfSDaniel Fojt 
1238edacedfSDaniel Fojt static int
policy_cache_new(X509 * x)1248edacedfSDaniel Fojt policy_cache_new(X509 *x)
1258edacedfSDaniel Fojt {
1268edacedfSDaniel Fojt 	X509_POLICY_CACHE *cache;
1278edacedfSDaniel Fojt 	ASN1_INTEGER *ext_any = NULL;
1288edacedfSDaniel Fojt 	POLICY_CONSTRAINTS *ext_pcons = NULL;
1298edacedfSDaniel Fojt 	CERTIFICATEPOLICIES *ext_cpols = NULL;
1308edacedfSDaniel Fojt 	POLICY_MAPPINGS *ext_pmaps = NULL;
1318edacedfSDaniel Fojt 	int i;
1328edacedfSDaniel Fojt 
1338edacedfSDaniel Fojt 	cache = malloc(sizeof(X509_POLICY_CACHE));
1348edacedfSDaniel Fojt 	if (!cache)
1358edacedfSDaniel Fojt 		return 0;
1368edacedfSDaniel Fojt 	cache->anyPolicy = NULL;
1378edacedfSDaniel Fojt 	cache->data = NULL;
1388edacedfSDaniel Fojt 	cache->any_skip = -1;
1398edacedfSDaniel Fojt 	cache->explicit_skip = -1;
1408edacedfSDaniel Fojt 	cache->map_skip = -1;
1418edacedfSDaniel Fojt 
1428edacedfSDaniel Fojt 	x->policy_cache = cache;
1438edacedfSDaniel Fojt 
1448edacedfSDaniel Fojt 	/* Handle requireExplicitPolicy *first*. Need to process this
1458edacedfSDaniel Fojt 	 * even if we don't have any policies.
1468edacedfSDaniel Fojt 	 */
1478edacedfSDaniel Fojt 	ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL);
1488edacedfSDaniel Fojt 
1498edacedfSDaniel Fojt 	if (!ext_pcons) {
1508edacedfSDaniel Fojt 		if (i != -1)
1518edacedfSDaniel Fojt 			goto bad_cache;
1528edacedfSDaniel Fojt 	} else {
1538edacedfSDaniel Fojt 		if (!ext_pcons->requireExplicitPolicy &&
1548edacedfSDaniel Fojt 		    !ext_pcons->inhibitPolicyMapping)
1558edacedfSDaniel Fojt 			goto bad_cache;
1568edacedfSDaniel Fojt 		if (!policy_cache_set_int(&cache->explicit_skip,
1578edacedfSDaniel Fojt 		    ext_pcons->requireExplicitPolicy))
1588edacedfSDaniel Fojt 			goto bad_cache;
1598edacedfSDaniel Fojt 		if (!policy_cache_set_int(&cache->map_skip,
1608edacedfSDaniel Fojt 		    ext_pcons->inhibitPolicyMapping))
1618edacedfSDaniel Fojt 			goto bad_cache;
1628edacedfSDaniel Fojt 	}
1638edacedfSDaniel Fojt 
1648edacedfSDaniel Fojt 	/* Process CertificatePolicies */
1658edacedfSDaniel Fojt 
1668edacedfSDaniel Fojt 	ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL);
1678edacedfSDaniel Fojt 	/* If no CertificatePolicies extension or problem decoding then
1688edacedfSDaniel Fojt 	 * there is no point continuing because the valid policies will be
1698edacedfSDaniel Fojt 	 * NULL.
1708edacedfSDaniel Fojt 	 */
1718edacedfSDaniel Fojt 	if (!ext_cpols) {
1728edacedfSDaniel Fojt 		/* If not absent some problem with extension */
1738edacedfSDaniel Fojt 		if (i != -1)
1748edacedfSDaniel Fojt 			goto bad_cache;
1758edacedfSDaniel Fojt 		return 1;
1768edacedfSDaniel Fojt 	}
1778edacedfSDaniel Fojt 
1788edacedfSDaniel Fojt 	i = policy_cache_create(x, ext_cpols, i);
1798edacedfSDaniel Fojt 
1808edacedfSDaniel Fojt 	/* NB: ext_cpols freed by policy_cache_set_policies */
1818edacedfSDaniel Fojt 
1828edacedfSDaniel Fojt 	if (i <= 0)
1838edacedfSDaniel Fojt 		return i;
1848edacedfSDaniel Fojt 
1858edacedfSDaniel Fojt 	ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL);
1868edacedfSDaniel Fojt 
1878edacedfSDaniel Fojt 	if (!ext_pmaps) {
1888edacedfSDaniel Fojt 		/* If not absent some problem with extension */
1898edacedfSDaniel Fojt 		if (i != -1)
1908edacedfSDaniel Fojt 			goto bad_cache;
1918edacedfSDaniel Fojt 	} else {
1928edacedfSDaniel Fojt 		i = policy_cache_set_mapping(x, ext_pmaps);
1938edacedfSDaniel Fojt 		if (i <= 0)
1948edacedfSDaniel Fojt 			goto bad_cache;
1958edacedfSDaniel Fojt 	}
1968edacedfSDaniel Fojt 
1978edacedfSDaniel Fojt 	ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL);
1988edacedfSDaniel Fojt 
1998edacedfSDaniel Fojt 	if (!ext_any) {
2008edacedfSDaniel Fojt 		if (i != -1)
2018edacedfSDaniel Fojt 			goto bad_cache;
2028edacedfSDaniel Fojt 	} else if (!policy_cache_set_int(&cache->any_skip, ext_any))
2038edacedfSDaniel Fojt 		goto bad_cache;
2048edacedfSDaniel Fojt 
2058edacedfSDaniel Fojt 	if (0) {
2068edacedfSDaniel Fojt bad_cache:
2078edacedfSDaniel Fojt 		x->ex_flags |= EXFLAG_INVALID_POLICY;
2088edacedfSDaniel Fojt 	}
2098edacedfSDaniel Fojt 
2108edacedfSDaniel Fojt 	if (ext_pcons)
2118edacedfSDaniel Fojt 		POLICY_CONSTRAINTS_free(ext_pcons);
2128edacedfSDaniel Fojt 
2138edacedfSDaniel Fojt 	if (ext_any)
2148edacedfSDaniel Fojt 		ASN1_INTEGER_free(ext_any);
2158edacedfSDaniel Fojt 
2168edacedfSDaniel Fojt 	return 1;
2178edacedfSDaniel Fojt }
2188edacedfSDaniel Fojt 
2198edacedfSDaniel Fojt void
policy_cache_free(X509_POLICY_CACHE * cache)2208edacedfSDaniel Fojt policy_cache_free(X509_POLICY_CACHE *cache)
2218edacedfSDaniel Fojt {
2228edacedfSDaniel Fojt 	if (!cache)
2238edacedfSDaniel Fojt 		return;
2248edacedfSDaniel Fojt 	if (cache->anyPolicy)
2258edacedfSDaniel Fojt 		policy_data_free(cache->anyPolicy);
2268edacedfSDaniel Fojt 	if (cache->data)
2278edacedfSDaniel Fojt 		sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free);
2288edacedfSDaniel Fojt 	free(cache);
2298edacedfSDaniel Fojt }
2308edacedfSDaniel Fojt 
2318edacedfSDaniel Fojt const X509_POLICY_CACHE *
policy_cache_set(X509 * x)2328edacedfSDaniel Fojt policy_cache_set(X509 *x)
2338edacedfSDaniel Fojt {
2348edacedfSDaniel Fojt 	if (x->policy_cache == NULL) {
2358edacedfSDaniel Fojt 		CRYPTO_w_lock(CRYPTO_LOCK_X509);
2368edacedfSDaniel Fojt 		policy_cache_new(x);
2378edacedfSDaniel Fojt 		CRYPTO_w_unlock(CRYPTO_LOCK_X509);
2388edacedfSDaniel Fojt 	}
2398edacedfSDaniel Fojt 
2408edacedfSDaniel Fojt 	return x->policy_cache;
2418edacedfSDaniel Fojt }
2428edacedfSDaniel Fojt 
2438edacedfSDaniel Fojt X509_POLICY_DATA *
policy_cache_find_data(const X509_POLICY_CACHE * cache,const ASN1_OBJECT * id)2448edacedfSDaniel Fojt policy_cache_find_data(const X509_POLICY_CACHE *cache, const ASN1_OBJECT *id)
2458edacedfSDaniel Fojt {
2468edacedfSDaniel Fojt 	int idx;
2478edacedfSDaniel Fojt 	X509_POLICY_DATA tmp;
2488edacedfSDaniel Fojt 
2498edacedfSDaniel Fojt 	tmp.valid_policy = (ASN1_OBJECT *)id;
2508edacedfSDaniel Fojt 	idx = sk_X509_POLICY_DATA_find(cache->data, &tmp);
2518edacedfSDaniel Fojt 	if (idx == -1)
2528edacedfSDaniel Fojt 		return NULL;
2538edacedfSDaniel Fojt 	return sk_X509_POLICY_DATA_value(cache->data, idx);
2548edacedfSDaniel Fojt }
2558edacedfSDaniel Fojt 
2568edacedfSDaniel Fojt static int
policy_data_cmp(const X509_POLICY_DATA * const * a,const X509_POLICY_DATA * const * b)2578edacedfSDaniel Fojt policy_data_cmp(const X509_POLICY_DATA * const *a,
2588edacedfSDaniel Fojt     const X509_POLICY_DATA * const *b)
2598edacedfSDaniel Fojt {
2608edacedfSDaniel Fojt 	return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy);
2618edacedfSDaniel Fojt }
2628edacedfSDaniel Fojt 
2638edacedfSDaniel Fojt static int
policy_cache_set_int(long * out,ASN1_INTEGER * value)2648edacedfSDaniel Fojt policy_cache_set_int(long *out, ASN1_INTEGER *value)
2658edacedfSDaniel Fojt {
2668edacedfSDaniel Fojt 	if (value == NULL)
2678edacedfSDaniel Fojt 		return 1;
2688edacedfSDaniel Fojt 	if (value->type == V_ASN1_NEG_INTEGER)
2698edacedfSDaniel Fojt 		return 0;
2708edacedfSDaniel Fojt 	*out = ASN1_INTEGER_get(value);
2718edacedfSDaniel Fojt 	return 1;
2728edacedfSDaniel Fojt }
273