]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
ba4356ae | 2 | * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved. |
21f77552 | 3 | * |
b1322259 RS |
4 | * Licensed under the OpenSSL license (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 | |
21f77552 DSH |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
b39fc560 | 11 | #include "internal/cryptlib.h" |
21f77552 | 12 | #include <openssl/x509v3.h> |
0c994d54 | 13 | #include "crypto/x509.h" |
21f77552 | 14 | |
0f113f3e | 15 | static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b); |
21f77552 DSH |
16 | static void trtable_free(X509_TRUST *p); |
17 | ||
6447cce3 | 18 | static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags); |
81f169e9 | 19 | static int trust_1oid(X509_TRUST *trust, X509 *x, int flags); |
068fdce8 | 20 | static int trust_compat(X509_TRUST *trust, X509 *x, int flags); |
21f77552 | 21 | |
6447cce3 | 22 | static int obj_trust(int id, X509 *x, int flags); |
0f113f3e | 23 | static int (*default_trust) (int id, X509 *x, int flags) = obj_trust; |
6447cce3 | 24 | |
0f113f3e MC |
25 | /* |
26 | * WARNING: the following table should be kept in order of trust and without | |
27 | * any gaps so we can just subtract the minimum trust value to get an index | |
28 | * into the table | |
dd413410 DSH |
29 | */ |
30 | ||
21f77552 | 31 | static X509_TRUST trstandard[] = { |
0f113f3e MC |
32 | {X509_TRUST_COMPAT, 0, trust_compat, "compatible", 0, NULL}, |
33 | {X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth, | |
34 | NULL}, | |
35 | {X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Server", NID_server_auth, | |
36 | NULL}, | |
37 | {X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect, | |
38 | NULL}, | |
39 | {X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, "Object Signer", NID_code_sign, | |
40 | NULL}, | |
41 | {X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, | |
42 | NULL}, | |
43 | {X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP, | |
44 | NULL}, | |
45 | {X509_TRUST_TSA, 0, trust_1oidany, "TSA server", NID_time_stamp, NULL} | |
21f77552 DSH |
46 | }; |
47 | ||
b6eb9827 | 48 | #define X509_TRUST_COUNT OSSL_NELEM(trstandard) |
dd413410 | 49 | |
21f77552 DSH |
50 | static STACK_OF(X509_TRUST) *trtable = NULL; |
51 | ||
0f113f3e | 52 | static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b) |
21f77552 | 53 | { |
0f113f3e | 54 | return (*a)->trust - (*b)->trust; |
21f77552 DSH |
55 | } |
56 | ||
0f113f3e MC |
57 | int (*X509_TRUST_set_default(int (*trust) (int, X509 *, int))) (int, X509 *, |
58 | int) { | |
59 | int (*oldtrust) (int, X509 *, int); | |
60 | oldtrust = default_trust; | |
61 | default_trust = trust; | |
62 | return oldtrust; | |
6447cce3 DSH |
63 | } |
64 | ||
21f77552 DSH |
65 | int X509_check_trust(X509 *x, int id, int flags) |
66 | { | |
0f113f3e MC |
67 | X509_TRUST *pt; |
68 | int idx; | |
0e7abc90 | 69 | |
0f113f3e | 70 | /* We get this as a default value */ |
33cc5dde VD |
71 | if (id == X509_TRUST_DEFAULT) |
72 | return obj_trust(NID_anyExtendedKeyUsage, x, | |
73 | flags | X509_TRUST_DO_SS_COMPAT); | |
0f113f3e MC |
74 | idx = X509_TRUST_get_by_id(id); |
75 | if (idx == -1) | |
76 | return default_trust(id, x, flags); | |
77 | pt = X509_TRUST_get0(idx); | |
78 | return pt->check_trust(pt, x, flags); | |
21f77552 DSH |
79 | } |
80 | ||
81 | int X509_TRUST_get_count(void) | |
82 | { | |
0f113f3e MC |
83 | if (!trtable) |
84 | return X509_TRUST_COUNT; | |
85 | return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT; | |
21f77552 DSH |
86 | } |
87 | ||
0f113f3e | 88 | X509_TRUST *X509_TRUST_get0(int idx) |
21f77552 | 89 | { |
0f113f3e MC |
90 | if (idx < 0) |
91 | return NULL; | |
92 | if (idx < (int)X509_TRUST_COUNT) | |
93 | return trstandard + idx; | |
94 | return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT); | |
21f77552 DSH |
95 | } |
96 | ||
97 | int X509_TRUST_get_by_id(int id) | |
98 | { | |
0f113f3e MC |
99 | X509_TRUST tmp; |
100 | int idx; | |
5b37fef0 | 101 | |
0f113f3e MC |
102 | if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) |
103 | return id - X509_TRUST_MIN; | |
5b37fef0 | 104 | if (trtable == NULL) |
0f113f3e | 105 | return -1; |
5b37fef0 | 106 | tmp.trust = id; |
0f113f3e | 107 | idx = sk_X509_TRUST_find(trtable, &tmp); |
5b37fef0 | 108 | if (idx < 0) |
0f113f3e MC |
109 | return -1; |
110 | return idx + X509_TRUST_COUNT; | |
21f77552 DSH |
111 | } |
112 | ||
926a56bf DSH |
113 | int X509_TRUST_set(int *t, int trust) |
114 | { | |
0f113f3e MC |
115 | if (X509_TRUST_get_by_id(trust) == -1) { |
116 | X509err(X509_F_X509_TRUST_SET, X509_R_INVALID_TRUST); | |
117 | return 0; | |
118 | } | |
119 | *t = trust; | |
120 | return 1; | |
926a56bf DSH |
121 | } |
122 | ||
0f113f3e | 123 | int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int), |
82643254 | 124 | const char *name, int arg1, void *arg2) |
21f77552 | 125 | { |
0f113f3e MC |
126 | int idx; |
127 | X509_TRUST *trtmp; | |
128 | /* | |
129 | * This is set according to what we change: application can't set it | |
130 | */ | |
131 | flags &= ~X509_TRUST_DYNAMIC; | |
132 | /* This will always be set for application modified trust entries */ | |
133 | flags |= X509_TRUST_DYNAMIC_NAME; | |
134 | /* Get existing entry if any */ | |
135 | idx = X509_TRUST_get_by_id(id); | |
136 | /* Need a new entry */ | |
137 | if (idx == -1) { | |
75ebbd9a | 138 | if ((trtmp = OPENSSL_malloc(sizeof(*trtmp))) == NULL) { |
0f113f3e MC |
139 | X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); |
140 | return 0; | |
141 | } | |
142 | trtmp->flags = X509_TRUST_DYNAMIC; | |
143 | } else | |
144 | trtmp = X509_TRUST_get0(idx); | |
145 | ||
146 | /* OPENSSL_free existing name if dynamic */ | |
147 | if (trtmp->flags & X509_TRUST_DYNAMIC_NAME) | |
148 | OPENSSL_free(trtmp->name); | |
149 | /* dup supplied name */ | |
7644a9ae | 150 | if ((trtmp->name = OPENSSL_strdup(name)) == NULL) { |
0f113f3e | 151 | X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); |
42328100 | 152 | goto err; |
0f113f3e MC |
153 | } |
154 | /* Keep the dynamic flag of existing entry */ | |
155 | trtmp->flags &= X509_TRUST_DYNAMIC; | |
156 | /* Set all other flags */ | |
157 | trtmp->flags |= flags; | |
158 | ||
159 | trtmp->trust = id; | |
160 | trtmp->check_trust = ck; | |
161 | trtmp->arg1 = arg1; | |
162 | trtmp->arg2 = arg2; | |
163 | ||
164 | /* If its a new entry manage the dynamic table */ | |
165 | if (idx == -1) { | |
75ebbd9a RS |
166 | if (trtable == NULL |
167 | && (trtable = sk_X509_TRUST_new(tr_cmp)) == NULL) { | |
0f113f3e | 168 | X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); |
42328100 | 169 | goto err;; |
0f113f3e MC |
170 | } |
171 | if (!sk_X509_TRUST_push(trtable, trtmp)) { | |
172 | X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE); | |
42328100 | 173 | goto err; |
0f113f3e MC |
174 | } |
175 | } | |
176 | return 1; | |
42328100 MC |
177 | err: |
178 | if (idx == -1) { | |
179 | OPENSSL_free(trtmp->name); | |
180 | OPENSSL_free(trtmp); | |
181 | } | |
182 | return 0; | |
21f77552 DSH |
183 | } |
184 | ||
185 | static void trtable_free(X509_TRUST *p) | |
0f113f3e MC |
186 | { |
187 | if (!p) | |
188 | return; | |
189 | if (p->flags & X509_TRUST_DYNAMIC) { | |
190 | if (p->flags & X509_TRUST_DYNAMIC_NAME) | |
191 | OPENSSL_free(p->name); | |
192 | OPENSSL_free(p); | |
193 | } | |
194 | } | |
21f77552 DSH |
195 | |
196 | void X509_TRUST_cleanup(void) | |
197 | { | |
0f113f3e MC |
198 | sk_X509_TRUST_pop_free(trtable, trtable_free); |
199 | trtable = NULL; | |
21f77552 DSH |
200 | } |
201 | ||
82643254 | 202 | int X509_TRUST_get_flags(const X509_TRUST *xp) |
21f77552 | 203 | { |
0f113f3e | 204 | return xp->flags; |
21f77552 DSH |
205 | } |
206 | ||
82643254 | 207 | char *X509_TRUST_get0_name(const X509_TRUST *xp) |
21f77552 | 208 | { |
0f113f3e | 209 | return xp->name; |
21f77552 DSH |
210 | } |
211 | ||
82643254 | 212 | int X509_TRUST_get_trust(const X509_TRUST *xp) |
21f77552 | 213 | { |
0f113f3e | 214 | return xp->trust; |
21f77552 DSH |
215 | } |
216 | ||
6447cce3 | 217 | static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags) |
21f77552 | 218 | { |
0f113f3e | 219 | /* |
33cc5dde VD |
220 | * Declare the chain verified if the desired trust OID is not rejected in |
221 | * any auxiliary trust info for this certificate, and the OID is either | |
222 | * expressly trusted, or else either "anyEKU" is trusted, or the | |
223 | * certificate is self-signed. | |
0f113f3e | 224 | */ |
33cc5dde VD |
225 | flags |= X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU; |
226 | return obj_trust(trust->arg1, x, flags); | |
068fdce8 DSH |
227 | } |
228 | ||
81f169e9 DSH |
229 | static int trust_1oid(X509_TRUST *trust, X509 *x, int flags) |
230 | { | |
33cc5dde VD |
231 | /* |
232 | * Declare the chain verified only if the desired trust OID is not | |
233 | * rejected and is expressly trusted. Neither "anyEKU" nor "compat" | |
234 | * trust in self-signed certificates apply. | |
235 | */ | |
236 | flags &= ~(X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU); | |
237 | return obj_trust(trust->arg1, x, flags); | |
81f169e9 DSH |
238 | } |
239 | ||
068fdce8 DSH |
240 | static int trust_compat(X509_TRUST *trust, X509 *x, int flags) |
241 | { | |
109f8b5d | 242 | /* Call for side-effect of computing hash and caching extensions */ |
ba4356ae BE |
243 | if (X509_check_purpose(x, -1, 0) != 1) |
244 | return X509_TRUST_UNTRUSTED; | |
245 | if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && (x->ex_flags & EXFLAG_SS)) | |
0f113f3e MC |
246 | return X509_TRUST_TRUSTED; |
247 | else | |
248 | return X509_TRUST_UNTRUSTED; | |
21f77552 DSH |
249 | } |
250 | ||
6447cce3 DSH |
251 | static int obj_trust(int id, X509 *x, int flags) |
252 | { | |
0daccd4d | 253 | X509_CERT_AUX *ax = x->aux; |
0f113f3e | 254 | int i; |
0daccd4d | 255 | |
33cc5dde | 256 | if (ax && ax->reject) { |
0f113f3e | 257 | for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) { |
0daccd4d VD |
258 | ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->reject, i); |
259 | int nid = OBJ_obj2nid(obj); | |
260 | ||
33cc5dde VD |
261 | if (nid == id || (nid == NID_anyExtendedKeyUsage && |
262 | (flags & X509_TRUST_OK_ANY_EKU))) | |
0f113f3e MC |
263 | return X509_TRUST_REJECTED; |
264 | } | |
265 | } | |
33cc5dde VD |
266 | |
267 | if (ax && ax->trust) { | |
0f113f3e | 268 | for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) { |
0daccd4d VD |
269 | ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->trust, i); |
270 | int nid = OBJ_obj2nid(obj); | |
271 | ||
33cc5dde VD |
272 | if (nid == id || (nid == NID_anyExtendedKeyUsage && |
273 | (flags & X509_TRUST_OK_ANY_EKU))) | |
0f113f3e MC |
274 | return X509_TRUST_TRUSTED; |
275 | } | |
3342dcea VD |
276 | /* |
277 | * Reject when explicit trust EKU are set and none match. | |
278 | * | |
279 | * Returning untrusted is enough for for full chains that end in | |
280 | * self-signed roots, because when explicit trust is specified it | |
281 | * suppresses the default blanket trust of self-signed objects. | |
282 | * | |
283 | * But for partial chains, this is not enough, because absent a similar | |
284 | * trust-self-signed policy, non matching EKUs are indistinguishable | |
285 | * from lack of EKU constraints. | |
286 | * | |
287 | * Therefore, failure to match any trusted purpose must trigger an | |
288 | * explicit reject. | |
289 | */ | |
290 | return X509_TRUST_REJECTED; | |
0f113f3e | 291 | } |
33cc5dde VD |
292 | |
293 | if ((flags & X509_TRUST_DO_SS_COMPAT) == 0) | |
294 | return X509_TRUST_UNTRUSTED; | |
295 | ||
296 | /* | |
297 | * Not rejected, and there is no list of accepted uses, try compat. | |
298 | */ | |
299 | return trust_compat(NULL, x, flags); | |
6447cce3 | 300 | } |