xref: /openbsd/lib/libcrypto/x509/x509_trs.c (revision d415bd75)
1 /* $OpenBSD: x509_trs.c,v 1.32 2023/07/02 17:12:17 tb Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 1999.
4  */
5 /* ====================================================================
6  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 
59 #include <stdio.h>
60 #include <string.h>
61 
62 #include <openssl/err.h>
63 #include <openssl/x509v3.h>
64 
65 #include "x509_local.h"
66 
67 static int tr_cmp(const X509_TRUST * const *a, const X509_TRUST * const *b);
68 static void trtable_free(X509_TRUST *p);
69 
70 static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
71 static int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
72 static int trust_compat(X509_TRUST *trust, X509 *x, int flags);
73 
74 static int obj_trust(int id, X509 *x, int flags);
75 static int (*default_trust)(int id, X509 *x, int flags) = obj_trust;
76 
77 /* WARNING: the following table should be kept in order of trust
78  * and without any gaps so we can just subtract the minimum trust
79  * value to get an index into the table
80  */
81 
82 static X509_TRUST trstandard[] = {
83 	{
84 		.trust = X509_TRUST_COMPAT,
85 		.check_trust = trust_compat,
86 		.name = "compatible",
87 	},
88 	{
89 		.trust = X509_TRUST_SSL_CLIENT,
90 		.check_trust = trust_1oidany,
91 		.name = "SSL Client",
92 		.arg1 = NID_client_auth,
93 	},
94 	{
95 		.trust = X509_TRUST_SSL_SERVER,
96 		.check_trust = trust_1oidany,
97 		.name = "SSL Server",
98 		.arg1 = NID_server_auth,
99 	},
100 	{
101 		.trust = X509_TRUST_EMAIL,
102 		.check_trust = trust_1oidany,
103 		.name = "S/MIME email",
104 		.arg1 = NID_email_protect,
105 	},
106 	{
107 		.trust = X509_TRUST_OBJECT_SIGN,
108 		.check_trust = trust_1oidany,
109 		.name = "Object Signer",
110 		.arg1 = NID_code_sign,
111 	},
112 	{
113 		.trust = X509_TRUST_OCSP_SIGN,
114 		.check_trust = trust_1oid,
115 		.name = "OCSP responder",
116 		.arg1 = NID_OCSP_sign,
117 	},
118 	{
119 		.trust = X509_TRUST_OCSP_REQUEST,
120 		.check_trust = trust_1oid,
121 		.name = "OCSP request",
122 		.arg1 = NID_ad_OCSP,
123 	},
124 	{
125 		.trust = X509_TRUST_TSA,
126 		.check_trust = trust_1oidany,
127 		.name = "TSA server",
128 		.arg1 = NID_time_stamp,
129 	},
130 };
131 
132 #define X509_TRUST_COUNT	(sizeof(trstandard) / sizeof(trstandard[0]))
133 
134 static STACK_OF(X509_TRUST) *trtable = NULL;
135 
136 static int
137 tr_cmp(const X509_TRUST * const *a, const X509_TRUST * const *b)
138 {
139 	return (*a)->trust - (*b)->trust;
140 }
141 
142 int
143 (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int)
144 {
145 	int (*oldtrust)(int , X509 *, int);
146 
147 	oldtrust = default_trust;
148 	default_trust = trust;
149 	return oldtrust;
150 }
151 LCRYPTO_ALIAS(X509_TRUST_set_default);
152 
153 int
154 X509_check_trust(X509 *x, int id, int flags)
155 {
156 	X509_TRUST *pt;
157 	int idx;
158 
159 	if (id == -1)
160 		return 1;
161 	/*
162 	 * XXX beck/jsing This enables self signed certs to be trusted for
163 	 * an unspecified id/trust flag value (this is NOT the
164 	 * X509_TRUST_DEFAULT), which was the longstanding
165 	 * openssl behaviour. boringssl does not have this behaviour.
166 	 *
167 	 * This should be revisited, but changing the default "not default"
168 	 * may break things.
169 	 */
170 	if (id == 0) {
171 		int rv;
172 		rv = obj_trust(NID_anyExtendedKeyUsage, x, 0);
173 		if (rv != X509_TRUST_UNTRUSTED)
174 			return rv;
175 		return trust_compat(NULL, x, 0);
176 	}
177 	idx = X509_TRUST_get_by_id(id);
178 	if (idx == -1)
179 		return default_trust(id, x, flags);
180 	pt = X509_TRUST_get0(idx);
181 	return pt->check_trust(pt, x, flags);
182 }
183 LCRYPTO_ALIAS(X509_check_trust);
184 
185 int
186 X509_TRUST_get_count(void)
187 {
188 	if (!trtable)
189 		return X509_TRUST_COUNT;
190 	return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT;
191 }
192 LCRYPTO_ALIAS(X509_TRUST_get_count);
193 
194 X509_TRUST *
195 X509_TRUST_get0(int idx)
196 {
197 	if (idx < 0)
198 		return NULL;
199 	if (idx < (int)X509_TRUST_COUNT)
200 		return trstandard + idx;
201 	return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT);
202 }
203 LCRYPTO_ALIAS(X509_TRUST_get0);
204 
205 int
206 X509_TRUST_get_by_id(int id)
207 {
208 	X509_TRUST tmp;
209 	int idx;
210 
211 	if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX))
212 		return id - X509_TRUST_MIN;
213 	tmp.trust = id;
214 	if (!trtable)
215 		return -1;
216 	idx = sk_X509_TRUST_find(trtable, &tmp);
217 	if (idx == -1)
218 		return -1;
219 	return idx + X509_TRUST_COUNT;
220 }
221 LCRYPTO_ALIAS(X509_TRUST_get_by_id);
222 
223 int
224 X509_TRUST_set(int *t, int trust)
225 {
226 	if (X509_TRUST_get_by_id(trust) == -1) {
227 		X509error(X509_R_INVALID_TRUST);
228 		return 0;
229 	}
230 	*t = trust;
231 	return 1;
232 }
233 LCRYPTO_ALIAS(X509_TRUST_set);
234 
235 int
236 X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
237     const char *name, int arg1, void *arg2)
238 {
239 	int idx;
240 	X509_TRUST *trtmp;
241 	char *name_dup;
242 
243 	/* This is set according to what we change: application can't set it */
244 	flags &= ~X509_TRUST_DYNAMIC;
245 	/* This will always be set for application modified trust entries */
246 	flags |= X509_TRUST_DYNAMIC_NAME;
247 	/* Get existing entry if any */
248 	idx = X509_TRUST_get_by_id(id);
249 	/* Need a new entry */
250 	if (idx == -1) {
251 		if (!(trtmp = malloc(sizeof(X509_TRUST)))) {
252 			X509error(ERR_R_MALLOC_FAILURE);
253 			return 0;
254 		}
255 		trtmp->flags = X509_TRUST_DYNAMIC;
256 	} else {
257 		trtmp = X509_TRUST_get0(idx);
258 		if (trtmp == NULL) {
259 			X509error(X509_R_INVALID_TRUST);
260 			return 0;
261 		}
262 	}
263 
264 	if ((name_dup = strdup(name)) == NULL)
265 		goto err;
266 
267 	/* free existing name if dynamic */
268 	if (trtmp->flags & X509_TRUST_DYNAMIC_NAME)
269 		free(trtmp->name);
270 	/* dup supplied name */
271 	trtmp->name = name_dup;
272 	/* Keep the dynamic flag of existing entry */
273 	trtmp->flags &= X509_TRUST_DYNAMIC;
274 	/* Set all other flags */
275 	trtmp->flags |= flags;
276 
277 	trtmp->trust = id;
278 	trtmp->check_trust = ck;
279 	trtmp->arg1 = arg1;
280 	trtmp->arg2 = arg2;
281 
282 	/* If it's a new entry, manage the dynamic table */
283 	if (idx == -1) {
284 		if (trtable == NULL &&
285 		    (trtable = sk_X509_TRUST_new(tr_cmp)) == NULL)
286 			goto err;
287 		if (sk_X509_TRUST_push(trtable, trtmp) == 0)
288 			goto err;
289 	}
290 	return 1;
291 
292 err:
293 	free(name_dup);
294 	if (idx == -1)
295 		free(trtmp);
296 	X509error(ERR_R_MALLOC_FAILURE);
297 	return 0;
298 }
299 LCRYPTO_ALIAS(X509_TRUST_add);
300 
301 static void
302 trtable_free(X509_TRUST *p)
303 {
304 	if (!p)
305 		return;
306 	if (p->flags & X509_TRUST_DYNAMIC) {
307 		if (p->flags & X509_TRUST_DYNAMIC_NAME)
308 			free(p->name);
309 		free(p);
310 	}
311 }
312 
313 void
314 X509_TRUST_cleanup(void)
315 {
316 	sk_X509_TRUST_pop_free(trtable, trtable_free);
317 	trtable = NULL;
318 }
319 LCRYPTO_ALIAS(X509_TRUST_cleanup);
320 
321 int
322 X509_TRUST_get_flags(const X509_TRUST *xp)
323 {
324 	return xp->flags;
325 }
326 LCRYPTO_ALIAS(X509_TRUST_get_flags);
327 
328 char *
329 X509_TRUST_get0_name(const X509_TRUST *xp)
330 {
331 	return xp->name;
332 }
333 LCRYPTO_ALIAS(X509_TRUST_get0_name);
334 
335 int
336 X509_TRUST_get_trust(const X509_TRUST *xp)
337 {
338 	return xp->trust;
339 }
340 LCRYPTO_ALIAS(X509_TRUST_get_trust);
341 
342 static int
343 trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
344 {
345 	if (x->aux && (x->aux->trust || x->aux->reject))
346 		return obj_trust(trust->arg1, x, flags);
347 	/* we don't have any trust settings: for compatibility
348 	 * we return trusted if it is self signed
349 	 */
350 	return trust_compat(trust, x, flags);
351 }
352 
353 static int
354 trust_1oid(X509_TRUST *trust, X509 *x, int flags)
355 {
356 	if (x->aux)
357 		return obj_trust(trust->arg1, x, flags);
358 	return X509_TRUST_UNTRUSTED;
359 }
360 
361 static int
362 trust_compat(X509_TRUST *trust, X509 *x, int flags)
363 {
364 	X509_check_purpose(x, -1, 0);
365 	if (x->ex_flags & EXFLAG_SS)
366 		return X509_TRUST_TRUSTED;
367 	else
368 		return X509_TRUST_UNTRUSTED;
369 }
370 
371 static int
372 obj_trust(int id, X509 *x, int flags)
373 {
374 	ASN1_OBJECT *obj;
375 	int i, nid;
376 	X509_CERT_AUX *ax;
377 
378 	ax = x->aux;
379 	if (!ax)
380 		return X509_TRUST_UNTRUSTED;
381 	if (ax->reject) {
382 		for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
383 			obj = sk_ASN1_OBJECT_value(ax->reject, i);
384 			nid = OBJ_obj2nid(obj);
385 			if (nid == id || nid == NID_anyExtendedKeyUsage)
386 				return X509_TRUST_REJECTED;
387 		}
388 	}
389 	if (ax->trust) {
390 		for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
391 			obj = sk_ASN1_OBJECT_value(ax->trust, i);
392 			nid = OBJ_obj2nid(obj);
393 			if (nid == id || nid == NID_anyExtendedKeyUsage)
394 				return X509_TRUST_TRUSTED;
395 		}
396 	}
397 	return X509_TRUST_UNTRUSTED;
398 }
399