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