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