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