xref: /openbsd-src/lib/libcrypto/x509/x509_lib.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /* $OpenBSD: x509_lib.c,v 1.6 2022/11/26 16:08:54 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 /* X509 v3 extension utilities */
59 
60 #include <stdio.h>
61 
62 #include <openssl/conf.h>
63 #include <openssl/err.h>
64 #include <openssl/x509v3.h>
65 
66 #include "ext_dat.h"
67 #include "x509_local.h"
68 
69 static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL;
70 
71 static int ext_cmp(const X509V3_EXT_METHOD * const *a,
72     const X509V3_EXT_METHOD * const *b);
73 static void ext_list_free(X509V3_EXT_METHOD *ext);
74 
75 int
76 X509V3_EXT_add(X509V3_EXT_METHOD *ext)
77 {
78 	if (!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_cmp))) {
79 		X509V3error(ERR_R_MALLOC_FAILURE);
80 		return 0;
81 	}
82 	if (!sk_X509V3_EXT_METHOD_push(ext_list, ext)) {
83 		X509V3error(ERR_R_MALLOC_FAILURE);
84 		return 0;
85 	}
86 	return 1;
87 }
88 LCRYPTO_ALIAS(X509V3_EXT_add)
89 
90 static int
91 ext_cmp(const X509V3_EXT_METHOD * const *a, const X509V3_EXT_METHOD * const *b)
92 {
93 	return ((*a)->ext_nid - (*b)->ext_nid);
94 }
95 
96 static int ext_cmp_BSEARCH_CMP_FN(const void *, const void *);
97 static int ext_cmp(const X509V3_EXT_METHOD * const *, const X509V3_EXT_METHOD * const *);
98 static const X509V3_EXT_METHOD * *OBJ_bsearch_ext(const X509V3_EXT_METHOD * *key, const X509V3_EXT_METHOD * const *base, int num);
99 
100 static int
101 ext_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_)
102 {
103 	const X509V3_EXT_METHOD * const *a = a_;
104 	const X509V3_EXT_METHOD * const *b = b_;
105 	return ext_cmp(a, b);
106 }
107 
108 static const X509V3_EXT_METHOD **
109 OBJ_bsearch_ext(const X509V3_EXT_METHOD **key,
110     const X509V3_EXT_METHOD *const *base, int num)
111 {
112 	return (const X509V3_EXT_METHOD **)OBJ_bsearch_(key, base, num,
113 	    sizeof(const X509V3_EXT_METHOD *), ext_cmp_BSEARCH_CMP_FN);
114 }
115 
116 const X509V3_EXT_METHOD *
117 X509V3_EXT_get_nid(int nid)
118 {
119 	X509V3_EXT_METHOD tmp;
120 	const X509V3_EXT_METHOD *t = &tmp, * const *ret;
121 	int idx;
122 
123 	if (nid < 0)
124 		return NULL;
125 	tmp.ext_nid = nid;
126 	ret = OBJ_bsearch_ext(&t, standard_exts, STANDARD_EXTENSION_COUNT);
127 	if (ret)
128 		return *ret;
129 	if (!ext_list)
130 		return NULL;
131 	idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp);
132 	if (idx == -1)
133 		return NULL;
134 	return sk_X509V3_EXT_METHOD_value(ext_list, idx);
135 }
136 LCRYPTO_ALIAS(X509V3_EXT_get_nid)
137 
138 const X509V3_EXT_METHOD *
139 X509V3_EXT_get(X509_EXTENSION *ext)
140 {
141 	int nid;
142 
143 	if ((nid = OBJ_obj2nid(ext->object)) == NID_undef)
144 		return NULL;
145 	return X509V3_EXT_get_nid(nid);
146 }
147 LCRYPTO_ALIAS(X509V3_EXT_get)
148 
149 int
150 X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist)
151 {
152 	for (; extlist->ext_nid!=-1; extlist++)
153 		if (!X509V3_EXT_add(extlist))
154 			return 0;
155 	return 1;
156 }
157 LCRYPTO_ALIAS(X509V3_EXT_add_list)
158 
159 int
160 X509V3_EXT_add_alias(int nid_to, int nid_from)
161 {
162 	const X509V3_EXT_METHOD *ext;
163 	X509V3_EXT_METHOD *tmpext;
164 
165 	if (!(ext = X509V3_EXT_get_nid(nid_from))) {
166 		X509V3error(X509V3_R_EXTENSION_NOT_FOUND);
167 		return 0;
168 	}
169 	if (!(tmpext = malloc(sizeof(X509V3_EXT_METHOD)))) {
170 		X509V3error(ERR_R_MALLOC_FAILURE);
171 		return 0;
172 	}
173 	*tmpext = *ext;
174 	tmpext->ext_nid = nid_to;
175 	tmpext->ext_flags |= X509V3_EXT_DYNAMIC;
176 	if (!X509V3_EXT_add(tmpext)) {
177 		free(tmpext);
178 		return 0;
179 	}
180 	return 1;
181 }
182 LCRYPTO_ALIAS(X509V3_EXT_add_alias)
183 
184 void
185 X509V3_EXT_cleanup(void)
186 {
187 	sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free);
188 	ext_list = NULL;
189 }
190 LCRYPTO_ALIAS(X509V3_EXT_cleanup)
191 
192 static void
193 ext_list_free(X509V3_EXT_METHOD *ext)
194 {
195 	if (ext->ext_flags & X509V3_EXT_DYNAMIC)
196 		free(ext);
197 }
198 
199 /* Legacy function: we don't need to add standard extensions
200  * any more because they are now kept in ext_dat.h.
201  */
202 
203 int
204 X509V3_add_standard_extensions(void)
205 {
206 	return 1;
207 }
208 LCRYPTO_ALIAS(X509V3_add_standard_extensions)
209 
210 /* Return an extension internal structure */
211 
212 void *
213 X509V3_EXT_d2i(X509_EXTENSION *ext)
214 {
215 	const X509V3_EXT_METHOD *method;
216 	const unsigned char *p;
217 
218 	if (!(method = X509V3_EXT_get(ext)))
219 		return NULL;
220 	p = ext->value->data;
221 	if (method->it)
222 		return ASN1_item_d2i(NULL, &p, ext->value->length,
223 		    method->it);
224 	return method->d2i(NULL, &p, ext->value->length);
225 }
226 LCRYPTO_ALIAS(X509V3_EXT_d2i)
227 
228 /* Get critical flag and decoded version of extension from a NID.
229  * The "idx" variable returns the last found extension and can
230  * be used to retrieve multiple extensions of the same NID.
231  * However multiple extensions with the same NID is usually
232  * due to a badly encoded certificate so if idx is NULL we
233  * choke if multiple extensions exist.
234  * The "crit" variable is set to the critical value.
235  * The return value is the decoded extension or NULL on
236  * error. The actual error can have several different causes,
237  * the value of *crit reflects the cause:
238  * >= 0, extension found but not decoded (reflects critical value).
239  * -1 extension not found.
240  * -2 extension occurs more than once.
241  */
242 
243 void *
244 X509V3_get_d2i(const STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx)
245 {
246 	int lastpos, i;
247 	X509_EXTENSION *ex, *found_ex = NULL;
248 
249 	if (!x) {
250 		if (idx)
251 			*idx = -1;
252 		if (crit)
253 			*crit = -1;
254 		return NULL;
255 	}
256 	if (idx)
257 		lastpos = *idx + 1;
258 	else
259 		lastpos = 0;
260 	if (lastpos < 0)
261 		lastpos = 0;
262 	for (i = lastpos; i < sk_X509_EXTENSION_num(x); i++) {
263 		ex = sk_X509_EXTENSION_value(x, i);
264 		if (OBJ_obj2nid(ex->object) == nid) {
265 			if (idx) {
266 				*idx = i;
267 				found_ex = ex;
268 				break;
269 			} else if (found_ex) {
270 				/* Found more than one */
271 				if (crit)
272 					*crit = -2;
273 				return NULL;
274 			}
275 			found_ex = ex;
276 		}
277 	}
278 	if (found_ex) {
279 		/* Found it */
280 		if (crit)
281 			*crit = X509_EXTENSION_get_critical(found_ex);
282 		return X509V3_EXT_d2i(found_ex);
283 	}
284 
285 	/* Extension not found */
286 	if (idx)
287 		*idx = -1;
288 	if (crit)
289 		*crit = -1;
290 	return NULL;
291 }
292 LCRYPTO_ALIAS(X509V3_get_d2i)
293 
294 /* This function is a general extension append, replace and delete utility.
295  * The precise operation is governed by the 'flags' value. The 'crit' and
296  * 'value' arguments (if relevant) are the extensions internal structure.
297  */
298 
299 int
300 X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value,
301     int crit, unsigned long flags)
302 {
303 	int extidx = -1;
304 	int errcode;
305 	X509_EXTENSION *ext, *extmp;
306 	unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
307 
308 	/* If appending we don't care if it exists, otherwise
309 	 * look for existing extension.
310 	 */
311 	if (ext_op != X509V3_ADD_APPEND)
312 		extidx = X509v3_get_ext_by_NID(*x, nid, -1);
313 
314 	/* See if extension exists */
315 	if (extidx >= 0) {
316 		/* If keep existing, nothing to do */
317 		if (ext_op == X509V3_ADD_KEEP_EXISTING)
318 			return 1;
319 		/* If default then its an error */
320 		if (ext_op == X509V3_ADD_DEFAULT) {
321 			errcode = X509V3_R_EXTENSION_EXISTS;
322 			goto err;
323 		}
324 		/* If delete, just delete it */
325 		if (ext_op == X509V3_ADD_DELETE) {
326 			if ((extmp = sk_X509_EXTENSION_delete(*x, extidx)) == NULL)
327 				return -1;
328 			X509_EXTENSION_free(extmp);
329 			return 1;
330 		}
331 	} else {
332 		/* If replace existing or delete, error since
333 		 * extension must exist
334 		 */
335 		if ((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
336 		    (ext_op == X509V3_ADD_DELETE)) {
337 			errcode = X509V3_R_EXTENSION_NOT_FOUND;
338 			goto err;
339 		}
340 	}
341 
342 	/* If we get this far then we have to create an extension:
343 	 * could have some flags for alternative encoding schemes...
344 	 */
345 
346 	ext = X509V3_EXT_i2d(nid, crit, value);
347 
348 	if (!ext) {
349 		X509V3error(X509V3_R_ERROR_CREATING_EXTENSION);
350 		return 0;
351 	}
352 
353 	/* If extension exists replace it.. */
354 	if (extidx >= 0) {
355 		extmp = sk_X509_EXTENSION_value(*x, extidx);
356 		X509_EXTENSION_free(extmp);
357 		if (!sk_X509_EXTENSION_set(*x, extidx, ext))
358 			return -1;
359 		return 1;
360 	}
361 
362 	if (!*x && !(*x = sk_X509_EXTENSION_new_null()))
363 		return -1;
364 	if (!sk_X509_EXTENSION_push(*x, ext))
365 		return -1;
366 
367 	return 1;
368 
369 err:
370 	if (!(flags & X509V3_ADD_SILENT))
371 		X509V3error(errcode);
372 	return 0;
373 }
374 LCRYPTO_ALIAS(X509V3_add1_i2d)
375