1*733666e3Sjsing /* $OpenBSD: x509_verify.c,v 1.12 2020/09/23 18:20:16 jsing 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 172*733666e3Sjsing static int 173*733666e3Sjsing x509_verify_ctx_set_xsc_chain(struct x509_verify_ctx *ctx, 174*733666e3Sjsing struct x509_verify_chain *chain) 175*733666e3Sjsing { 176*733666e3Sjsing size_t depth; 177*733666e3Sjsing X509 *last = x509_verify_chain_last(chain); 178*733666e3Sjsing 179*733666e3Sjsing if (ctx->xsc == NULL) 180*733666e3Sjsing return 1; 181*733666e3Sjsing 182*733666e3Sjsing depth = sk_X509_num(chain->certs); 183*733666e3Sjsing if (depth > 0) 184*733666e3Sjsing depth--; 185*733666e3Sjsing 186*733666e3Sjsing ctx->xsc->last_untrusted = depth ? depth - 1 : 0; 187*733666e3Sjsing sk_X509_pop_free(ctx->xsc->chain, X509_free); 188*733666e3Sjsing ctx->xsc->chain = X509_chain_up_ref(chain->certs); 189*733666e3Sjsing if (ctx->xsc->chain == NULL) 190*733666e3Sjsing return x509_verify_cert_error(ctx, last, depth, 191*733666e3Sjsing X509_V_ERR_OUT_OF_MEM, 0); 192*733666e3Sjsing return 1; 193*733666e3Sjsing } 194*733666e3Sjsing 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) { 220*733666e3Sjsing if (!x509_verify_ctx_set_xsc_chain(ctx, chain)) 221*733666e3Sjsing 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 */ 365*733666e3Sjsing if (is_root_cert) { 366*733666e3Sjsing if (!x509_verify_ctx_set_xsc_chain(ctx, new_chain)) { 367*733666e3Sjsing x509_verify_chain_free(new_chain); 368*733666e3Sjsing return 0; 369*733666e3Sjsing } 370*733666e3Sjsing if (x509_verify_cert_error(ctx, candidate, depth, X509_V_OK, 1)) { 37123258cfeSbeck (void) x509_verify_ctx_add_chain(ctx, new_chain); 372*733666e3Sjsing goto done; 373*733666e3Sjsing } 374*733666e3Sjsing } 375*733666e3Sjsing 37623258cfeSbeck x509_verify_build_chains(ctx, candidate, new_chain); 37723258cfeSbeck 378*733666e3Sjsing 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) { 46123258cfeSbeck if (ctx->xsc != NULL) 46223258cfeSbeck return x509_vfy_check_id(ctx->xsc); 46323258cfeSbeck return 1; 46423258cfeSbeck } 46523258cfeSbeck if ((candidate = strdup(name)) == NULL) { 46623258cfeSbeck ctx->error = X509_V_ERR_OUT_OF_MEM; 46723258cfeSbeck goto err; 46823258cfeSbeck } 46923258cfeSbeck if ((len = strlen(candidate)) < 1) { 47023258cfeSbeck ctx->error = X509_V_ERR_UNSPECIFIED; /* XXX */ 47123258cfeSbeck goto err; 47223258cfeSbeck } 47323258cfeSbeck 47423258cfeSbeck /* IP addresses may be written in [ ]. */ 47523258cfeSbeck if (candidate[0] == '[' && candidate[len - 1] == ']') { 47623258cfeSbeck candidate[len - 1] = '\0'; 47723258cfeSbeck if (X509_check_ip_asc(cert, candidate + 1, 0) <= 0) { 47823258cfeSbeck ctx->error = X509_V_ERR_IP_ADDRESS_MISMATCH; 47923258cfeSbeck goto err; 48023258cfeSbeck } 48123258cfeSbeck } else { 48223258cfeSbeck int flags = 0; 48323258cfeSbeck 48423258cfeSbeck if (ctx->xsc == NULL) 48523258cfeSbeck flags = X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; 48623258cfeSbeck 48723258cfeSbeck if (X509_check_host(cert, candidate, len, flags, NULL) <= 0) { 48823258cfeSbeck ctx->error = X509_V_ERR_HOSTNAME_MISMATCH; 48923258cfeSbeck goto err; 49023258cfeSbeck } 49123258cfeSbeck } 49223258cfeSbeck free(candidate); 49323258cfeSbeck return 1; 49423258cfeSbeck err: 49523258cfeSbeck free(candidate); 49623258cfeSbeck return x509_verify_cert_error(ctx, cert, 0, ctx->error, 0); 49723258cfeSbeck } 49823258cfeSbeck 49923258cfeSbeck static int 50023258cfeSbeck x509_verify_set_check_time(struct x509_verify_ctx *ctx) { 50123258cfeSbeck if (ctx->xsc != NULL) { 50223258cfeSbeck if (ctx->xsc->param->flags & X509_V_FLAG_USE_CHECK_TIME) { 50323258cfeSbeck ctx->check_time = &ctx->xsc->param->check_time; 50423258cfeSbeck return 1; 50523258cfeSbeck } 50623258cfeSbeck if (ctx->xsc->param->flags & X509_V_FLAG_NO_CHECK_TIME) 50723258cfeSbeck return 0; 50823258cfeSbeck } 50923258cfeSbeck 51023258cfeSbeck ctx->check_time = NULL; 51123258cfeSbeck return 1; 51223258cfeSbeck } 51323258cfeSbeck 514e3c58b6dSbeck int 51523258cfeSbeck x509_verify_asn1_time_to_tm(const ASN1_TIME *atime, struct tm *tm, int notafter) 51623258cfeSbeck { 51723258cfeSbeck int type; 51823258cfeSbeck 51923258cfeSbeck memset(tm, 0, sizeof(*tm)); 52023258cfeSbeck 52123258cfeSbeck type = ASN1_time_parse(atime->data, atime->length, tm, atime->type); 52223258cfeSbeck if (type == -1) 52323258cfeSbeck return 0; 52423258cfeSbeck 52523258cfeSbeck /* RFC 5280 section 4.1.2.5 */ 52623258cfeSbeck if (tm->tm_year < 150 && type != V_ASN1_UTCTIME) 52723258cfeSbeck return 0; 52823258cfeSbeck if (tm->tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME) 52923258cfeSbeck return 0; 53023258cfeSbeck 53123258cfeSbeck if (notafter) { 53223258cfeSbeck /* 53323258cfeSbeck * If we are a completely broken operating system with a 53423258cfeSbeck * 32 bit time_t, and we have been told this is a notafter 53523258cfeSbeck * date, limit the date to a 32 bit representable value. 53623258cfeSbeck */ 53723258cfeSbeck if (!ASN1_time_tm_clamp_notafter(tm)) 53823258cfeSbeck return 0; 53923258cfeSbeck } 54023258cfeSbeck 54123258cfeSbeck /* 54223258cfeSbeck * Defensively fail if the time string is not representable as 54323258cfeSbeck * a time_t. A time_t must be sane if you care about times after 54423258cfeSbeck * Jan 19 2038. 54523258cfeSbeck */ 5467332621bSbeck if (timegm(tm) == -1) 54723258cfeSbeck return 0; 54823258cfeSbeck 54923258cfeSbeck return 1; 55023258cfeSbeck } 55123258cfeSbeck 55223258cfeSbeck static int 55323258cfeSbeck x509_verify_cert_time(int is_notafter, const ASN1_TIME *cert_asn1, 55423258cfeSbeck time_t *cmp_time, int *error) 55523258cfeSbeck { 55623258cfeSbeck struct tm cert_tm, when_tm; 55723258cfeSbeck time_t when; 55823258cfeSbeck 55923258cfeSbeck if (cmp_time == NULL) 56023258cfeSbeck when = time(NULL); 56123258cfeSbeck else 56223258cfeSbeck when = *cmp_time; 56323258cfeSbeck 56423258cfeSbeck if (!x509_verify_asn1_time_to_tm(cert_asn1, &cert_tm, 56523258cfeSbeck is_notafter)) { 56623258cfeSbeck *error = is_notafter ? 56723258cfeSbeck X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD : 56823258cfeSbeck X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; 56923258cfeSbeck return 0; 57023258cfeSbeck } 57123258cfeSbeck 57223258cfeSbeck if (gmtime_r(&when, &when_tm) == NULL) { 57323258cfeSbeck *error = X509_V_ERR_UNSPECIFIED; 57423258cfeSbeck return 0; 57523258cfeSbeck } 57623258cfeSbeck 57723258cfeSbeck if (is_notafter) { 57823258cfeSbeck if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == -1) { 57923258cfeSbeck *error = X509_V_ERR_CERT_HAS_EXPIRED; 58023258cfeSbeck return 0; 58123258cfeSbeck } 58223258cfeSbeck } else { 58323258cfeSbeck if (ASN1_time_tm_cmp(&cert_tm, &when_tm) == 1) { 58423258cfeSbeck *error = X509_V_ERR_CERT_NOT_YET_VALID; 58523258cfeSbeck return 0; 58623258cfeSbeck } 58723258cfeSbeck } 58823258cfeSbeck 58923258cfeSbeck return 1; 59023258cfeSbeck } 59123258cfeSbeck 59223258cfeSbeck static int 59323258cfeSbeck x509_verify_validate_constraints(X509 *cert, 59423258cfeSbeck struct x509_verify_chain *current_chain, int *error) 59523258cfeSbeck { 59623258cfeSbeck struct x509_constraints_names *excluded = NULL; 59723258cfeSbeck struct x509_constraints_names *permitted = NULL; 59823258cfeSbeck int err = X509_V_ERR_UNSPECIFIED; 59923258cfeSbeck 60023258cfeSbeck if (current_chain == NULL) 60123258cfeSbeck return 1; 60223258cfeSbeck 60323258cfeSbeck if (cert->nc != NULL) { 60423258cfeSbeck if ((permitted = x509_constraints_names_new()) == NULL) { 60523258cfeSbeck err = X509_V_ERR_OUT_OF_MEM; 60623258cfeSbeck goto err; 60723258cfeSbeck } 60823258cfeSbeck if ((excluded = x509_constraints_names_new()) == NULL) { 60923258cfeSbeck err = X509_V_ERR_OUT_OF_MEM; 61023258cfeSbeck goto err; 61123258cfeSbeck } 61223258cfeSbeck if (!x509_constraints_extract_constraints(cert, 61323258cfeSbeck permitted, excluded, &err)) 61423258cfeSbeck goto err; 61523258cfeSbeck if (!x509_constraints_check(current_chain->names, 61623258cfeSbeck permitted, excluded, &err)) 61723258cfeSbeck goto err; 61823258cfeSbeck x509_constraints_names_free(excluded); 61923258cfeSbeck x509_constraints_names_free(permitted); 62023258cfeSbeck } 62123258cfeSbeck 62223258cfeSbeck return 1; 62323258cfeSbeck err: 62423258cfeSbeck *error = err; 62523258cfeSbeck x509_constraints_names_free(excluded); 62623258cfeSbeck x509_constraints_names_free(permitted); 62723258cfeSbeck return 0; 62823258cfeSbeck } 62923258cfeSbeck 63023258cfeSbeck static int 63123258cfeSbeck x509_verify_cert_extensions(struct x509_verify_ctx *ctx, X509 *cert, int need_ca) 63223258cfeSbeck { 63323258cfeSbeck if (!(cert->ex_flags & EXFLAG_SET)) { 63423258cfeSbeck CRYPTO_w_lock(CRYPTO_LOCK_X509); 63523258cfeSbeck x509v3_cache_extensions(cert); 63623258cfeSbeck CRYPTO_w_unlock(CRYPTO_LOCK_X509); 63723258cfeSbeck } 63823258cfeSbeck 63923258cfeSbeck if (ctx->xsc != NULL) 64023258cfeSbeck return 1; /* legacy is checked after chain is built */ 64123258cfeSbeck 64223258cfeSbeck if (cert->ex_flags & EXFLAG_CRITICAL) { 64323258cfeSbeck ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; 64423258cfeSbeck return 0; 64523258cfeSbeck } 64623258cfeSbeck /* No we don't care about v1, netscape, and other ancient silliness */ 64723258cfeSbeck if (need_ca && (!(cert->ex_flags & EXFLAG_BCONS) && 64823258cfeSbeck (cert->ex_flags & EXFLAG_CA))) { 64923258cfeSbeck ctx->error = X509_V_ERR_INVALID_CA; 65023258cfeSbeck return 0; 65123258cfeSbeck } 65223258cfeSbeck if (ctx->purpose > 0 && X509_check_purpose(cert, ctx->purpose, need_ca)) { 65323258cfeSbeck ctx->error = X509_V_ERR_INVALID_PURPOSE; 65423258cfeSbeck return 0; 65523258cfeSbeck } 65623258cfeSbeck 65723258cfeSbeck /* XXX support proxy certs later in new api */ 65823258cfeSbeck if (ctx->xsc == NULL && cert->ex_flags & EXFLAG_PROXY) { 65923258cfeSbeck ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; 66023258cfeSbeck return 0; 66123258cfeSbeck } 66223258cfeSbeck 66323258cfeSbeck return 1; 66423258cfeSbeck } 66523258cfeSbeck 66623258cfeSbeck /* Validate that cert is a possible candidate to append to current_chain */ 66723258cfeSbeck static int 66823258cfeSbeck x509_verify_cert_valid(struct x509_verify_ctx *ctx, X509 *cert, 66923258cfeSbeck struct x509_verify_chain *current_chain) 67023258cfeSbeck { 67123258cfeSbeck X509 *issuer_candidate; 67223258cfeSbeck int should_be_ca = current_chain != NULL; 67323258cfeSbeck size_t depth = 0; 67423258cfeSbeck 675ec12bfceSbeck if (current_chain != NULL) 67623258cfeSbeck depth = sk_X509_num(current_chain->certs); 67723258cfeSbeck 67823258cfeSbeck if (!x509_verify_cert_extensions(ctx, cert, should_be_ca)) 67923258cfeSbeck return 0; 68023258cfeSbeck 68123258cfeSbeck if (should_be_ca) { 68223258cfeSbeck issuer_candidate = x509_verify_chain_last(current_chain); 68323258cfeSbeck if (issuer_candidate != NULL && 68423258cfeSbeck !X509_check_issued(issuer_candidate, cert)) 68523258cfeSbeck if (!x509_verify_cert_error(ctx, cert, depth, 68623258cfeSbeck X509_V_ERR_SUBJECT_ISSUER_MISMATCH, 0)) 68723258cfeSbeck return 0; 68823258cfeSbeck } 68923258cfeSbeck 69023258cfeSbeck if (x509_verify_set_check_time(ctx)) { 69123258cfeSbeck if (!x509_verify_cert_time(0, X509_get_notBefore(cert), 69223258cfeSbeck ctx->check_time, &ctx->error)) { 69323258cfeSbeck if (!x509_verify_cert_error(ctx, cert, depth, 69423258cfeSbeck ctx->error, 0)) 69523258cfeSbeck return 0; 69623258cfeSbeck } 69723258cfeSbeck 69823258cfeSbeck if (!x509_verify_cert_time(1, X509_get_notAfter(cert), 69923258cfeSbeck ctx->check_time, &ctx->error)) { 70023258cfeSbeck if (!x509_verify_cert_error(ctx, cert, depth, 70123258cfeSbeck ctx->error, 0)) 70223258cfeSbeck return 0; 70323258cfeSbeck } 70423258cfeSbeck } 70523258cfeSbeck 70623258cfeSbeck if (!x509_verify_validate_constraints(cert, current_chain, 70723258cfeSbeck &ctx->error) && !x509_verify_cert_error(ctx, cert, depth, 70823258cfeSbeck ctx->error, 0)) 70923258cfeSbeck return 0; 71023258cfeSbeck 71123258cfeSbeck return 1; 71223258cfeSbeck } 71323258cfeSbeck 71423258cfeSbeck struct x509_verify_ctx * 71523258cfeSbeck x509_verify_ctx_new_from_xsc(X509_STORE_CTX *xsc, STACK_OF(X509) *roots) 71623258cfeSbeck { 71723258cfeSbeck struct x509_verify_ctx *ctx; 7182c940cf3Sjsing size_t max_depth; 71923258cfeSbeck 72023258cfeSbeck if (xsc == NULL) 72123258cfeSbeck return NULL; 72223258cfeSbeck 7232c940cf3Sjsing if ((ctx = x509_verify_ctx_new(roots)) == NULL) 72423258cfeSbeck return NULL; 72523258cfeSbeck 72623258cfeSbeck ctx->xsc = xsc; 72723258cfeSbeck 72823258cfeSbeck if (xsc->untrusted && 72923258cfeSbeck (ctx->intermediates = X509_chain_up_ref(xsc->untrusted)) == NULL) 73023258cfeSbeck goto err; 73123258cfeSbeck 7322c940cf3Sjsing max_depth = X509_VERIFY_MAX_CHAIN_CERTS; 7332c940cf3Sjsing if (xsc->param->depth > 0 && xsc->param->depth < X509_VERIFY_MAX_CHAIN_CERTS) 7342c940cf3Sjsing max_depth = xsc->param->depth; 7352c940cf3Sjsing if (!x509_verify_ctx_set_max_depth(ctx, max_depth)) 73623258cfeSbeck goto err; 73723258cfeSbeck 73823258cfeSbeck return ctx; 73923258cfeSbeck err: 74023258cfeSbeck x509_verify_ctx_free(ctx); 74123258cfeSbeck return NULL; 74223258cfeSbeck } 74323258cfeSbeck 74423258cfeSbeck /* Public API */ 74523258cfeSbeck 74623258cfeSbeck struct x509_verify_ctx * 74723258cfeSbeck x509_verify_ctx_new(STACK_OF(X509) *roots) 74823258cfeSbeck { 74923258cfeSbeck struct x509_verify_ctx *ctx; 75023258cfeSbeck 75123258cfeSbeck if (roots == NULL) 75223258cfeSbeck return NULL; 75323258cfeSbeck 75423258cfeSbeck if ((ctx = calloc(1, sizeof(struct x509_verify_ctx))) == NULL) 75523258cfeSbeck return NULL; 75623258cfeSbeck 75723258cfeSbeck if ((ctx->roots = X509_chain_up_ref(roots)) == NULL) 75823258cfeSbeck goto err; 75923258cfeSbeck 76023258cfeSbeck ctx->max_depth = X509_VERIFY_MAX_CHAIN_CERTS; 76123258cfeSbeck ctx->max_chains = X509_VERIFY_MAX_CHAINS; 76223258cfeSbeck ctx->max_sigs = X509_VERIFY_MAX_SIGCHECKS; 76323258cfeSbeck 76423258cfeSbeck if ((ctx->chains = calloc(X509_VERIFY_MAX_CHAINS, 76523258cfeSbeck sizeof(*ctx->chains))) == NULL) 76623258cfeSbeck goto err; 76723258cfeSbeck 76823258cfeSbeck return ctx; 76923258cfeSbeck err: 77023258cfeSbeck x509_verify_ctx_free(ctx); 77123258cfeSbeck return NULL; 77223258cfeSbeck } 77323258cfeSbeck 77423258cfeSbeck void 77523258cfeSbeck x509_verify_ctx_free(struct x509_verify_ctx *ctx) 77623258cfeSbeck { 77723258cfeSbeck if (ctx == NULL) 77823258cfeSbeck return; 77923258cfeSbeck sk_X509_pop_free(ctx->roots, X509_free); 78023258cfeSbeck x509_verify_ctx_clear(ctx); 78123258cfeSbeck free(ctx); 78223258cfeSbeck } 78323258cfeSbeck 78423258cfeSbeck int 78523258cfeSbeck x509_verify_ctx_set_max_depth(struct x509_verify_ctx *ctx, size_t max) 78623258cfeSbeck { 78723258cfeSbeck if (max < 1 || max > X509_VERIFY_MAX_CHAIN_CERTS) 78823258cfeSbeck return 0; 78923258cfeSbeck ctx->max_depth = max; 79023258cfeSbeck return 1; 79123258cfeSbeck } 79223258cfeSbeck 79323258cfeSbeck int 79423258cfeSbeck x509_verify_ctx_set_max_chains(struct x509_verify_ctx *ctx, size_t max) 79523258cfeSbeck { 79623258cfeSbeck if (max < 1 || max > X509_VERIFY_MAX_CHAINS) 79723258cfeSbeck return 0; 79823258cfeSbeck ctx->max_chains = max; 79923258cfeSbeck return 1; 80023258cfeSbeck } 80123258cfeSbeck 80223258cfeSbeck int 80323258cfeSbeck x509_verify_ctx_set_max_signatures(struct x509_verify_ctx *ctx, size_t max) 80423258cfeSbeck { 8059f2be83cSjsing if (max < 1 || max > 100000) 80623258cfeSbeck return 0; 80723258cfeSbeck ctx->max_sigs = max; 80823258cfeSbeck return 1; 80923258cfeSbeck } 81023258cfeSbeck 81123258cfeSbeck int 81223258cfeSbeck x509_verify_ctx_set_purpose(struct x509_verify_ctx *ctx, int purpose) 81323258cfeSbeck { 81423258cfeSbeck if (purpose < X509_PURPOSE_MIN || purpose > X509_PURPOSE_MAX) 81523258cfeSbeck return 0; 81623258cfeSbeck ctx->purpose = purpose; 81723258cfeSbeck return 1; 81823258cfeSbeck } 81923258cfeSbeck 82023258cfeSbeck int 82123258cfeSbeck x509_verify_ctx_set_intermediates(struct x509_verify_ctx *ctx, 82223258cfeSbeck STACK_OF(X509) *intermediates) 82323258cfeSbeck { 82423258cfeSbeck if ((ctx->intermediates = X509_chain_up_ref(intermediates)) == NULL) 82523258cfeSbeck return 0; 82623258cfeSbeck return 1; 82723258cfeSbeck } 82823258cfeSbeck 82923258cfeSbeck const char * 83023258cfeSbeck x509_verify_ctx_error_string(struct x509_verify_ctx *ctx) 83123258cfeSbeck { 83223258cfeSbeck return X509_verify_cert_error_string(ctx->error); 83323258cfeSbeck } 83423258cfeSbeck 83523258cfeSbeck size_t 83623258cfeSbeck x509_verify_ctx_error_depth(struct x509_verify_ctx *ctx) 83723258cfeSbeck { 83823258cfeSbeck return ctx->error_depth; 83923258cfeSbeck } 84023258cfeSbeck 84123258cfeSbeck STACK_OF(X509) * 84223258cfeSbeck x509_verify_ctx_chain(struct x509_verify_ctx *ctx, size_t i) 84323258cfeSbeck { 84423258cfeSbeck if (i >= ctx->chains_count) 84523258cfeSbeck return NULL; 84623258cfeSbeck return ctx->chains[i]->certs; 84723258cfeSbeck } 84823258cfeSbeck 84923258cfeSbeck size_t 85023258cfeSbeck x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name) 85123258cfeSbeck { 85223258cfeSbeck struct x509_verify_chain *current_chain; 85323258cfeSbeck 854e4db083fSbeck if (ctx->roots == NULL || ctx->max_depth == 0) { 85523258cfeSbeck ctx->error = X509_V_ERR_INVALID_CALL; 85623258cfeSbeck return 0; 85723258cfeSbeck } 85823258cfeSbeck 85923258cfeSbeck if (ctx->xsc != NULL) { 86023258cfeSbeck if (leaf != NULL || name != NULL) { 86123258cfeSbeck ctx->error = X509_V_ERR_INVALID_CALL; 86223258cfeSbeck return 0; 86323258cfeSbeck } 86423258cfeSbeck leaf = ctx->xsc->cert; 86523258cfeSbeck } 86623258cfeSbeck 86723258cfeSbeck if (!x509_verify_cert_valid(ctx, leaf, NULL)) 86823258cfeSbeck return 0; 86923258cfeSbeck 87023258cfeSbeck if (!x509_verify_cert_hostname(ctx, leaf, name)) 87123258cfeSbeck return 0; 87223258cfeSbeck 87323258cfeSbeck if (ctx->xsc != NULL) { 87423258cfeSbeck /* 87523258cfeSbeck * XXX 87623258cfeSbeck * The legacy code expects the top level cert to be 87723258cfeSbeck * there, even if we didn't find a chain. So put it 87823258cfeSbeck * there, we will clobber it later if we find a valid 87923258cfeSbeck * chain. 88023258cfeSbeck */ 88123258cfeSbeck if ((ctx->xsc->chain = sk_X509_new_null()) == NULL) { 88223258cfeSbeck ctx->error = X509_V_ERR_OUT_OF_MEM; 88323258cfeSbeck return 0; 88423258cfeSbeck } 88523258cfeSbeck if (!X509_up_ref(leaf)) { 88623258cfeSbeck ctx->error = X509_V_ERR_OUT_OF_MEM; 88723258cfeSbeck return 0; 88823258cfeSbeck } 88923258cfeSbeck if (!sk_X509_push(ctx->xsc->chain, leaf)) { 89023258cfeSbeck X509_free(leaf); 89123258cfeSbeck ctx->error = X509_V_ERR_OUT_OF_MEM; 89223258cfeSbeck return 0; 89323258cfeSbeck } 894d59cc15fSbeck ctx->xsc->error_depth = 0; 895d59cc15fSbeck ctx->xsc->current_cert = leaf; 89623258cfeSbeck } 89723258cfeSbeck 89823258cfeSbeck if ((current_chain = x509_verify_chain_new()) == NULL) { 89923258cfeSbeck ctx->error = X509_V_ERR_OUT_OF_MEM; 90023258cfeSbeck return 0; 90123258cfeSbeck } 90223258cfeSbeck if (!x509_verify_chain_append(current_chain, leaf, &ctx->error)) { 90323258cfeSbeck x509_verify_chain_free(current_chain); 90423258cfeSbeck return 0; 90523258cfeSbeck } 90623258cfeSbeck if (x509_verify_ctx_cert_is_root(ctx, leaf)) 90723258cfeSbeck x509_verify_ctx_add_chain(ctx, current_chain); 90823258cfeSbeck else 90923258cfeSbeck x509_verify_build_chains(ctx, leaf, current_chain); 91023258cfeSbeck 91123258cfeSbeck x509_verify_chain_free(current_chain); 91223258cfeSbeck 91323258cfeSbeck /* 91423258cfeSbeck * Safety net: 91523258cfeSbeck * We could not find a validated chain, and for some reason do not 91623258cfeSbeck * have an error set. 91723258cfeSbeck */ 91823258cfeSbeck if (ctx->chains_count == 0 && ctx->error == 0) 91923258cfeSbeck ctx->error = X509_V_ERR_UNSPECIFIED; 92023258cfeSbeck 92123258cfeSbeck /* Clear whatever errors happened if we have any validated chain */ 92223258cfeSbeck if (ctx->chains_count > 0) 92323258cfeSbeck ctx->error = X509_V_OK; 92423258cfeSbeck 92523258cfeSbeck if (ctx->xsc != NULL) { 92623258cfeSbeck ctx->xsc->error = ctx->error; 92723258cfeSbeck return ctx->xsc->verify_cb(ctx->chains_count, ctx->xsc); 92823258cfeSbeck } 92923258cfeSbeck return (ctx->chains_count); 93023258cfeSbeck } 931