Update copyright year
[openssl.git] / crypto / x509 / pcy_cache.c
1 /*
2  * Copyright 2004-2020 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "internal/cryptlib.h"
11 #include <openssl/x509.h>
12 #include <openssl/x509v3.h>
13 #include "crypto/x509.h"
14
15 #include "pcy_local.h"
16
17 DEFINE_STACK_OF(POLICYINFO)
18
19 static int policy_data_cmp(const X509_POLICY_DATA *const *a,
20                            const X509_POLICY_DATA *const *b);
21 static int policy_cache_set_int(long *out, ASN1_INTEGER *value);
22
23 /*
24  * Set cache entry according to CertificatePolicies extension. Note: this
25  * destroys the passed CERTIFICATEPOLICIES structure.
26  */
27
28 static int policy_cache_create(X509 *x,
29                                CERTIFICATEPOLICIES *policies, int crit)
30 {
31     int i, num, ret = 0;
32     X509_POLICY_CACHE *cache = x->policy_cache;
33     X509_POLICY_DATA *data = NULL;
34     POLICYINFO *policy;
35
36     if ((num = sk_POLICYINFO_num(policies)) <= 0)
37         goto bad_policy;
38     cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp);
39     if (cache->data == NULL) {
40         X509V3err(X509V3_F_POLICY_CACHE_CREATE, ERR_R_MALLOC_FAILURE);
41         goto just_cleanup;
42     }
43     for (i = 0; i < num; i++) {
44         policy = sk_POLICYINFO_value(policies, i);
45         data = policy_data_new(policy, NULL, crit);
46         if (data == NULL) {
47             X509V3err(X509V3_F_POLICY_CACHE_CREATE, ERR_R_MALLOC_FAILURE);
48             goto just_cleanup;
49         }
50         /*
51          * Duplicate policy OIDs are illegal: reject if matches found.
52          */
53         if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) {
54             if (cache->anyPolicy) {
55                 ret = -1;
56                 goto bad_policy;
57             }
58             cache->anyPolicy = data;
59         } else if (sk_X509_POLICY_DATA_find(cache->data, data) >=0 ) {
60             ret = -1;
61             goto bad_policy;
62         } else if (!sk_X509_POLICY_DATA_push(cache->data, data)) {
63             X509V3err(X509V3_F_POLICY_CACHE_CREATE, ERR_R_MALLOC_FAILURE);
64             goto bad_policy;
65         }
66         data = NULL;
67     }
68     ret = 1;
69
70  bad_policy:
71     if (ret == -1)
72         x->ex_flags |= EXFLAG_INVALID_POLICY;
73     policy_data_free(data);
74  just_cleanup:
75     sk_POLICYINFO_pop_free(policies, POLICYINFO_free);
76     if (ret <= 0) {
77         sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free);
78         cache->data = NULL;
79     }
80     return ret;
81 }
82
83 static int policy_cache_new(X509 *x)
84 {
85     X509_POLICY_CACHE *cache;
86     ASN1_INTEGER *ext_any = NULL;
87     POLICY_CONSTRAINTS *ext_pcons = NULL;
88     CERTIFICATEPOLICIES *ext_cpols = NULL;
89     POLICY_MAPPINGS *ext_pmaps = NULL;
90     int i;
91
92     if (x->policy_cache != NULL)
93         return 1;
94     cache = OPENSSL_malloc(sizeof(*cache));
95     if (cache == NULL) {
96         X509V3err(X509V3_F_POLICY_CACHE_NEW, ERR_R_MALLOC_FAILURE);
97         return 0;
98     }
99     cache->anyPolicy = NULL;
100     cache->data = NULL;
101     cache->any_skip = -1;
102     cache->explicit_skip = -1;
103     cache->map_skip = -1;
104
105     x->policy_cache = cache;
106
107     /*
108      * Handle requireExplicitPolicy *first*. Need to process this even if we
109      * don't have any policies.
110      */
111     ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL);
112
113     if (!ext_pcons) {
114         if (i != -1)
115             goto bad_cache;
116     } else {
117         if (!ext_pcons->requireExplicitPolicy
118             && !ext_pcons->inhibitPolicyMapping)
119             goto bad_cache;
120         if (!policy_cache_set_int(&cache->explicit_skip,
121                                   ext_pcons->requireExplicitPolicy))
122             goto bad_cache;
123         if (!policy_cache_set_int(&cache->map_skip,
124                                   ext_pcons->inhibitPolicyMapping))
125             goto bad_cache;
126     }
127
128     /* Process CertificatePolicies */
129
130     ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL);
131     /*
132      * If no CertificatePolicies extension or problem decoding then there is
133      * no point continuing because the valid policies will be NULL.
134      */
135     if (!ext_cpols) {
136         /* If not absent some problem with extension */
137         if (i != -1)
138             goto bad_cache;
139         return 1;
140     }
141
142     i = policy_cache_create(x, ext_cpols, i);
143
144     /* NB: ext_cpols freed by policy_cache_set_policies */
145
146     if (i <= 0)
147         return i;
148
149     ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL);
150
151     if (!ext_pmaps) {
152         /* If not absent some problem with extension */
153         if (i != -1)
154             goto bad_cache;
155     } else {
156         i = policy_cache_set_mapping(x, ext_pmaps);
157         if (i <= 0)
158             goto bad_cache;
159     }
160
161     ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL);
162
163     if (!ext_any) {
164         if (i != -1)
165             goto bad_cache;
166     } else if (!policy_cache_set_int(&cache->any_skip, ext_any))
167         goto bad_cache;
168     goto just_cleanup;
169
170  bad_cache:
171     x->ex_flags |= EXFLAG_INVALID_POLICY;
172
173  just_cleanup:
174     POLICY_CONSTRAINTS_free(ext_pcons);
175     ASN1_INTEGER_free(ext_any);
176     return 1;
177
178 }
179
180 void policy_cache_free(X509_POLICY_CACHE *cache)
181 {
182     if (!cache)
183         return;
184     policy_data_free(cache->anyPolicy);
185     sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free);
186     OPENSSL_free(cache);
187 }
188
189 const X509_POLICY_CACHE *policy_cache_set(X509 *x)
190 {
191
192     if (x->policy_cache == NULL) {
193         CRYPTO_THREAD_write_lock(x->lock);
194         policy_cache_new(x);
195         CRYPTO_THREAD_unlock(x->lock);
196     }
197
198     return x->policy_cache;
199
200 }
201
202 X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache,
203                                          const ASN1_OBJECT *id)
204 {
205     int idx;
206     X509_POLICY_DATA tmp;
207     tmp.valid_policy = (ASN1_OBJECT *)id;
208     idx = sk_X509_POLICY_DATA_find(cache->data, &tmp);
209     return sk_X509_POLICY_DATA_value(cache->data, idx);
210 }
211
212 static int policy_data_cmp(const X509_POLICY_DATA *const *a,
213                            const X509_POLICY_DATA *const *b)
214 {
215     return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy);
216 }
217
218 static int policy_cache_set_int(long *out, ASN1_INTEGER *value)
219 {
220     if (value == NULL)
221         return 1;
222     if (value->type == V_ASN1_NEG_INTEGER)
223         return 0;
224     *out = ASN1_INTEGER_get(value);
225     return 1;
226 }