Home | History | Annotate | Download | only in x509
      1 /* Written by Dr Stephen N Henson (steve (at) openssl.org) for the OpenSSL
      2  * project 2004. */
      3 /* ====================================================================
      4  * Copyright (c) 2004 The OpenSSL Project.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  *
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *
     18  * 3. All advertising materials mentioning features or use of this
     19  *    software must display the following acknowledgment:
     20  *    "This product includes software developed by the OpenSSL Project
     21  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
     22  *
     23  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
     24  *    endorse or promote products derived from this software without
     25  *    prior written permission. For written permission, please contact
     26  *    licensing (at) OpenSSL.org.
     27  *
     28  * 5. Products derived from this software may not be called "OpenSSL"
     29  *    nor may "OpenSSL" appear in their names without prior written
     30  *    permission of the OpenSSL Project.
     31  *
     32  * 6. Redistributions of any form whatsoever must retain the following
     33  *    acknowledgment:
     34  *    "This product includes software developed by the OpenSSL Project
     35  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
     36  *
     37  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
     38  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     40  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
     41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     43  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     46  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     47  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     48  * OF THE POSSIBILITY OF SUCH DAMAGE.
     49  * ====================================================================
     50  *
     51  * This product includes cryptographic software written by Eric Young
     52  * (eay (at) cryptsoft.com).  This product includes software written by Tim
     53  * Hudson (tjh (at) cryptsoft.com). */
     54 
     55 #include <string.h>
     56 
     57 #include <openssl/buf.h>
     58 #include <openssl/lhash.h>
     59 #include <openssl/mem.h>
     60 #include <openssl/obj.h>
     61 #include <openssl/stack.h>
     62 #include <openssl/x509.h>
     63 #include <openssl/x509v3.h>
     64 
     65 #include "vpm_int.h"
     66 
     67 
     68 /* X509_VERIFY_PARAM functions */
     69 
     70 #define SET_HOST 0
     71 #define ADD_HOST 1
     72 
     73 static char *str_copy(char *s) { return OPENSSL_strdup(s); }
     74 static void str_free(char *s) { OPENSSL_free(s); }
     75 
     76 #define string_stack_free(sk) sk_OPENSSL_STRING_pop_free(sk, str_free)
     77 
     78 static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode,
     79 				    const char *name, size_t namelen)
     80 	{
     81 	char *copy;
     82 
     83 	/*
     84 	 * Refuse names with embedded NUL bytes.
     85 	 * XXX: Do we need to push an error onto the error stack?
     86 	 */
     87 	if (name && memchr(name, '\0', namelen))
     88 		 return 0;
     89 
     90 	if (mode == SET_HOST && id->hosts)
     91 		{
     92 		string_stack_free(id->hosts);
     93 		id->hosts = NULL;
     94 		}
     95 	if (name == NULL || namelen == 0)
     96 		return 1;
     97 
     98 	copy = BUF_strndup(name, namelen);
     99 	if (copy == NULL)
    100 		return 0;
    101 
    102 	if (id->hosts == NULL &&
    103 	    (id->hosts = sk_OPENSSL_STRING_new_null()) == NULL)
    104 		{
    105 		OPENSSL_free(copy);
    106 		return 0;
    107 		}
    108 
    109 	if (!sk_OPENSSL_STRING_push(id->hosts, copy))
    110 		{
    111 		OPENSSL_free(copy);
    112 		if (sk_OPENSSL_STRING_num(id->hosts) == 0)
    113 			{
    114 			sk_OPENSSL_STRING_free(id->hosts);
    115 			id->hosts = NULL;
    116 			}
    117 		return 0;
    118 		}
    119 
    120 	return 1;
    121 	}
    122 
    123 static void x509_verify_param_zero(X509_VERIFY_PARAM *param)
    124 	{
    125 	X509_VERIFY_PARAM_ID *paramid;
    126 	if (!param)
    127 		return;
    128 	param->name = NULL;
    129 	param->purpose = 0;
    130 	param->trust = 0;
    131 	/*param->inh_flags = X509_VP_FLAG_DEFAULT;*/
    132 	param->inh_flags = 0;
    133 	param->flags = 0;
    134 	param->depth = -1;
    135 	if (param->policies)
    136 		{
    137 		sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
    138 		param->policies = NULL;
    139 		}
    140 	paramid = param->id;
    141 	if (paramid->hosts)
    142 		{
    143 		string_stack_free(paramid->hosts);
    144 		paramid->hosts = NULL;
    145 		}
    146 	if (paramid->peername)
    147 		{
    148 		OPENSSL_free(paramid->peername);
    149 		paramid->peername = NULL;
    150 		}
    151 	if (paramid->email)
    152 		{
    153 		OPENSSL_free(paramid->email);
    154 		paramid->email = NULL;
    155 		paramid->emaillen = 0;
    156 		}
    157 	if (paramid->ip)
    158 		{
    159 		OPENSSL_free(paramid->ip);
    160 		paramid->ip = NULL;
    161 		paramid->iplen = 0;
    162 		}
    163 
    164 	}
    165 
    166 X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void)
    167 	{
    168 	X509_VERIFY_PARAM *param;
    169 	X509_VERIFY_PARAM_ID *paramid;
    170 	param = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM));
    171 	if (!param)
    172 		return NULL;
    173 	paramid = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM_ID));
    174 	if (!paramid)
    175 		{
    176 		OPENSSL_free(param);
    177 		return NULL;
    178 		}
    179 	memset(param, 0, sizeof(X509_VERIFY_PARAM));
    180 	memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID));
    181 	param->id = paramid;
    182 	x509_verify_param_zero(param);
    183 	return param;
    184 	}
    185 
    186 void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param)
    187 	{
    188 	if (param == NULL)
    189 		return;
    190 	x509_verify_param_zero(param);
    191 	OPENSSL_free(param->id);
    192 	OPENSSL_free(param);
    193 	}
    194 
    195 /* This function determines how parameters are "inherited" from one structure
    196  * to another. There are several different ways this can happen.
    197  *
    198  * 1. If a child structure needs to have its values initialized from a parent
    199  *    they are simply copied across. For example SSL_CTX copied to SSL.
    200  * 2. If the structure should take on values only if they are currently unset.
    201  *    For example the values in an SSL structure will take appropriate value
    202  *    for SSL servers or clients but only if the application has not set new
    203  *    ones.
    204  *
    205  * The "inh_flags" field determines how this function behaves.
    206  *
    207  * Normally any values which are set in the default are not copied from the
    208  * destination and verify flags are ORed together.
    209  *
    210  * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied
    211  * to the destination. Effectively the values in "to" become default values
    212  * which will be used only if nothing new is set in "from".
    213  *
    214  * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether
    215  * they are set or not. Flags is still Ored though.
    216  *
    217  * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead
    218  * of ORed.
    219  *
    220  * If X509_VP_FLAG_LOCKED is set then no values are copied.
    221  *
    222  * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed
    223  * after the next call.
    224  */
    225 
    226 /* Macro to test if a field should be copied from src to dest */
    227 
    228 #define test_x509_verify_param_copy(field, def) \
    229 	(to_overwrite || \
    230 		((src->field != def) && (to_default || (dest->field == def))))
    231 
    232 /* As above but for ID fields */
    233 
    234 #define test_x509_verify_param_copy_id(idf, def) \
    235 	test_x509_verify_param_copy(id->idf, def)
    236 
    237 /* Macro to test and copy a field if necessary */
    238 
    239 #define x509_verify_param_copy(field, def) \
    240 	if (test_x509_verify_param_copy(field, def)) \
    241 		dest->field = src->field
    242 
    243 
    244 int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
    245 						const X509_VERIFY_PARAM *src)
    246 	{
    247 	unsigned long inh_flags;
    248 	int to_default, to_overwrite;
    249 	X509_VERIFY_PARAM_ID *id;
    250 	if (!src)
    251 		return 1;
    252 	id = src->id;
    253 	inh_flags = dest->inh_flags | src->inh_flags;
    254 
    255 	if (inh_flags & X509_VP_FLAG_ONCE)
    256 		dest->inh_flags = 0;
    257 
    258 	if (inh_flags & X509_VP_FLAG_LOCKED)
    259 		return 1;
    260 
    261 	if (inh_flags & X509_VP_FLAG_DEFAULT)
    262 		to_default = 1;
    263 	else
    264 		to_default = 0;
    265 
    266 	if (inh_flags & X509_VP_FLAG_OVERWRITE)
    267 		to_overwrite = 1;
    268 	else
    269 		to_overwrite = 0;
    270 
    271 	x509_verify_param_copy(purpose, 0);
    272 	x509_verify_param_copy(trust, 0);
    273 	x509_verify_param_copy(depth, -1);
    274 
    275 	/* If overwrite or check time not set, copy across */
    276 
    277 	if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME))
    278 		{
    279 		dest->check_time = src->check_time;
    280 		dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME;
    281 		/* Don't need to copy flag: that is done below */
    282 		}
    283 
    284 	if (inh_flags & X509_VP_FLAG_RESET_FLAGS)
    285 		dest->flags = 0;
    286 
    287 	dest->flags |= src->flags;
    288 
    289 	if (test_x509_verify_param_copy(policies, NULL))
    290 		{
    291 		if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies))
    292 			return 0;
    293 		}
    294 
    295 	/* Copy the host flags if and only if we're copying the host list */
    296 	if (test_x509_verify_param_copy_id(hosts, NULL))
    297 		{
    298 		if (dest->id->hosts)
    299 			{
    300 			string_stack_free(dest->id->hosts);
    301 			dest->id->hosts = NULL;
    302 			}
    303 		if (id->hosts)
    304 			{
    305 			dest->id->hosts =
    306 			    sk_OPENSSL_STRING_deep_copy(id->hosts,
    307 							str_copy, str_free);
    308 			if (dest->id->hosts == NULL)
    309 				return 0;
    310 			dest->id->hostflags = id->hostflags;
    311 			}
    312 		}
    313 
    314 	if (test_x509_verify_param_copy_id(email, NULL))
    315 		{
    316 		if (!X509_VERIFY_PARAM_set1_email(dest, id->email, id->emaillen))
    317 			return 0;
    318 		}
    319 
    320 	if (test_x509_verify_param_copy_id(ip, NULL))
    321 		{
    322 		if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen))
    323 			return 0;
    324 		}
    325 
    326 	return 1;
    327 	}
    328 
    329 int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
    330 						const X509_VERIFY_PARAM *from)
    331 	{
    332 	unsigned long save_flags = to->inh_flags;
    333 	int ret;
    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 	}
    339 
    340 static int int_x509_param_set1(char **pdest, size_t *pdestlen,
    341 				const char *src, size_t srclen)
    342 	{
    343 	void *tmp;
    344 	if (src)
    345 		{
    346 		if (srclen == 0)
    347 			{
    348 			tmp = BUF_strdup(src);
    349 			srclen = strlen(src);
    350 			}
    351 		else
    352 			tmp = BUF_memdup(src, srclen);
    353 		if (!tmp)
    354 			return 0;
    355 		}
    356 	else
    357 		{
    358 		tmp = NULL;
    359 		srclen = 0;
    360 		}
    361 	if (*pdest)
    362 		OPENSSL_free(*pdest);
    363 	*pdest = tmp;
    364 	if (pdestlen)
    365 		*pdestlen = srclen;
    366 	return 1;
    367 	}
    368 
    369 int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name)
    370 	{
    371 	if (param->name)
    372 		OPENSSL_free(param->name);
    373 	param->name = BUF_strdup(name);
    374 	if (param->name)
    375 		return 1;
    376 	return 0;
    377 	}
    378 
    379 int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags)
    380 	{
    381 	param->flags |= flags;
    382 	if (flags & X509_V_FLAG_POLICY_MASK)
    383 		param->flags |= X509_V_FLAG_POLICY_CHECK;
    384 	return 1;
    385 	}
    386 
    387 int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags)
    388 	{
    389 	param->flags &= ~flags;
    390 	return 1;
    391 	}
    392 
    393 unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param)
    394 	{
    395 	return param->flags;
    396 	}
    397 
    398 int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose)
    399 	{
    400 	return X509_PURPOSE_set(&param->purpose, purpose);
    401 	}
    402 
    403 int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust)
    404 	{
    405 	return X509_TRUST_set(&param->trust, trust);
    406 	}
    407 
    408 void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth)
    409 	{
    410 	param->depth = depth;
    411 	}
    412 
    413 void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t)
    414 	{
    415 	param->check_time = t;
    416 	param->flags |= X509_V_FLAG_USE_CHECK_TIME;
    417 	}
    418 
    419 int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ASN1_OBJECT *policy)
    420 	{
    421 	if (!param->policies)
    422 		{
    423 		param->policies = sk_ASN1_OBJECT_new_null();
    424 		if (!param->policies)
    425 			return 0;
    426 		}
    427 	if (!sk_ASN1_OBJECT_push(param->policies, policy))
    428 		return 0;
    429 	return 1;
    430 	}
    431 
    432 int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
    433 					STACK_OF(ASN1_OBJECT) *policies)
    434 	{
    435 	size_t i;
    436 	ASN1_OBJECT *oid, *doid;
    437 	if (!param)
    438 		return 0;
    439 	if (param->policies)
    440 		sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
    441 
    442 	if (!policies)
    443 		{
    444 		param->policies = NULL;
    445 		return 1;
    446 		}
    447 
    448 	param->policies = sk_ASN1_OBJECT_new_null();
    449 	if (!param->policies)
    450 		return 0;
    451 
    452 	for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++)
    453 		{
    454 		oid = sk_ASN1_OBJECT_value(policies, i);
    455 		doid = OBJ_dup(oid);
    456 		if (!doid)
    457 			return 0;
    458 		if (!sk_ASN1_OBJECT_push(param->policies, doid))
    459 			{
    460 			ASN1_OBJECT_free(doid);
    461 			return 0;
    462 			}
    463 		}
    464 	param->flags |= X509_V_FLAG_POLICY_CHECK;
    465 	return 1;
    466 	}
    467 
    468 int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
    469 				const char *name, size_t namelen)
    470 	{
    471 	return int_x509_param_set_hosts(param->id, SET_HOST, name, namelen);
    472 	}
    473 
    474 int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
    475 				const char *name, size_t namelen)
    476 	{
    477 	return int_x509_param_set_hosts(param->id, ADD_HOST, name, namelen);
    478 	}
    479 
    480 void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
    481 					unsigned int flags)
    482 	{
    483 	param->id->hostflags = flags;
    484 	}
    485 
    486 char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param)
    487 	{
    488 	return param->id->peername;
    489 	}
    490 
    491 int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
    492 				const char *email, size_t emaillen)
    493 	{
    494 	return int_x509_param_set1(&param->id->email, &param->id->emaillen,
    495 					email, emaillen);
    496 	}
    497 
    498 int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
    499 					const unsigned char *ip, size_t iplen)
    500 	{
    501 	if (iplen != 0 && iplen != 4 && iplen != 16)
    502 		return 0;
    503 	return int_x509_param_set1((char **)&param->id->ip, &param->id->iplen,
    504 				   (char *)ip, iplen);
    505 	}
    506 
    507 int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
    508 	{
    509 	unsigned char ipout[16];
    510 	size_t iplen;
    511 
    512 	iplen = (size_t) a2i_ipadd(ipout, ipasc);
    513 	if (iplen == 0)
    514 		return 0;
    515 	return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen);
    516 	}
    517 
    518 int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
    519 	{
    520 	return param->depth;
    521 	}
    522 
    523 const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
    524 	{
    525 	return param->name;
    526 	}
    527 
    528 static const X509_VERIFY_PARAM_ID _empty_id = {NULL, 0U, NULL, NULL, 0, NULL, 0};
    529 
    530 #define vpm_empty_id (X509_VERIFY_PARAM_ID *)&_empty_id
    531 
    532 /* Default verify parameters: these are used for various
    533  * applications and can be overridden by the user specified table.
    534  * NB: the 'name' field *must* be in alphabetical order because it
    535  * will be searched using OBJ_search.
    536  */
    537 
    538 static const X509_VERIFY_PARAM default_table[] = {
    539 	{
    540 	(char *) "default",	/* X509 default parameters */
    541 	0,		/* Check time */
    542 	0,		/* internal flags */
    543 	0,		/* flags */
    544 	0,		/* purpose */
    545 	0,		/* trust */
    546 	100,		/* depth */
    547 	NULL,		/* policies */
    548 	vpm_empty_id
    549 	},
    550 	{
    551 	(char *) "pkcs7",			/* S/MIME sign parameters */
    552 	0,				/* Check time */
    553 	0,				/* internal flags */
    554 	0,				/* flags */
    555 	X509_PURPOSE_SMIME_SIGN,	/* purpose */
    556 	X509_TRUST_EMAIL,		/* trust */
    557 	-1,				/* depth */
    558 	NULL,				/* policies */
    559 	vpm_empty_id
    560 	},
    561 	{
    562 	(char *) "smime_sign",			/* S/MIME sign parameters */
    563 	0,				/* Check time */
    564 	0,				/* internal flags */
    565 	0,				/* flags */
    566 	X509_PURPOSE_SMIME_SIGN,	/* purpose */
    567 	X509_TRUST_EMAIL,		/* trust */
    568 	-1,				/* depth */
    569 	NULL,				/* policies */
    570 	vpm_empty_id
    571 	},
    572 	{
    573 	(char *) "ssl_client",			/* SSL/TLS client parameters */
    574 	0,				/* Check time */
    575 	0,				/* internal flags */
    576 	0,				/* flags */
    577 	X509_PURPOSE_SSL_CLIENT,	/* purpose */
    578 	X509_TRUST_SSL_CLIENT,		/* trust */
    579 	-1,				/* depth */
    580 	NULL,				/* policies */
    581 	vpm_empty_id
    582 	},
    583 	{
    584 	(char *) "ssl_server",			/* SSL/TLS server parameters */
    585 	0,				/* Check time */
    586 	0,				/* internal flags */
    587 	0,				/* flags */
    588 	X509_PURPOSE_SSL_SERVER,	/* purpose */
    589 	X509_TRUST_SSL_SERVER,		/* trust */
    590 	-1,				/* depth */
    591 	NULL,				/* policies */
    592 	vpm_empty_id
    593 	}};
    594 
    595 static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL;
    596 
    597 static int param_cmp(const X509_VERIFY_PARAM **a,
    598 			const X509_VERIFY_PARAM **b)
    599 	{
    600 	return strcmp((*a)->name, (*b)->name);
    601 	}
    602 
    603 int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param)
    604 	{
    605 	X509_VERIFY_PARAM *ptmp;
    606 	if (!param_table)
    607 		{
    608 		param_table = sk_X509_VERIFY_PARAM_new(param_cmp);
    609 		if (!param_table)
    610 			return 0;
    611 		}
    612 	else
    613 		{
    614 		size_t idx;
    615 
    616 		if (sk_X509_VERIFY_PARAM_find(param_table, &idx, param))
    617 			{
    618 			ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx);
    619 			X509_VERIFY_PARAM_free(ptmp);
    620 			(void)sk_X509_VERIFY_PARAM_delete(param_table, idx);
    621 			}
    622 		}
    623 	if (!sk_X509_VERIFY_PARAM_push(param_table, param))
    624 		return 0;
    625 	return 1;
    626 	}
    627 
    628 int X509_VERIFY_PARAM_get_count(void)
    629 	{
    630 	int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM);
    631 	if (param_table)
    632 		num += sk_X509_VERIFY_PARAM_num(param_table);
    633 	return num;
    634 	}
    635 
    636 const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id)
    637 	{
    638 	int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM);
    639 	if (id < num)
    640 		return default_table + id;
    641 	return sk_X509_VERIFY_PARAM_value(param_table, id - num);
    642 	}
    643 
    644 const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name)
    645 	{
    646 	X509_VERIFY_PARAM pm;
    647 	unsigned i, limit;
    648 
    649 	pm.name = (char *)name;
    650 	if (param_table)
    651 		{
    652 		size_t idx;
    653 		if (sk_X509_VERIFY_PARAM_find(param_table, &idx, &pm))
    654 			return sk_X509_VERIFY_PARAM_value(param_table, idx);
    655 		}
    656 
    657 	limit = sizeof(default_table)/sizeof(X509_VERIFY_PARAM);
    658 	for (i = 0; i < limit; i++) {
    659 		if (strcmp(default_table[i].name, name) == 0) {
    660 			return &default_table[i];
    661 		}
    662 	}
    663 	return NULL;
    664 	}
    665 
    666 void X509_VERIFY_PARAM_table_cleanup(void)
    667 	{
    668 	if (param_table)
    669 		sk_X509_VERIFY_PARAM_pop_free(param_table,
    670 						X509_VERIFY_PARAM_free);
    671 	param_table = NULL;
    672 	}
    673