xref: /openbsd-src/lib/libcrypto/x509/x509_vpm.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /* $OpenBSD: x509_vpm.c,v 1.37 2023/04/28 16:50:16 beck Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 2004.
4  */
5 /* ====================================================================
6  * Copyright (c) 2004 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/buffer.h>
63 #include <openssl/crypto.h>
64 #include <openssl/lhash.h>
65 #include <openssl/stack.h>
66 #include <openssl/x509.h>
67 #include <openssl/x509v3.h>
68 
69 #include "x509_local.h"
70 
71 /* X509_VERIFY_PARAM functions */
72 
73 int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, const char *email,
74     size_t emaillen);
75 int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, const unsigned char *ip,
76     size_t iplen);
77 
78 #define SET_HOST 0
79 #define ADD_HOST 1
80 
81 static void
82 str_free(char *s)
83 {
84     free(s);
85 }
86 
87 /*
88  * Post 1.0.1 sk function "deep_copy".  For the moment we simply make
89  * these take void * and use them directly without a glorious blob of
90  * obfuscating macros of dubious value in front of them. All this in
91  * preparation for a rototilling of safestack.h (likely inspired by
92  * this).
93  */
94 static void *
95 sk_deep_copy(void *sk_void, void *copy_func_void, void *free_func_void)
96 {
97 	_STACK *sk = sk_void;
98 	void *(*copy_func)(void *) = copy_func_void;
99 	void (*free_func)(void *) = free_func_void;
100 	_STACK *ret = sk_dup(sk);
101 	size_t i;
102 
103 	if (ret == NULL)
104 		return NULL;
105 
106 	for (i = 0; i < ret->num; i++) {
107 		if (ret->data[i] == NULL)
108 			continue;
109 		ret->data[i] = copy_func(ret->data[i]);
110 		if (ret->data[i] == NULL) {
111 			size_t j;
112 			for (j = 0; j < i; j++) {
113 				if (ret->data[j] != NULL)
114 					free_func(ret->data[j]);
115 			}
116 			sk_free(ret);
117 			return NULL;
118 		}
119 	}
120 
121 	return ret;
122 }
123 
124 static int
125 x509_param_set_hosts_internal(X509_VERIFY_PARAM_ID *id, int mode,
126     const char *name, size_t namelen)
127 {
128 	char *copy;
129 
130 	if (name != NULL && namelen == 0)
131 		namelen = strlen(name);
132 	/*
133 	 * Refuse names with embedded NUL bytes.
134 	 */
135 	if (name && memchr(name, '\0', namelen))
136 		return 0;
137 
138 	if (mode == SET_HOST && id->hosts) {
139 		sk_OPENSSL_STRING_pop_free(id->hosts, str_free);
140 		id->hosts = NULL;
141 	}
142 	if (name == NULL || namelen == 0)
143 		return 1;
144 	copy = strndup(name, namelen);
145 	if (copy == NULL)
146 		return 0;
147 
148 	if (id->hosts == NULL &&
149 	    (id->hosts = sk_OPENSSL_STRING_new_null()) == NULL) {
150 		free(copy);
151 		return 0;
152 	}
153 
154 	if (!sk_OPENSSL_STRING_push(id->hosts, copy)) {
155 		free(copy);
156 		if (sk_OPENSSL_STRING_num(id->hosts) == 0) {
157 			sk_OPENSSL_STRING_free(id->hosts);
158 			id->hosts = NULL;
159 		}
160 		return 0;
161 	}
162 
163 	return 1;
164 }
165 
166 static void
167 x509_verify_param_zero(X509_VERIFY_PARAM *param)
168 {
169 	X509_VERIFY_PARAM_ID *paramid;
170 	if (!param)
171 		return;
172 	free(param->name);
173 	param->name = NULL;
174 	param->purpose = 0;
175 	param->trust = 0;
176 	/*param->inh_flags = X509_VP_FLAG_DEFAULT;*/
177 	param->inh_flags = 0;
178 	param->flags = 0;
179 	param->depth = -1;
180 	if (param->policies) {
181 		sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
182 		param->policies = NULL;
183 	}
184 	paramid = param->id;
185 	if (paramid->hosts) {
186 		sk_OPENSSL_STRING_pop_free(paramid->hosts, str_free);
187 		paramid->hosts = NULL;
188 	}
189 	free(paramid->peername);
190 	paramid->peername = NULL;
191 	free(paramid->email);
192 	paramid->email = NULL;
193 	paramid->emaillen = 0;
194 	free(paramid->ip);
195 	paramid->ip = NULL;
196 	paramid->iplen = 0;
197 	paramid->poisoned = 0;
198 }
199 
200 X509_VERIFY_PARAM *
201 X509_VERIFY_PARAM_new(void)
202 {
203 	X509_VERIFY_PARAM *param;
204 	X509_VERIFY_PARAM_ID *paramid;
205 	param = calloc(1, sizeof(X509_VERIFY_PARAM));
206 	if (param == NULL)
207 		return NULL;
208 	paramid = calloc(1, sizeof(X509_VERIFY_PARAM_ID));
209 	if (paramid == NULL) {
210 		free(param);
211 		return NULL;
212 	}
213 	param->id = paramid;
214 	x509_verify_param_zero(param);
215 	return param;
216 }
217 LCRYPTO_ALIAS(X509_VERIFY_PARAM_new);
218 
219 void
220 X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param)
221 {
222 	if (param == NULL)
223 		return;
224 	x509_verify_param_zero(param);
225 	free(param->id);
226 	free(param);
227 }
228 LCRYPTO_ALIAS(X509_VERIFY_PARAM_free);
229 
230 /*
231  * This function determines how parameters are "inherited" from one structure
232  * to another. There are several different ways this can happen.
233  *
234  * 1. If a child structure needs to have its values initialized from a parent
235  *    they are simply copied across. For example SSL_CTX copied to SSL.
236  * 2. If the structure should take on values only if they are currently unset.
237  *    For example the values in an SSL structure will take appropriate value
238  *    for SSL servers or clients but only if the application has not set new
239  *    ones.
240  *
241  * The "inh_flags" field determines how this function behaves.
242  *
243  * Normally any values which are set in the default are not copied from the
244  * destination and verify flags are ORed together.
245  *
246  * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied
247  * to the destination. Effectively the values in "to" become default values
248  * which will be used only if nothing new is set in "from".
249  *
250  * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether
251  * they are set or not. Flags is still Ored though.
252  *
253  * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead
254  * of ORed.
255  *
256  * If X509_VP_FLAG_LOCKED is set then no values are copied.
257  *
258  * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed
259  * after the next call.
260  */
261 
262 /* Macro to test if a field should be copied from src to dest */
263 
264 #define test_x509_verify_param_copy(field, def) \
265 	(to_overwrite || \
266 		((src->field != def) && (to_default || (dest->field == def))))
267 
268 /* As above but for ID fields */
269 
270 #define test_x509_verify_param_copy_id(idf, def) \
271 	test_x509_verify_param_copy(id->idf, def)
272 
273 /* Macro to test and copy a field if necessary */
274 
275 #define x509_verify_param_copy(field, def) \
276 	if (test_x509_verify_param_copy(field, def)) \
277 		dest->field = src->field
278 
279 int
280 X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, const X509_VERIFY_PARAM *src)
281 {
282 	unsigned long inh_flags;
283 	int to_default, to_overwrite;
284 	X509_VERIFY_PARAM_ID *id;
285 
286 	if (!src)
287 		return 1;
288 	id = src->id;
289 	inh_flags = dest->inh_flags | src->inh_flags;
290 
291 	if (inh_flags & X509_VP_FLAG_ONCE)
292 		dest->inh_flags = 0;
293 
294 	if (inh_flags & X509_VP_FLAG_LOCKED)
295 		return 1;
296 
297 	if (inh_flags & X509_VP_FLAG_DEFAULT)
298 		to_default = 1;
299 	else
300 		to_default = 0;
301 
302 	if (inh_flags & X509_VP_FLAG_OVERWRITE)
303 		to_overwrite = 1;
304 	else
305 		to_overwrite = 0;
306 
307 	x509_verify_param_copy(purpose, 0);
308 	x509_verify_param_copy(trust, 0);
309 	x509_verify_param_copy(depth, -1);
310 
311 	/* If overwrite or check time not set, copy across */
312 
313 	if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) {
314 		dest->check_time = src->check_time;
315 		dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME;
316 		/* Don't need to copy flag: that is done below */
317 	}
318 
319 	if (inh_flags & X509_VP_FLAG_RESET_FLAGS)
320 		dest->flags = 0;
321 
322 	dest->flags |= src->flags;
323 
324 	if (test_x509_verify_param_copy(policies, NULL)) {
325 		if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies))
326 			return 0;
327 	}
328 
329 	/* Copy the host flags if and only if we're copying the host list */
330 	if (test_x509_verify_param_copy_id(hosts, NULL)) {
331 		if (dest->id->hosts) {
332 			sk_OPENSSL_STRING_pop_free(dest->id->hosts, str_free);
333 			dest->id->hosts = NULL;
334 		}
335 		if (id->hosts) {
336 			dest->id->hosts =
337 			    sk_deep_copy(id->hosts, strdup, str_free);
338 			if (dest->id->hosts == NULL)
339 				return 0;
340 			dest->id->hostflags = id->hostflags;
341 		}
342 	}
343 
344 	if (test_x509_verify_param_copy_id(email, NULL)) {
345 		if (!X509_VERIFY_PARAM_set1_email(dest, id->email,
346 		    id->emaillen))
347 			return 0;
348 	}
349 
350 	if (test_x509_verify_param_copy_id(ip, NULL)) {
351 		if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen))
352 			return 0;
353 	}
354 
355 	return 1;
356 }
357 LCRYPTO_ALIAS(X509_VERIFY_PARAM_inherit);
358 
359 int
360 X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, const X509_VERIFY_PARAM *from)
361 {
362 	unsigned long save_flags = to->inh_flags;
363 	int ret;
364 
365 	to->inh_flags |= X509_VP_FLAG_DEFAULT;
366 	ret = X509_VERIFY_PARAM_inherit(to, from);
367 	to->inh_flags = save_flags;
368 	return ret;
369 }
370 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set1);
371 
372 static int
373 x509_param_set1_internal(char **pdest, size_t *pdestlen,  const char *src,
374     size_t srclen, int nonul)
375 {
376 	char *tmp;
377 
378 	if (src == NULL)
379 		return 0;
380 
381 	if (srclen == 0) {
382 		srclen = strlen(src);
383 		if (srclen == 0)
384 			return 0;
385 		if ((tmp = strdup(src)) == NULL)
386 			return 0;
387 	} else {
388 		if (nonul && memchr(src, '\0', srclen))
389 			return 0;
390 		if ((tmp = malloc(srclen)) == NULL)
391 			return 0;
392 		memcpy(tmp, src, srclen);
393 	}
394 
395 	if (*pdest)
396 		free(*pdest);
397 	*pdest = tmp;
398 	if (pdestlen)
399 		*pdestlen = srclen;
400 	return 1;
401 }
402 
403 int
404 X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name)
405 {
406 	free(param->name);
407 	param->name = NULL;
408 	if (name == NULL)
409 		return 1;
410 	param->name = strdup(name);
411 	if (param->name)
412 		return 1;
413 	return 0;
414 }
415 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set1_name);
416 
417 int
418 X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags)
419 {
420 	param->flags |= flags;
421 	return 1;
422 }
423 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set_flags);
424 
425 int
426 X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags)
427 {
428 	param->flags &= ~flags;
429 	return 1;
430 }
431 LCRYPTO_ALIAS(X509_VERIFY_PARAM_clear_flags);
432 
433 unsigned long
434 X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param)
435 {
436 	return param->flags;
437 }
438 LCRYPTO_ALIAS(X509_VERIFY_PARAM_get_flags);
439 
440 int
441 X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose)
442 {
443 	return X509_PURPOSE_set(&param->purpose, purpose);
444 }
445 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set_purpose);
446 
447 int
448 X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust)
449 {
450 	return X509_TRUST_set(&param->trust, trust);
451 }
452 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set_trust);
453 
454 void
455 X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth)
456 {
457 	param->depth = depth;
458 }
459 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set_depth);
460 
461 void
462 X509_VERIFY_PARAM_set_auth_level(X509_VERIFY_PARAM *param, int auth_level)
463 {
464 	param->security_level = auth_level;
465 }
466 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set_auth_level);
467 
468 time_t
469 X509_VERIFY_PARAM_get_time(const X509_VERIFY_PARAM *param)
470 {
471 	return param->check_time;
472 }
473 LCRYPTO_ALIAS(X509_VERIFY_PARAM_get_time);
474 
475 void
476 X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t)
477 {
478 	param->check_time = t;
479 	param->flags |= X509_V_FLAG_USE_CHECK_TIME;
480 }
481 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set_time);
482 
483 int
484 X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ASN1_OBJECT *policy)
485 {
486 	if (!param->policies) {
487 		param->policies = sk_ASN1_OBJECT_new_null();
488 		if (!param->policies)
489 			return 0;
490 	}
491 	if (!sk_ASN1_OBJECT_push(param->policies, policy))
492 		return 0;
493 	return 1;
494 }
495 LCRYPTO_ALIAS(X509_VERIFY_PARAM_add0_policy);
496 
497 int
498 X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
499     STACK_OF(ASN1_OBJECT) *policies)
500 {
501 	int i;
502 	ASN1_OBJECT *oid, *doid;
503 
504 	if (!param)
505 		return 0;
506 	if (param->policies)
507 		sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
508 
509 	if (!policies) {
510 		param->policies = NULL;
511 		return 1;
512 	}
513 
514 	param->policies = sk_ASN1_OBJECT_new_null();
515 	if (!param->policies)
516 		return 0;
517 
518 	for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++) {
519 		oid = sk_ASN1_OBJECT_value(policies, i);
520 		doid = OBJ_dup(oid);
521 		if (!doid)
522 			return 0;
523 		if (!sk_ASN1_OBJECT_push(param->policies, doid)) {
524 			ASN1_OBJECT_free(doid);
525 			return 0;
526 		}
527 	}
528 	return 1;
529 }
530 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set1_policies);
531 
532 int
533 X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
534     const char *name, size_t namelen)
535 {
536 	if (x509_param_set_hosts_internal(param->id, SET_HOST, name, namelen))
537 		return 1;
538 	param->id->poisoned = 1;
539 	return 0;
540 }
541 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set1_host);
542 
543 int
544 X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
545     const char *name, size_t namelen)
546 {
547 	if (x509_param_set_hosts_internal(param->id, ADD_HOST, name, namelen))
548 		return 1;
549 	param->id->poisoned = 1;
550 	return 0;
551 }
552 LCRYPTO_ALIAS(X509_VERIFY_PARAM_add1_host);
553 
554 void
555 X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, unsigned int flags)
556 {
557 	param->id->hostflags = flags;
558 }
559 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set_hostflags);
560 
561 char *
562 X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param)
563 {
564 	return param->id->peername;
565 }
566 LCRYPTO_ALIAS(X509_VERIFY_PARAM_get0_peername);
567 
568 int
569 X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,  const char *email,
570     size_t emaillen)
571 {
572 	if (x509_param_set1_internal(&param->id->email, &param->id->emaillen,
573 	    email, emaillen, 1))
574 		return 1;
575 	param->id->poisoned = 1;
576 	return 0;
577 }
578 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set1_email);
579 
580 int
581 X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, const unsigned char *ip,
582     size_t iplen)
583 {
584 	if (iplen != 4 && iplen != 16)
585 		goto err;
586 	if (x509_param_set1_internal((char **)&param->id->ip, &param->id->iplen,
587 		(char *)ip, iplen, 0))
588 		return 1;
589  err:
590 	param->id->poisoned = 1;
591 	return 0;
592 }
593 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set1_ip);
594 
595 int
596 X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
597 {
598 	unsigned char ipout[16];
599 	size_t iplen;
600 
601 	iplen = (size_t)a2i_ipadd(ipout, ipasc);
602 	return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen);
603 }
604 LCRYPTO_ALIAS(X509_VERIFY_PARAM_set1_ip_asc);
605 
606 int
607 X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
608 {
609 	return param->depth;
610 }
611 LCRYPTO_ALIAS(X509_VERIFY_PARAM_get_depth);
612 
613 const char *
614 X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
615 {
616 	return param->name;
617 }
618 LCRYPTO_ALIAS(X509_VERIFY_PARAM_get0_name);
619 
620 static const X509_VERIFY_PARAM_ID _empty_id = { NULL };
621 
622 #define vpm_empty_id (X509_VERIFY_PARAM_ID *)&_empty_id
623 
624 /*
625  * Default verify parameters: these are used for various applications and can
626  * be overridden by the user specified table.
627  */
628 
629 static const X509_VERIFY_PARAM default_table[] = {
630 	{
631 		.name = "default",
632 		.flags = X509_V_FLAG_TRUSTED_FIRST,
633 		.depth = 100,
634 		.trust = 0,  /* XXX This is not the default trust value */
635 		.id = vpm_empty_id
636 	},
637 	{
638 		.name = "pkcs7",
639 		.purpose = X509_PURPOSE_SMIME_SIGN,
640 		.trust = X509_TRUST_EMAIL,
641 		.depth = -1,
642 		.id = vpm_empty_id
643 	},
644 	{
645 		.name = "smime_sign",
646 		.purpose = X509_PURPOSE_SMIME_SIGN,
647 		.trust = X509_TRUST_EMAIL,
648 		.depth =  -1,
649 		.id = vpm_empty_id
650 	},
651 	{
652 		.name = "ssl_client",
653 		.purpose = X509_PURPOSE_SSL_CLIENT,
654 		.trust = X509_TRUST_SSL_CLIENT,
655 		.depth = -1,
656 		.id = vpm_empty_id
657 	},
658 	{
659 		.name = "ssl_server",
660 		.purpose = X509_PURPOSE_SSL_SERVER,
661 		.trust = X509_TRUST_SSL_SERVER,
662 		.depth = -1,
663 		.id = vpm_empty_id
664 	}
665 };
666 
667 static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL;
668 
669 static int
670 param_cmp(const X509_VERIFY_PARAM * const *a,
671     const X509_VERIFY_PARAM * const *b)
672 {
673 	return strcmp((*a)->name, (*b)->name);
674 }
675 
676 int
677 X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param)
678 {
679 	X509_VERIFY_PARAM *ptmp;
680 	if (!param_table) {
681 		param_table = sk_X509_VERIFY_PARAM_new(param_cmp);
682 		if (!param_table)
683 			return 0;
684 	} else {
685 		size_t idx;
686 
687 		if ((idx = sk_X509_VERIFY_PARAM_find(param_table, param))
688 		    != -1) {
689 			ptmp = sk_X509_VERIFY_PARAM_value(param_table,
690 			    idx);
691 			X509_VERIFY_PARAM_free(ptmp);
692 			(void)sk_X509_VERIFY_PARAM_delete(param_table,
693 			    idx);
694 		}
695 	}
696 	if (!sk_X509_VERIFY_PARAM_push(param_table, param))
697 		return 0;
698 	return 1;
699 }
700 LCRYPTO_ALIAS(X509_VERIFY_PARAM_add0_table);
701 
702 int
703 X509_VERIFY_PARAM_get_count(void)
704 {
705 	int num = sizeof(default_table) / sizeof(X509_VERIFY_PARAM);
706 	if (param_table)
707 		num += sk_X509_VERIFY_PARAM_num(param_table);
708 	return num;
709 }
710 LCRYPTO_ALIAS(X509_VERIFY_PARAM_get_count);
711 
712 const X509_VERIFY_PARAM *
713 X509_VERIFY_PARAM_get0(int id)
714 {
715 	int num = sizeof(default_table) / sizeof(X509_VERIFY_PARAM);
716 	if (id < num)
717 		return default_table + id;
718 	return sk_X509_VERIFY_PARAM_value(param_table, id - num);
719 }
720 LCRYPTO_ALIAS(X509_VERIFY_PARAM_get0);
721 
722 const X509_VERIFY_PARAM *
723 X509_VERIFY_PARAM_lookup(const char *name)
724 {
725 	X509_VERIFY_PARAM pm;
726 	unsigned int i, limit;
727 
728 	pm.name = (char *)name;
729 	if (param_table) {
730 		size_t idx;
731 		if ((idx = sk_X509_VERIFY_PARAM_find(param_table, &pm)) != -1)
732 			return sk_X509_VERIFY_PARAM_value(param_table, idx);
733 	}
734 
735 	limit = sizeof(default_table) / sizeof(X509_VERIFY_PARAM);
736 	for (i = 0; i < limit; i++) {
737 		if (strcmp(default_table[i].name, name) == 0) {
738 			return &default_table[i];
739 		}
740 	}
741 	return NULL;
742 }
743 LCRYPTO_ALIAS(X509_VERIFY_PARAM_lookup);
744 
745 void
746 X509_VERIFY_PARAM_table_cleanup(void)
747 {
748 	if (param_table)
749 		sk_X509_VERIFY_PARAM_pop_free(param_table,
750 		    X509_VERIFY_PARAM_free);
751 	param_table = NULL;
752 }
753 LCRYPTO_ALIAS(X509_VERIFY_PARAM_table_cleanup);
754