xref: /openbsd/lib/libcrypto/x509/x509_verify.c (revision b77df7f7)
1*b77df7f7Stb /* $OpenBSD: x509_verify.c,v 1.15 2020/10/26 11:59:16 tb Exp $ */
223258cfeSbeck /*
323258cfeSbeck  * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
423258cfeSbeck  *
523258cfeSbeck  * Permission to use, copy, modify, and distribute this software for any
623258cfeSbeck  * purpose with or without fee is hereby granted, provided that the above
723258cfeSbeck  * copyright notice and this permission notice appear in all copies.
823258cfeSbeck  *
923258cfeSbeck  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1023258cfeSbeck  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1123258cfeSbeck  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1223258cfeSbeck  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1323258cfeSbeck  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1423258cfeSbeck  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1523258cfeSbeck  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1623258cfeSbeck  */
1723258cfeSbeck 
1823258cfeSbeck /* x509_verify - inspired by golang's crypto/x509/Verify */
1923258cfeSbeck 
2023258cfeSbeck #include <errno.h>
2123258cfeSbeck #include <stdio.h>
2223258cfeSbeck #include <string.h>
2323258cfeSbeck #include <time.h>
2423258cfeSbeck #include <unistd.h>
2523258cfeSbeck 
2623258cfeSbeck #include <openssl/safestack.h>
2723258cfeSbeck #include <openssl/x509.h>
2823258cfeSbeck #include <openssl/x509v3.h>
2923258cfeSbeck 
3023258cfeSbeck #include "x509_internal.h"
3123258cfeSbeck #include "x509_issuer_cache.h"
3223258cfeSbeck 
3323258cfeSbeck static int x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert,
3423258cfeSbeck     struct x509_verify_chain *current_chain);
3523258cfeSbeck static void x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
3623258cfeSbeck     struct x509_verify_chain *current_chain);
3723258cfeSbeck static int x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert,
3823258cfeSbeck     size_t depth, int error, int ok);
3923258cfeSbeck static void x509_verify_chain_free(struct x509_verify_chain *chain);
4023258cfeSbeck 
4123258cfeSbeck #define X509_VERIFY_CERT_HASH (EVP_sha512())
4223258cfeSbeck 
4323258cfeSbeck struct x509_verify_chain *
4423258cfeSbeck x509_verify_chain_new(void)
4523258cfeSbeck {
4623258cfeSbeck 	struct x509_verify_chain *chain;
4723258cfeSbeck 
4823258cfeSbeck 	if ((chain = calloc(1, sizeof(*chain))) == NULL)
4923258cfeSbeck 		goto err;
5023258cfeSbeck 	if ((chain->certs = sk_X509_new_null()) == NULL)
5123258cfeSbeck 		goto err;
5223258cfeSbeck 	if ((chain->names = x509_constraints_names_new()) == NULL)
5323258cfeSbeck 		goto err;
5423258cfeSbeck 
5523258cfeSbeck 	return chain;
5623258cfeSbeck  err:
5723258cfeSbeck 	x509_verify_chain_free(chain);
5823258cfeSbeck 	return NULL;
5923258cfeSbeck }
6023258cfeSbeck 
6123258cfeSbeck static void
6223258cfeSbeck x509_verify_chain_clear(struct x509_verify_chain *chain)
6323258cfeSbeck {
6423258cfeSbeck 	sk_X509_pop_free(chain->certs, X509_free);
6523258cfeSbeck 	chain->certs = NULL;
6623258cfeSbeck 	x509_constraints_names_free(chain->names);
6723258cfeSbeck 	chain->names = NULL;
6823258cfeSbeck }
6923258cfeSbeck 
7023258cfeSbeck static void
7123258cfeSbeck x509_verify_chain_free(struct x509_verify_chain *chain)
7223258cfeSbeck {
7323258cfeSbeck 	if (chain == NULL)
7423258cfeSbeck 		return;
7523258cfeSbeck 	x509_verify_chain_clear(chain);
7623258cfeSbeck 	free(chain);
7723258cfeSbeck }
7823258cfeSbeck 
7923258cfeSbeck static struct x509_verify_chain *
8023258cfeSbeck x509_verify_chain_dup(struct x509_verify_chain *chain)
8123258cfeSbeck {
8223258cfeSbeck 	struct x509_verify_chain *new_chain;
8323258cfeSbeck 
8423258cfeSbeck 	if ((new_chain = x509_verify_chain_new()) == NULL)
8523258cfeSbeck 		goto err;
8623258cfeSbeck 	if ((new_chain->certs = X509_chain_up_ref(chain->certs)) == NULL)
8723258cfeSbeck 		goto err;
8823258cfeSbeck 	if ((new_chain->names =
8923258cfeSbeck 	    x509_constraints_names_dup(chain->names)) == NULL)
9023258cfeSbeck 		goto err;
9123258cfeSbeck 	return(new_chain);
9223258cfeSbeck  err:
9323258cfeSbeck 	x509_verify_chain_free(new_chain);
9423258cfeSbeck 	return NULL;
9523258cfeSbeck }
9623258cfeSbeck 
9723258cfeSbeck static int
9823258cfeSbeck x509_verify_chain_append(struct x509_verify_chain *chain, X509 *cert,
9923258cfeSbeck     int *error)
10023258cfeSbeck {
10123258cfeSbeck 	int verify_err = X509_V_ERR_UNSPECIFIED;
10223258cfeSbeck 
10323258cfeSbeck 	if (!x509_constraints_extract_names(chain->names, cert,
10423258cfeSbeck 	    sk_X509_num(chain->certs) == 0, &verify_err)) {
10523258cfeSbeck 		*error = verify_err;
10623258cfeSbeck 		return 0;
10723258cfeSbeck 	}
10823258cfeSbeck 	X509_up_ref(cert);
10923258cfeSbeck 	if (!sk_X509_push(chain->certs, cert)) {
11023258cfeSbeck 		X509_free(cert);
1116b178030Sbeck 		*error = X509_V_ERR_OUT_OF_MEM;
11223258cfeSbeck 		return 0;
11323258cfeSbeck 	}
11423258cfeSbeck 	return 1;
11523258cfeSbeck }
11623258cfeSbeck 
11723258cfeSbeck static X509 *
11823258cfeSbeck x509_verify_chain_last(struct x509_verify_chain *chain)
11923258cfeSbeck {
12023258cfeSbeck 	int last;
12123258cfeSbeck 
12223258cfeSbeck 	if (chain->certs == NULL)
12323258cfeSbeck 		return NULL;
12423258cfeSbeck 	if ((last = sk_X509_num(chain->certs) - 1) < 0)
12523258cfeSbeck 		return NULL;
12623258cfeSbeck 	return sk_X509_value(chain->certs, last);
12723258cfeSbeck }
12823258cfeSbeck 
12923258cfeSbeck X509 *
13023258cfeSbeck x509_verify_chain_leaf(struct x509_verify_chain *chain)
13123258cfeSbeck {
13223258cfeSbeck 	if (chain->certs == NULL)
13323258cfeSbeck 		return NULL;
13423258cfeSbeck 	return sk_X509_value(chain->certs, 0);
13523258cfeSbeck }
13623258cfeSbeck 
13723258cfeSbeck static void
13823258cfeSbeck x509_verify_ctx_reset(struct x509_verify_ctx *ctx)
13923258cfeSbeck {
14023258cfeSbeck 	size_t i;
14123258cfeSbeck 
14223258cfeSbeck 	for (i = 0; i < ctx->chains_count; i++)
14323258cfeSbeck 		x509_verify_chain_free(ctx->chains[i]);
14423258cfeSbeck 	ctx->error = 0;
14523258cfeSbeck 	ctx->error_depth = 0;
14623258cfeSbeck 	ctx->chains_count = 0;
14723258cfeSbeck 	ctx->sig_checks = 0;
14823258cfeSbeck 	ctx->check_time = NULL;
14923258cfeSbeck }
15023258cfeSbeck 
15123258cfeSbeck static void
15223258cfeSbeck x509_verify_ctx_clear(struct x509_verify_ctx *ctx)
15323258cfeSbeck {
15423258cfeSbeck 	x509_verify_ctx_reset(ctx);
15523258cfeSbeck 	sk_X509_pop_free(ctx->intermediates, X509_free);
15623258cfeSbeck 	free(ctx->chains);
15723258cfeSbeck 	memset(ctx, 0, sizeof(*ctx));
15823258cfeSbeck }
15923258cfeSbeck 
16023258cfeSbeck static int
16123258cfeSbeck x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert)
16223258cfeSbeck {
16323258cfeSbeck 	int i;
16423258cfeSbeck 
16523258cfeSbeck 	for (i = 0; i < sk_X509_num(ctx->roots); i++) {
16623258cfeSbeck 		if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0)
16723258cfeSbeck 			return 1;
16823258cfeSbeck 	}
16923258cfeSbeck 	return 0;
17023258cfeSbeck }
17123258cfeSbeck 
172733666e3Sjsing static int
173733666e3Sjsing x509_verify_ctx_set_xsc_chain(struct x509_verify_ctx *ctx,
174733666e3Sjsing     struct x509_verify_chain *chain)
175733666e3Sjsing {
176733666e3Sjsing 	size_t depth;
177733666e3Sjsing 	X509 *last = x509_verify_chain_last(chain);
178733666e3Sjsing 
179733666e3Sjsing 	if (ctx->xsc == NULL)
180733666e3Sjsing 		return 1;
181733666e3Sjsing 
182733666e3Sjsing 	depth = sk_X509_num(chain->certs);
183733666e3Sjsing 	if (depth > 0)
184733666e3Sjsing 		depth--;
185733666e3Sjsing 
186733666e3Sjsing 	ctx->xsc->last_untrusted = depth ? depth - 1 : 0;
187733666e3Sjsing 	sk_X509_pop_free(ctx->xsc->chain, X509_free);
188733666e3Sjsing 	ctx->xsc->chain = X509_chain_up_ref(chain->certs);
189733666e3Sjsing 	if (ctx->xsc->chain == NULL)
190733666e3Sjsing 		return x509_verify_cert_error(ctx, last, depth,
191733666e3Sjsing 		    X509_V_ERR_OUT_OF_MEM, 0);
192733666e3Sjsing 	return 1;
193733666e3Sjsing }
194733666e3Sjsing 
19523258cfeSbeck /* Add a validated chain to our list of valid chains */
19623258cfeSbeck static int
19723258cfeSbeck x509_verify_ctx_add_chain(struct x509_verify_ctx *ctx,
19823258cfeSbeck     struct x509_verify_chain *chain)
19923258cfeSbeck {
20023258cfeSbeck 	size_t depth;
20123258cfeSbeck 	X509 *last = x509_verify_chain_last(chain);
20223258cfeSbeck 
20323258cfeSbeck 	depth = sk_X509_num(chain->certs);
20423258cfeSbeck 	if (depth > 0)
20523258cfeSbeck 		depth--;
20623258cfeSbeck 
20723258cfeSbeck 	if (ctx->chains_count >= ctx->max_chains)
20823258cfeSbeck 		return x509_verify_cert_error(ctx, last, depth,
20923258cfeSbeck 		    X509_V_ERR_CERT_CHAIN_TOO_LONG, 0);
21023258cfeSbeck 
21123258cfeSbeck 	/*
21223258cfeSbeck 	 * If we have a legacy xsc, choose a validated chain,
21323258cfeSbeck 	 * and apply the extensions, revocation, and policy checks
21423258cfeSbeck 	 * just like the legacy code did. We do this here instead
21523258cfeSbeck 	 * of as building the chains to more easily support the
21623258cfeSbeck 	 * callback and the bewildering array of VERIFY_PARAM
21723258cfeSbeck 	 * knobs that are there for the fiddling.
21823258cfeSbeck 	 */
21923258cfeSbeck 	if (ctx->xsc != NULL) {
220733666e3Sjsing 		if (!x509_verify_ctx_set_xsc_chain(ctx, chain))
221733666e3Sjsing 			return 0;
22223258cfeSbeck 
22323258cfeSbeck 		/*
22423258cfeSbeck 		 * XXX currently this duplicates some work done
22523258cfeSbeck 		 * in chain build, but we keep it here until
22623258cfeSbeck 		 * we have feature parity
22723258cfeSbeck 		 */
22823258cfeSbeck 		if (!x509_vfy_check_chain_extensions(ctx->xsc))
22923258cfeSbeck 			return 0;
23023258cfeSbeck 
23123258cfeSbeck 		if (!x509_constraints_chain(ctx->xsc->chain,
23223258cfeSbeck 		    &ctx->xsc->error, &ctx->xsc->error_depth)) {
23323258cfeSbeck 			X509 *cert = sk_X509_value(ctx->xsc->chain, depth);
23423258cfeSbeck 			if (!x509_verify_cert_error(ctx, cert,
23523258cfeSbeck 			    ctx->xsc->error_depth, ctx->xsc->error, 0))
23623258cfeSbeck 				return 0;
23723258cfeSbeck 		}
23823258cfeSbeck 
23923258cfeSbeck 		if (!x509_vfy_check_revocation(ctx->xsc))
24023258cfeSbeck 			return 0;
24123258cfeSbeck 
24223258cfeSbeck 		if (!x509_vfy_check_policy(ctx->xsc))
24323258cfeSbeck 			return 0;
24423258cfeSbeck 	}
24523258cfeSbeck 	/*
24623258cfeSbeck 	 * no xsc means we are being called from the non-legacy API,
24723258cfeSbeck 	 * extensions and purpose are dealt with as the chain is built.
24823258cfeSbeck 	 *
24923258cfeSbeck 	 * The non-legacy api returns multiple chains but does not do
25023258cfeSbeck 	 * any revocation checking (it must be done by the caller on
25123258cfeSbeck 	 * any chain they wish to use)
25223258cfeSbeck 	 */
25323258cfeSbeck 
25423258cfeSbeck 	if ((ctx->chains[ctx->chains_count] = x509_verify_chain_dup(chain)) ==
25523258cfeSbeck 	    NULL) {
25623258cfeSbeck 		return x509_verify_cert_error(ctx, last, depth,
25723258cfeSbeck 		    X509_V_ERR_OUT_OF_MEM, 0);
25823258cfeSbeck 	}
25923258cfeSbeck 	ctx->chains_count++;
26023258cfeSbeck 	ctx->error = X509_V_OK;
26123258cfeSbeck 	ctx->error_depth = depth;
26223258cfeSbeck 	return 1;
26323258cfeSbeck }
26423258cfeSbeck 
26523258cfeSbeck static int
26623258cfeSbeck x509_verify_potential_parent(struct x509_verify_ctx *ctx, X509 *parent,
26723258cfeSbeck     X509 *child)
26823258cfeSbeck {
26923258cfeSbeck 	if (ctx->xsc != NULL)
27023258cfeSbeck 		return (ctx->xsc->check_issued(ctx->xsc, child, parent));
27123258cfeSbeck 
27223258cfeSbeck 	/* XXX key usage */
27323258cfeSbeck 	return X509_check_issued(child, parent) != X509_V_OK;
27423258cfeSbeck }
27523258cfeSbeck 
27623258cfeSbeck static int
27723258cfeSbeck x509_verify_parent_signature(X509 *parent, X509 *child,
27823258cfeSbeck     unsigned char *child_md, int *error)
27923258cfeSbeck {
28023258cfeSbeck 	unsigned char parent_md[EVP_MAX_MD_SIZE] = { 0 };
28123258cfeSbeck 	EVP_PKEY *pkey;
28223258cfeSbeck 	int cached;
28323258cfeSbeck 	int ret = 0;
28423258cfeSbeck 
28523258cfeSbeck 	/* Use cached value if we have it */
28623258cfeSbeck 	if (child_md != NULL) {
28723258cfeSbeck 		if (!X509_digest(parent, X509_VERIFY_CERT_HASH, parent_md,
28823258cfeSbeck 		    NULL))
28923258cfeSbeck 			return 0;
29023258cfeSbeck 		if ((cached = x509_issuer_cache_find(parent_md, child_md)) >= 0)
29123258cfeSbeck 			return cached;
29223258cfeSbeck 	}
29323258cfeSbeck 
29423258cfeSbeck 	/* Check signature. Did parent sign child? */
29523258cfeSbeck 	if ((pkey = X509_get_pubkey(parent)) == NULL) {
29623258cfeSbeck 		*error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
29723258cfeSbeck 		return 0;
29823258cfeSbeck 	}
29923258cfeSbeck 	if (X509_verify(child, pkey) <= 0)
30023258cfeSbeck 		*error = X509_V_ERR_CERT_SIGNATURE_FAILURE;
30123258cfeSbeck 	else
30223258cfeSbeck 		ret = 1;
30323258cfeSbeck 
30423258cfeSbeck 	/* Add result to cache */
30523258cfeSbeck 	if (child_md != NULL)
30623258cfeSbeck 		x509_issuer_cache_add(parent_md, child_md, ret);
30723258cfeSbeck 
30823258cfeSbeck 	EVP_PKEY_free(pkey);
30923258cfeSbeck 
31023258cfeSbeck 	return ret;
31123258cfeSbeck }
31223258cfeSbeck 
31323258cfeSbeck static int
31423258cfeSbeck x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert,
31523258cfeSbeck     unsigned char *cert_md, int is_root_cert, X509 *candidate,
31623258cfeSbeck     struct x509_verify_chain *current_chain)
31723258cfeSbeck {
31823258cfeSbeck 	int depth = sk_X509_num(current_chain->certs);
31923258cfeSbeck 	struct x509_verify_chain *new_chain;
32023258cfeSbeck 	int i;
32123258cfeSbeck 
32223258cfeSbeck 	/* Fail if the certificate is already in the chain */
32323258cfeSbeck 	for (i = 0; i < sk_X509_num(current_chain->certs); i++) {
32423258cfeSbeck 		if (X509_cmp(sk_X509_value(current_chain->certs, i),
32523258cfeSbeck 		    candidate) == 0)
32623258cfeSbeck 			return 0;
32723258cfeSbeck 	}
32823258cfeSbeck 
32923258cfeSbeck 	if (ctx->sig_checks++ > X509_VERIFY_MAX_SIGCHECKS) {
33023258cfeSbeck 		/* don't allow callback to override safety check */
33123258cfeSbeck 		(void) x509_verify_cert_error(ctx, candidate, depth,
33223258cfeSbeck 		    X509_V_ERR_CERT_CHAIN_TOO_LONG, 0);
33323258cfeSbeck 		return 0;
33423258cfeSbeck 	}
33523258cfeSbeck 
33623258cfeSbeck 
33723258cfeSbeck 	if (!x509_verify_parent_signature(candidate, cert, cert_md,
33823258cfeSbeck 	    &ctx->error)) {
33923258cfeSbeck 		    if (!x509_verify_cert_error(ctx, candidate, depth,
34023258cfeSbeck 			ctx->error, 0))
34123258cfeSbeck 			    return 0;
34223258cfeSbeck 	}
34323258cfeSbeck 
34423258cfeSbeck 	if (!x509_verify_cert_valid(ctx, candidate, current_chain))
34523258cfeSbeck 		return 0;
34623258cfeSbeck 
34723258cfeSbeck 	/* candidate is good, add it to a copy of the current chain */
34823258cfeSbeck 	if ((new_chain = x509_verify_chain_dup(current_chain)) == NULL) {
34923258cfeSbeck 		x509_verify_cert_error(ctx, candidate, depth,
35023258cfeSbeck 		    X509_V_ERR_OUT_OF_MEM, 0);
35123258cfeSbeck 		return 0;
35223258cfeSbeck 	}
35323258cfeSbeck 	if (!x509_verify_chain_append(new_chain, candidate, &ctx->error)) {
35423258cfeSbeck 		x509_verify_cert_error(ctx, candidate, depth,
35523258cfeSbeck 		    ctx->error, 0);
35623258cfeSbeck 		x509_verify_chain_free(new_chain);
35723258cfeSbeck 		return 0;
35823258cfeSbeck 	}
35923258cfeSbeck 
36023258cfeSbeck 	/*
36123258cfeSbeck 	 * If candidate is a trusted root, we have a validated chain,
36223258cfeSbeck 	 * so we save it.  Otherwise, recurse until we find a root or
36323258cfeSbeck 	 * give up.
36423258cfeSbeck 	 */
365733666e3Sjsing 	if (is_root_cert) {
366733666e3Sjsing 		if (!x509_verify_ctx_set_xsc_chain(ctx, new_chain)) {
367733666e3Sjsing 			x509_verify_chain_free(new_chain);
368733666e3Sjsing 			return 0;
369733666e3Sjsing 		}
370733666e3Sjsing 		if (x509_verify_cert_error(ctx, candidate, depth, X509_V_OK, 1)) {
37123258cfeSbeck 			(void) x509_verify_ctx_add_chain(ctx, new_chain);
372733666e3Sjsing 			goto done;
373733666e3Sjsing 		}
374733666e3Sjsing 	}
375733666e3Sjsing 
37623258cfeSbeck 	x509_verify_build_chains(ctx, candidate, new_chain);
37723258cfeSbeck 
378733666e3Sjsing  done:
37923258cfeSbeck 	x509_verify_chain_free(new_chain);
38023258cfeSbeck 	return 1;
38123258cfeSbeck }
38223258cfeSbeck 
38323258cfeSbeck static int
38423258cfeSbeck x509_verify_cert_error(struct x509_verify_ctx *ctx, X509 *cert, size_t depth,
38523258cfeSbeck     int error, int ok)
38623258cfeSbeck {
38723258cfeSbeck 	ctx->error = error;
38823258cfeSbeck 	ctx->error_depth = depth;
38923258cfeSbeck 	if (ctx->xsc != NULL) {
39023258cfeSbeck 		ctx->xsc->error = error;
39123258cfeSbeck 		ctx->xsc->error_depth = depth;
39223258cfeSbeck 		ctx->xsc->current_cert = cert;
39323258cfeSbeck 		return ctx->xsc->verify_cb(ok, ctx->xsc);
39423258cfeSbeck 	}
39523258cfeSbeck 	return ok;
39623258cfeSbeck }
39723258cfeSbeck 
39823258cfeSbeck static void
39923258cfeSbeck x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
40023258cfeSbeck     struct x509_verify_chain *current_chain)
40123258cfeSbeck {
40223258cfeSbeck 	unsigned char cert_md[EVP_MAX_MD_SIZE] = { 0 };
40323258cfeSbeck 	X509 *candidate;
40423258cfeSbeck 	int i, depth, count;
40523258cfeSbeck 
40623258cfeSbeck 	depth = sk_X509_num(current_chain->certs);
40723258cfeSbeck 	if (depth > 0)
40823258cfeSbeck 		depth--;
40923258cfeSbeck 
41023258cfeSbeck 	if (depth >= ctx->max_depth &&
41123258cfeSbeck 	    !x509_verify_cert_error(ctx, cert, depth,
41223258cfeSbeck 		X509_V_ERR_CERT_CHAIN_TOO_LONG, 0))
41323258cfeSbeck 		return;
41423258cfeSbeck 
41523258cfeSbeck 	if (!X509_digest(cert, X509_VERIFY_CERT_HASH, cert_md, NULL) &&
41623258cfeSbeck 	    !x509_verify_cert_error(ctx, cert, depth,
41723258cfeSbeck 		X509_V_ERR_UNSPECIFIED, 0))
41823258cfeSbeck 		return;
41923258cfeSbeck 
42023258cfeSbeck 	count = ctx->chains_count;
42123258cfeSbeck 	ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
42223258cfeSbeck 	ctx->error_depth = depth;
42323258cfeSbeck 
42423258cfeSbeck 	for (i = 0; i < sk_X509_num(ctx->roots); i++) {
42523258cfeSbeck 		candidate = sk_X509_value(ctx->roots, i);
42623258cfeSbeck 		if (x509_verify_potential_parent(ctx, candidate, cert)) {
42723258cfeSbeck 			x509_verify_consider_candidate(ctx, cert,
42823258cfeSbeck 			    cert_md, 1, candidate, current_chain);
42923258cfeSbeck 		}
43023258cfeSbeck 	}
43123258cfeSbeck 
43223258cfeSbeck 	if (ctx->intermediates != NULL) {
43323258cfeSbeck 		for (i = 0; i < sk_X509_num(ctx->intermediates); i++) {
43423258cfeSbeck 			candidate = sk_X509_value(ctx->intermediates, i);
43523258cfeSbeck 			if (x509_verify_potential_parent(ctx, candidate, cert)) {
43623258cfeSbeck 				x509_verify_consider_candidate(ctx, cert,
43723258cfeSbeck 				    cert_md, 0, candidate, current_chain);
43823258cfeSbeck 			}
43923258cfeSbeck 		}
44023258cfeSbeck 	}
44123258cfeSbeck 	if (ctx->chains_count > count) {
44223258cfeSbeck 		if (ctx->xsc != NULL) {
44323258cfeSbeck 			ctx->xsc->error = X509_V_OK;
44423258cfeSbeck 			ctx->xsc->error_depth = depth;
44523258cfeSbeck 			ctx->xsc->current_cert = cert;
44623258cfeSbeck 			(void) ctx->xsc->verify_cb(1, ctx->xsc);
44723258cfeSbeck 		}
44823258cfeSbeck 	} else if (ctx->error_depth == depth) {
44923258cfeSbeck 			(void) x509_verify_cert_error(ctx, cert, depth,
45023258cfeSbeck 			    ctx->error, 0);
45123258cfeSbeck 	}
45223258cfeSbeck }
45323258cfeSbeck 
45423258cfeSbeck static int
45523258cfeSbeck x509_verify_cert_hostname(struct x509_verify_ctx *ctx, X509 *cert, char *name)
45623258cfeSbeck {
45723258cfeSbeck 	char *candidate;
45823258cfeSbeck 	size_t len;
45923258cfeSbeck 
46023258cfeSbeck 	if (name == NULL) {
461f31559c1Stb 		if (ctx->xsc != NULL) {
462f31559c1Stb 			int ret;
463f31559c1Stb 
464f31559c1Stb 			if ((ret = x509_vfy_check_id(ctx->xsc)) == 0)
465f31559c1Stb 				ctx->error = ctx->xsc->error;
466f31559c1Stb 			return ret;
467f31559c1Stb 		}
46823258cfeSbeck 		return 1;
46923258cfeSbeck 	}
47023258cfeSbeck 	if ((candidate = strdup(name)) == NULL) {
47123258cfeSbeck 		ctx->error = X509_V_ERR_OUT_OF_MEM;
47223258cfeSbeck 		goto err;
47323258cfeSbeck 	}
47423258cfeSbeck 	if ((len = strlen(candidate)) < 1) {
47523258cfeSbeck 		ctx->error = X509_V_ERR_UNSPECIFIED; /* XXX */
47623258cfeSbeck 		goto err;
47723258cfeSbeck 	}
47823258cfeSbeck 
47923258cfeSbeck 	/* IP addresses may be written in [ ]. */
48023258cfeSbeck 	if (candidate[0] == '[' && candidate[len - 1] == ']') {
48123258cfeSbeck 		candidate[len - 1] = '\0';
48223258cfeSbeck 		if (X509_check_ip_asc(cert, candidate + 1, 0) <= 0) {
48323258cfeSbeck 			ctx->error = X509_V_ERR_IP_ADDRESS_MISMATCH;
48423258cfeSbeck 			goto err;
48523258cfeSbeck 		}
48623258cfeSbeck 	} else {
48723258cfeSbeck 		int flags = 0;
48823258cfeSbeck 
48923258cfeSbeck 		if (ctx->xsc == NULL)
49023258cfeSbeck 			flags = X509_CHECK_FLAG_NEVER_CHECK_SUBJECT;
49123258cfeSbeck 
49223258cfeSbeck 		if (X509_check_host(cert, candidate, len, flags, NULL) <= 0) {
49323258cfeSbeck 			ctx->error = X509_V_ERR_HOSTNAME_MISMATCH;
49423258cfeSbeck 			goto err;
49523258cfeSbeck 		}
49623258cfeSbeck 	}
49723258cfeSbeck 	free(candidate);
49823258cfeSbeck 	return 1;
49923258cfeSbeck  err:
50023258cfeSbeck 	free(candidate);
50123258cfeSbeck 	return x509_verify_cert_error(ctx, cert, 0, ctx->error, 0);
50223258cfeSbeck }
50323258cfeSbeck 
50423258cfeSbeck static int
50523258cfeSbeck x509_verify_set_check_time(struct x509_verify_ctx *ctx) {
50623258cfeSbeck 	if (ctx->xsc != NULL)  {
50723258cfeSbeck 		if (ctx->xsc->param->flags & X509_V_FLAG_USE_CHECK_TIME) {
50823258cfeSbeck 			ctx->check_time = &ctx->xsc->param->check_time;
50923258cfeSbeck 			return 1;
51023258cfeSbeck 		}
51123258cfeSbeck 		if (ctx->xsc->param->flags & X509_V_FLAG_NO_CHECK_TIME)
51223258cfeSbeck 			return 0;
51323258cfeSbeck 	}
51423258cfeSbeck 
51523258cfeSbeck 	ctx->check_time = NULL;
51623258cfeSbeck 	return 1;
51723258cfeSbeck }
51823258cfeSbeck 
519e3c58b6dSbeck int
52023258cfeSbeck x509_verify_asn1_time_to_tm(const ASN1_TIME *atime, struct tm *tm, int notafter)
52123258cfeSbeck {
52223258cfeSbeck 	int type;
52323258cfeSbeck 
52423258cfeSbeck 	memset(tm, 0, sizeof(*tm));
52523258cfeSbeck 
52623258cfeSbeck 	type = ASN1_time_parse(atime->data, atime->length, tm, atime->type);
52723258cfeSbeck 	if (type == -1)
52823258cfeSbeck 		return 0;
52923258cfeSbeck 
53023258cfeSbeck 	/* RFC 5280 section 4.1.2.5 */
53123258cfeSbeck 	if (tm->tm_year < 150 && type != V_ASN1_UTCTIME)
53223258cfeSbeck 		return 0;
53323258cfeSbeck 	if (tm->tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME)
53423258cfeSbeck 		return 0;
53523258cfeSbeck 
53623258cfeSbeck 	if (notafter) {
53723258cfeSbeck 		/*
53823258cfeSbeck 		 * If we are a completely broken operating system with a
53923258cfeSbeck 		 * 32 bit time_t, and we have been told this is a notafter
54023258cfeSbeck 		 * date, limit the date to a 32 bit representable value.
54123258cfeSbeck 		 */
54223258cfeSbeck 		if (!ASN1_time_tm_clamp_notafter(tm))
54323258cfeSbeck 			return 0;
54423258cfeSbeck 	}
54523258cfeSbeck 
54623258cfeSbeck 	/*
54723258cfeSbeck 	 * Defensively fail if the time string is not representable as
54823258cfeSbeck 	 * a time_t. A time_t must be sane if you care about times after
54923258cfeSbeck 	 * Jan 19 2038.
55023258cfeSbeck 	 */
5517332621bSbeck 	if (timegm(tm) == -1)
55223258cfeSbeck 		return 0;
55323258cfeSbeck 
55423258cfeSbeck 	return 1;
55523258cfeSbeck }
55623258cfeSbeck 
55723258cfeSbeck static int
55823258cfeSbeck x509_verify_cert_time(int is_notafter, const ASN1_TIME *cert_asn1,
55923258cfeSbeck     time_t *cmp_time, int *error)
56023258cfeSbeck {
56123258cfeSbeck 	struct tm cert_tm, when_tm;
56223258cfeSbeck 	time_t when;
56323258cfeSbeck 
56423258cfeSbeck 	if (cmp_time == NULL)
56523258cfeSbeck 		when = time(NULL);
56623258cfeSbeck 	else
56723258cfeSbeck 		when = *cmp_time;
56823258cfeSbeck 
56923258cfeSbeck 	if (!x509_verify_asn1_time_to_tm(cert_asn1, &cert_tm,
57023258cfeSbeck 	    is_notafter)) {
57123258cfeSbeck 		*error = is_notafter ?
57223258cfeSbeck 		    X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD :
57323258cfeSbeck 		    X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
57423258cfeSbeck 		return 0;
57523258cfeSbeck 	}
57623258cfeSbeck 
57723258cfeSbeck 	if (gmtime_r(&when, &when_tm) == NULL) {
57823258cfeSbeck 		*error = X509_V_ERR_UNSPECIFIED;
57923258cfeSbeck 		return 0;
58023258cfeSbeck 	}
58123258cfeSbeck 
58223258cfeSbeck 	if (is_notafter) {
58323258cfeSbeck 		if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == -1) {
58423258cfeSbeck 			*error = X509_V_ERR_CERT_HAS_EXPIRED;
58523258cfeSbeck 			return 0;
58623258cfeSbeck 		}
58723258cfeSbeck 	} else  {
58823258cfeSbeck 		if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == 1) {
58923258cfeSbeck 			*error = X509_V_ERR_CERT_NOT_YET_VALID;
59023258cfeSbeck 			return 0;
59123258cfeSbeck 		}
59223258cfeSbeck 	}
59323258cfeSbeck 
59423258cfeSbeck 	return 1;
59523258cfeSbeck }
59623258cfeSbeck 
59723258cfeSbeck static int
59823258cfeSbeck x509_verify_validate_constraints(X509 *cert,
59923258cfeSbeck     struct x509_verify_chain *current_chain, int *error)
60023258cfeSbeck {
60123258cfeSbeck 	struct x509_constraints_names *excluded = NULL;
60223258cfeSbeck 	struct x509_constraints_names *permitted = NULL;
60323258cfeSbeck 	int err = X509_V_ERR_UNSPECIFIED;
60423258cfeSbeck 
60523258cfeSbeck 	if (current_chain == NULL)
60623258cfeSbeck 		return 1;
60723258cfeSbeck 
60823258cfeSbeck 	if (cert->nc != NULL) {
60923258cfeSbeck 		if ((permitted = x509_constraints_names_new()) == NULL) {
61023258cfeSbeck 			err = X509_V_ERR_OUT_OF_MEM;
61123258cfeSbeck 			goto err;
61223258cfeSbeck 		}
61323258cfeSbeck 		if ((excluded = x509_constraints_names_new()) == NULL) {
61423258cfeSbeck 			err = X509_V_ERR_OUT_OF_MEM;
61523258cfeSbeck 			goto err;
61623258cfeSbeck 		}
61723258cfeSbeck 		if (!x509_constraints_extract_constraints(cert,
61823258cfeSbeck 		    permitted, excluded, &err))
61923258cfeSbeck 			goto err;
62023258cfeSbeck 		if (!x509_constraints_check(current_chain->names,
62123258cfeSbeck 		    permitted, excluded, &err))
62223258cfeSbeck 			goto err;
62323258cfeSbeck 		x509_constraints_names_free(excluded);
62423258cfeSbeck 		x509_constraints_names_free(permitted);
62523258cfeSbeck 	}
62623258cfeSbeck 
62723258cfeSbeck 	return 1;
62823258cfeSbeck  err:
62923258cfeSbeck 	*error = err;
63023258cfeSbeck 	x509_constraints_names_free(excluded);
63123258cfeSbeck 	x509_constraints_names_free(permitted);
63223258cfeSbeck 	return 0;
63323258cfeSbeck }
63423258cfeSbeck 
63523258cfeSbeck static int
63623258cfeSbeck x509_verify_cert_extensions(struct x509_verify_ctx *ctx, X509 *cert, int need_ca)
63723258cfeSbeck {
63823258cfeSbeck 	if (!(cert->ex_flags & EXFLAG_SET)) {
63923258cfeSbeck 		CRYPTO_w_lock(CRYPTO_LOCK_X509);
64023258cfeSbeck 		x509v3_cache_extensions(cert);
64123258cfeSbeck 		CRYPTO_w_unlock(CRYPTO_LOCK_X509);
64223258cfeSbeck 	}
64323258cfeSbeck 
64423258cfeSbeck 	if (ctx->xsc != NULL)
64523258cfeSbeck 		return 1;	/* legacy is checked after chain is built */
64623258cfeSbeck 
64723258cfeSbeck 	if (cert->ex_flags & EXFLAG_CRITICAL) {
64823258cfeSbeck 		ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
64923258cfeSbeck 		return 0;
65023258cfeSbeck 	}
65123258cfeSbeck 	/* No we don't care about v1, netscape, and other ancient silliness */
65223258cfeSbeck 	if (need_ca && (!(cert->ex_flags & EXFLAG_BCONS) &&
65323258cfeSbeck 	    (cert->ex_flags & EXFLAG_CA))) {
65423258cfeSbeck 		ctx->error = X509_V_ERR_INVALID_CA;
65523258cfeSbeck 		return 0;
65623258cfeSbeck 	}
65723258cfeSbeck 	if (ctx->purpose > 0 && X509_check_purpose(cert, ctx->purpose, need_ca)) {
65823258cfeSbeck 		ctx->error = X509_V_ERR_INVALID_PURPOSE;
65923258cfeSbeck 		return 0;
66023258cfeSbeck 	}
66123258cfeSbeck 
66223258cfeSbeck 	/* XXX support proxy certs later in new api */
66323258cfeSbeck 	if (ctx->xsc == NULL && cert->ex_flags & EXFLAG_PROXY) {
66423258cfeSbeck 		ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
66523258cfeSbeck 		return 0;
66623258cfeSbeck 	}
66723258cfeSbeck 
66823258cfeSbeck 	return 1;
66923258cfeSbeck }
67023258cfeSbeck 
67123258cfeSbeck /* Validate that cert is a possible candidate to append to current_chain */
67223258cfeSbeck static int
67323258cfeSbeck x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert,
67423258cfeSbeck     struct x509_verify_chain *current_chain)
67523258cfeSbeck {
67623258cfeSbeck 	X509 *issuer_candidate;
67723258cfeSbeck 	int should_be_ca = current_chain != NULL;
67823258cfeSbeck 	size_t depth = 0;
67923258cfeSbeck 
680ec12bfceSbeck 	if (current_chain != NULL)
68123258cfeSbeck 		depth = sk_X509_num(current_chain->certs);
68223258cfeSbeck 
68323258cfeSbeck 	if (!x509_verify_cert_extensions(ctx, cert, should_be_ca))
68423258cfeSbeck 		return 0;
68523258cfeSbeck 
68623258cfeSbeck 	if (should_be_ca) {
68723258cfeSbeck 		issuer_candidate = x509_verify_chain_last(current_chain);
68823258cfeSbeck 		if (issuer_candidate != NULL &&
68923258cfeSbeck 		    !X509_check_issued(issuer_candidate, cert))
69023258cfeSbeck 			if (!x509_verify_cert_error(ctx, cert, depth,
69123258cfeSbeck 			    X509_V_ERR_SUBJECT_ISSUER_MISMATCH, 0))
69223258cfeSbeck 				return 0;
69323258cfeSbeck 	}
69423258cfeSbeck 
69523258cfeSbeck 	if (x509_verify_set_check_time(ctx)) {
69623258cfeSbeck 		if (!x509_verify_cert_time(0, X509_get_notBefore(cert),
69723258cfeSbeck 		    ctx->check_time, &ctx->error)) {
69823258cfeSbeck 			if (!x509_verify_cert_error(ctx, cert, depth,
69923258cfeSbeck 			    ctx->error, 0))
70023258cfeSbeck 				return 0;
70123258cfeSbeck 		}
70223258cfeSbeck 
70323258cfeSbeck 		if (!x509_verify_cert_time(1, X509_get_notAfter(cert),
70423258cfeSbeck 		    ctx->check_time, &ctx->error)) {
70523258cfeSbeck 			if (!x509_verify_cert_error(ctx, cert, depth,
70623258cfeSbeck 			    ctx->error, 0))
70723258cfeSbeck 				return 0;
70823258cfeSbeck 		}
70923258cfeSbeck 	}
71023258cfeSbeck 
71123258cfeSbeck 	if (!x509_verify_validate_constraints(cert, current_chain,
71223258cfeSbeck 	    &ctx->error) && !x509_verify_cert_error(ctx, cert, depth,
71323258cfeSbeck 	    ctx->error, 0))
71423258cfeSbeck 		return 0;
71523258cfeSbeck 
71623258cfeSbeck 	return 1;
71723258cfeSbeck }
71823258cfeSbeck 
71923258cfeSbeck struct x509_verify_ctx *
72023258cfeSbeck x509_verify_ctx_new_from_xsc(X509_STORE_CTX *xsc, STACK_OF(X509) *roots)
72123258cfeSbeck {
72223258cfeSbeck 	struct x509_verify_ctx *ctx;
7232c940cf3Sjsing 	size_t max_depth;
72423258cfeSbeck 
72523258cfeSbeck 	if (xsc == NULL)
72623258cfeSbeck 		return NULL;
72723258cfeSbeck 
7282c940cf3Sjsing 	if ((ctx = x509_verify_ctx_new(roots)) == NULL)
72923258cfeSbeck 		return NULL;
73023258cfeSbeck 
73123258cfeSbeck 	ctx->xsc = xsc;
73223258cfeSbeck 
73323258cfeSbeck 	if (xsc->untrusted &&
73423258cfeSbeck 	    (ctx->intermediates = X509_chain_up_ref(xsc->untrusted)) == NULL)
73523258cfeSbeck 		goto err;
73623258cfeSbeck 
7372c940cf3Sjsing 	max_depth = X509_VERIFY_MAX_CHAIN_CERTS;
7382c940cf3Sjsing 	if (xsc->param->depth > 0 && xsc->param->depth < X509_VERIFY_MAX_CHAIN_CERTS)
7392c940cf3Sjsing 		max_depth = xsc->param->depth;
7402c940cf3Sjsing 	if (!x509_verify_ctx_set_max_depth(ctx, max_depth))
74123258cfeSbeck 		goto err;
74223258cfeSbeck 
74323258cfeSbeck 	return ctx;
74423258cfeSbeck  err:
74523258cfeSbeck 	x509_verify_ctx_free(ctx);
74623258cfeSbeck 	return NULL;
74723258cfeSbeck }
74823258cfeSbeck 
74923258cfeSbeck /* Public API */
75023258cfeSbeck 
75123258cfeSbeck struct x509_verify_ctx *
75223258cfeSbeck x509_verify_ctx_new(STACK_OF(X509) *roots)
75323258cfeSbeck {
75423258cfeSbeck 	struct x509_verify_ctx *ctx;
75523258cfeSbeck 
75623258cfeSbeck 	if (roots == NULL)
75723258cfeSbeck 		return NULL;
75823258cfeSbeck 
75923258cfeSbeck 	if ((ctx = calloc(1, sizeof(struct x509_verify_ctx))) == NULL)
76023258cfeSbeck 		return NULL;
76123258cfeSbeck 
76223258cfeSbeck 	if ((ctx->roots = X509_chain_up_ref(roots)) == NULL)
76323258cfeSbeck 		goto err;
76423258cfeSbeck 
76523258cfeSbeck 	ctx->max_depth = X509_VERIFY_MAX_CHAIN_CERTS;
76623258cfeSbeck 	ctx->max_chains = X509_VERIFY_MAX_CHAINS;
76723258cfeSbeck 	ctx->max_sigs = X509_VERIFY_MAX_SIGCHECKS;
76823258cfeSbeck 
76923258cfeSbeck 	if ((ctx->chains = calloc(X509_VERIFY_MAX_CHAINS,
77023258cfeSbeck 	    sizeof(*ctx->chains))) == NULL)
77123258cfeSbeck 		goto err;
77223258cfeSbeck 
77323258cfeSbeck 	return ctx;
77423258cfeSbeck  err:
77523258cfeSbeck 	x509_verify_ctx_free(ctx);
77623258cfeSbeck 	return NULL;
77723258cfeSbeck }
77823258cfeSbeck 
77923258cfeSbeck void
78023258cfeSbeck x509_verify_ctx_free(struct x509_verify_ctx *ctx)
78123258cfeSbeck {
78223258cfeSbeck 	if (ctx == NULL)
78323258cfeSbeck 		return;
78423258cfeSbeck 	sk_X509_pop_free(ctx->roots, X509_free);
78523258cfeSbeck 	x509_verify_ctx_clear(ctx);
78623258cfeSbeck 	free(ctx);
78723258cfeSbeck }
78823258cfeSbeck 
78923258cfeSbeck int
79023258cfeSbeck x509_verify_ctx_set_max_depth(struct x509_verify_ctx *ctx, size_t max)
79123258cfeSbeck {
79223258cfeSbeck 	if (max < 1 || max > X509_VERIFY_MAX_CHAIN_CERTS)
79323258cfeSbeck 		return 0;
79423258cfeSbeck 	ctx->max_depth = max;
79523258cfeSbeck 	return 1;
79623258cfeSbeck }
79723258cfeSbeck 
79823258cfeSbeck int
79923258cfeSbeck x509_verify_ctx_set_max_chains(struct x509_verify_ctx *ctx, size_t max)
80023258cfeSbeck {
80123258cfeSbeck 	if (max < 1 || max > X509_VERIFY_MAX_CHAINS)
80223258cfeSbeck 		return 0;
80323258cfeSbeck 	ctx->max_chains = max;
80423258cfeSbeck 	return 1;
80523258cfeSbeck }
80623258cfeSbeck 
80723258cfeSbeck int
80823258cfeSbeck x509_verify_ctx_set_max_signatures(struct x509_verify_ctx *ctx, size_t max)
80923258cfeSbeck {
8109f2be83cSjsing 	if (max < 1 || max > 100000)
81123258cfeSbeck 		return 0;
81223258cfeSbeck 	ctx->max_sigs = max;
81323258cfeSbeck 	return 1;
81423258cfeSbeck }
81523258cfeSbeck 
81623258cfeSbeck int
81723258cfeSbeck x509_verify_ctx_set_purpose(struct x509_verify_ctx *ctx, int purpose)
81823258cfeSbeck {
81923258cfeSbeck 	if (purpose < X509_PURPOSE_MIN || purpose > X509_PURPOSE_MAX)
82023258cfeSbeck 		return 0;
82123258cfeSbeck 	ctx->purpose = purpose;
82223258cfeSbeck 	return 1;
82323258cfeSbeck }
82423258cfeSbeck 
82523258cfeSbeck int
82623258cfeSbeck x509_verify_ctx_set_intermediates(struct x509_verify_ctx *ctx,
82723258cfeSbeck     STACK_OF(X509) *intermediates)
82823258cfeSbeck {
82923258cfeSbeck 	if ((ctx->intermediates = X509_chain_up_ref(intermediates)) == NULL)
83023258cfeSbeck 		return 0;
83123258cfeSbeck 	return 1;
83223258cfeSbeck }
83323258cfeSbeck 
83423258cfeSbeck const char *
83523258cfeSbeck x509_verify_ctx_error_string(struct x509_verify_ctx *ctx)
83623258cfeSbeck {
83723258cfeSbeck 	return X509_verify_cert_error_string(ctx->error);
83823258cfeSbeck }
83923258cfeSbeck 
84023258cfeSbeck size_t
84123258cfeSbeck x509_verify_ctx_error_depth(struct x509_verify_ctx *ctx)
84223258cfeSbeck {
84323258cfeSbeck 	return ctx->error_depth;
84423258cfeSbeck }
84523258cfeSbeck 
84623258cfeSbeck STACK_OF(X509) *
84723258cfeSbeck x509_verify_ctx_chain(struct x509_verify_ctx *ctx, size_t i)
84823258cfeSbeck {
84923258cfeSbeck 	if (i >= ctx->chains_count)
85023258cfeSbeck 		return NULL;
85123258cfeSbeck 	return ctx->chains[i]->certs;
85223258cfeSbeck }
85323258cfeSbeck 
85423258cfeSbeck size_t
85523258cfeSbeck x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name)
85623258cfeSbeck {
85723258cfeSbeck 	struct x509_verify_chain *current_chain;
85823258cfeSbeck 
859e4db083fSbeck 	if (ctx->roots == NULL || ctx->max_depth == 0) {
86023258cfeSbeck 		ctx->error = X509_V_ERR_INVALID_CALL;
861*b77df7f7Stb 		goto err;
86223258cfeSbeck 	}
86323258cfeSbeck 
86423258cfeSbeck 	if (ctx->xsc != NULL) {
86523258cfeSbeck 		if (leaf != NULL || name != NULL) {
86623258cfeSbeck 			ctx->error = X509_V_ERR_INVALID_CALL;
867*b77df7f7Stb 			goto err;
86823258cfeSbeck 		}
86923258cfeSbeck 		leaf = ctx->xsc->cert;
87023258cfeSbeck 
87123258cfeSbeck 		/*
87223258cfeSbeck 		 * XXX
87323258cfeSbeck 		 * The legacy code expects the top level cert to be
87423258cfeSbeck 		 * there, even if we didn't find a chain. So put it
87523258cfeSbeck 		 * there, we will clobber it later if we find a valid
87623258cfeSbeck 		 * chain.
87723258cfeSbeck 		 */
87823258cfeSbeck 		if ((ctx->xsc->chain = sk_X509_new_null()) == NULL) {
87923258cfeSbeck 			ctx->error = X509_V_ERR_OUT_OF_MEM;
880*b77df7f7Stb 			goto err;
88123258cfeSbeck 		}
88223258cfeSbeck 		if (!X509_up_ref(leaf)) {
88323258cfeSbeck 			ctx->error = X509_V_ERR_OUT_OF_MEM;
884*b77df7f7Stb 			goto err;
88523258cfeSbeck 		}
88623258cfeSbeck 		if (!sk_X509_push(ctx->xsc->chain, leaf)) {
88723258cfeSbeck 			X509_free(leaf);
88823258cfeSbeck 			ctx->error = X509_V_ERR_OUT_OF_MEM;
889*b77df7f7Stb 			goto err;
89023258cfeSbeck 		}
891d59cc15fSbeck 		ctx->xsc->error_depth = 0;
892d59cc15fSbeck 		ctx->xsc->current_cert = leaf;
89323258cfeSbeck 	}
89423258cfeSbeck 
89534417d0dSjsing 	if (!x509_verify_cert_valid(ctx, leaf, NULL))
896*b77df7f7Stb 		goto err;
89734417d0dSjsing 
89834417d0dSjsing 	if (!x509_verify_cert_hostname(ctx, leaf, name))
899*b77df7f7Stb 		goto err;
90034417d0dSjsing 
90123258cfeSbeck 	if ((current_chain = x509_verify_chain_new()) == NULL) {
90223258cfeSbeck 		ctx->error = X509_V_ERR_OUT_OF_MEM;
903*b77df7f7Stb 		goto err;
90423258cfeSbeck 	}
90523258cfeSbeck 	if (!x509_verify_chain_append(current_chain, leaf, &ctx->error)) {
90623258cfeSbeck 		x509_verify_chain_free(current_chain);
907*b77df7f7Stb 		goto err;
90823258cfeSbeck 	}
90923258cfeSbeck 	if (x509_verify_ctx_cert_is_root(ctx, leaf))
91023258cfeSbeck 		x509_verify_ctx_add_chain(ctx, current_chain);
91123258cfeSbeck 	else
91223258cfeSbeck 		x509_verify_build_chains(ctx, leaf, current_chain);
91323258cfeSbeck 
91423258cfeSbeck 	x509_verify_chain_free(current_chain);
91523258cfeSbeck 
91623258cfeSbeck 	/*
91723258cfeSbeck 	 * Safety net:
91823258cfeSbeck 	 * We could not find a validated chain, and for some reason do not
91923258cfeSbeck 	 * have an error set.
92023258cfeSbeck 	 */
92123258cfeSbeck 	if (ctx->chains_count == 0 && ctx->error == 0)
92223258cfeSbeck 		ctx->error = X509_V_ERR_UNSPECIFIED;
92323258cfeSbeck 
92423258cfeSbeck 	/* Clear whatever errors happened if we have any validated chain */
92523258cfeSbeck 	if (ctx->chains_count > 0)
92623258cfeSbeck 		ctx->error = X509_V_OK;
92723258cfeSbeck 
92823258cfeSbeck 	if (ctx->xsc != NULL) {
92923258cfeSbeck 		ctx->xsc->error = ctx->error;
93023258cfeSbeck 		return ctx->xsc->verify_cb(ctx->chains_count, ctx->xsc);
93123258cfeSbeck 	}
93223258cfeSbeck 	return (ctx->chains_count);
933*b77df7f7Stb 
934*b77df7f7Stb  err:
935*b77df7f7Stb 	if (ctx->xsc != NULL)
936*b77df7f7Stb 		ctx->xsc->error = ctx->error;
937*b77df7f7Stb 	return 0;
93823258cfeSbeck }
939