Tidy up x509_vfy callback handling

Reviewed-by: Dr. Stephen Henson <steve@openssl.org>
This commit is contained in:
Viktor Dukhovni
2016-02-27 14:17:28 -05:00
parent 0f1ef63bf1
commit 70dd3c6593
3 changed files with 223 additions and 291 deletions

View File

@@ -81,7 +81,8 @@ struct X509_VERIFY_PARAM_st {
size_t iplen; /* Length of IP address */ size_t iplen; /* Length of IP address */
}; };
int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int quiet); /* No error callback if depth < 0 */
int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth);
/* a sequence of these are used */ /* a sequence of these are used */
struct x509_attributes_st { struct x509_attributes_st {

View File

@@ -630,7 +630,7 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
} }
/* If certificate matches all OK */ /* If certificate matches all OK */
if (ctx->check_issued(ctx, x, obj.data.x509)) { if (ctx->check_issued(ctx, x, obj.data.x509)) {
if (x509_check_cert_time(ctx, obj.data.x509, 1)) { if (x509_check_cert_time(ctx, obj.data.x509, -1)) {
*issuer = obj.data.x509; *issuer = obj.data.x509;
return 1; return 1;
} }
@@ -661,7 +661,7 @@ int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
* match if no certificate time is OK. * match if no certificate time is OK.
*/ */
if (x509_check_cert_time(ctx, *issuer, 1)) if (x509_check_cert_time(ctx, *issuer, -1))
break; break;
} }
} }

View File

@@ -190,6 +190,37 @@ static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
return xtmp; return xtmp;
} }
/*-
* Inform the verify callback of an error.
* If B<x> is not NULL it is the error cert, otherwise use the chain cert at
* B<depth>.
* If B<err> is not X509_V_OK, that's the error value, otherwise leave
* unchanged (presumably set by the caller).
*
* Returns 0 to abort verification with an error, non-zero to continue.
*/
static int verify_cb_cert(X509_STORE_CTX *ctx, X509 *x, int depth, int err)
{
ctx->error_depth = depth;
ctx->current_cert = (x != NULL) ? x : sk_X509_value(ctx->chain, depth);
if (err != X509_V_OK)
ctx->error = err;
return ctx->verify_cb(0, ctx);
}
/*-
* Inform the verify callback of an error, CRL-specific variant. Here, the
* error depth and certificate are already set, we just specify the error
* number.
*
* Returns 0 to abort verification with an error, non-zero to continue.
*/
static int verify_cb_crl(X509_STORE_CTX *ctx, int err)
{
ctx->error = err;
return ctx->verify_cb(0, ctx);
}
static int verify_chain(X509_STORE_CTX *ctx) static int verify_chain(X509_STORE_CTX *ctx)
{ {
int err; int err;
@@ -210,9 +241,7 @@ static int verify_chain(X509_STORE_CTX *ctx)
err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, err = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain,
ctx->param->flags); ctx->param->flags);
if (err != X509_V_OK) { if (err != X509_V_OK) {
ctx->error = err; if ((ok = verify_cb_cert(ctx, NULL, ctx->error_depth, err)) == 0)
ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth);
if ((ok = ctx->verify_cb(0, ctx)) == 0)
return ok; return ok;
} }
@@ -288,7 +317,7 @@ static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
issuer = sk_X509_value(sk, i); issuer = sk_X509_value(sk, i);
if (ctx->check_issued(ctx, x, issuer)) { if (ctx->check_issued(ctx, x, issuer)) {
rv = issuer; rv = issuer;
if (x509_check_cert_time(ctx, rv, 1)) if (x509_check_cert_time(ctx, rv, -1))
break; break;
} }
} }
@@ -401,10 +430,7 @@ static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth,
break; break;
} }
ctx->error = X509_V_ERR_INVALID_PURPOSE; return verify_cb_cert(ctx, x, depth, X509_V_ERR_INVALID_PURPOSE);
ctx->error_depth = depth;
ctx->current_cert = x;
return ctx->verify_cb(0, ctx);
} }
/* /*
@@ -453,17 +479,13 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
x = sk_X509_value(ctx->chain, i); x = sk_X509_value(ctx->chain, i);
if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
&& (x->ex_flags & EXFLAG_CRITICAL)) { && (x->ex_flags & EXFLAG_CRITICAL)) {
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; if (!verify_cb_cert(ctx, x, i,
ctx->error_depth = i; X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION))
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) { if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) {
ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; if (!verify_cb_cert(ctx, x, i,
ctx->error_depth = i; X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED))
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
ret = X509_check_ca(x); ret = X509_check_ca(x);
@@ -494,24 +516,16 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
ret = 1; ret = 1;
break; break;
} }
if (ret == 0) { if (ret == 0 && !verify_cb_cert(ctx, x, i, X509_V_OK))
ctx->error_depth = i; return 0;
ctx->current_cert = x; /* check_purpose() makes the callback as needed */
if (!ctx->verify_cb(0, ctx)) if (purpose > 0 && !check_purpose(ctx, x, purpose, i, must_be_ca))
return 0; return 0;
}
if (purpose > 0) {
if (!check_purpose(ctx, x, purpose, i, must_be_ca))
return 0;
}
/* Check pathlen if not self issued */ /* Check pathlen if not self issued */
if ((i > 1) && !(x->ex_flags & EXFLAG_SI) if ((i > 1) && !(x->ex_flags & EXFLAG_SI)
&& (x->ex_pathlen != -1) && (x->ex_pathlen != -1)
&& (plen > (x->ex_pathlen + proxy_path_length + 1))) { && (plen > (x->ex_pathlen + proxy_path_length + 1))) {
ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED; if (!verify_cb_cert(ctx, x, i, X509_V_ERR_PATH_LENGTH_EXCEEDED))
ctx->error_depth = i;
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
/* Increment path length if not self issued */ /* Increment path length if not self issued */
@@ -524,10 +538,8 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
*/ */
if (x->ex_flags & EXFLAG_PROXY) { if (x->ex_flags & EXFLAG_PROXY) {
if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen) { if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen) {
ctx->error = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED; if (!verify_cb_cert(ctx, x, i,
ctx->error_depth = i; X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED))
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
proxy_path_length++; proxy_path_length++;
@@ -540,11 +552,13 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
static int check_name_constraints(X509_STORE_CTX *ctx) static int check_name_constraints(X509_STORE_CTX *ctx)
{ {
X509 *x; int i;
int i, j, rv;
/* Check name constraints for all certificates */ /* Check name constraints for all certificates */
for (i = sk_X509_num(ctx->chain) - 1; i >= 0; i--) { for (i = sk_X509_num(ctx->chain) - 1; i >= 0; i--) {
x = sk_X509_value(ctx->chain, i); X509 *x = sk_X509_value(ctx->chain, i);
int j;
/* Ignore self issued certs unless last in chain */ /* Ignore self issued certs unless last in chain */
if (i && (x->ex_flags & EXFLAG_SI)) if (i && (x->ex_flags & EXFLAG_SI))
continue; continue;
@@ -556,15 +570,12 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
*/ */
for (j = sk_X509_num(ctx->chain) - 1; j > i; j--) { for (j = sk_X509_num(ctx->chain) - 1; j > i; j--) {
NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc; NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc;
if (nc) { if (nc) {
rv = NAME_CONSTRAINTS_check(x, nc); int rv = NAME_CONSTRAINTS_check(x, nc);
if (rv != X509_V_OK) {
ctx->error = rv; if (rv != X509_V_OK && !verify_cb_cert(ctx, x, i, rv))
ctx->error_depth = i; return 0;
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0;
}
} }
} }
} }
@@ -573,10 +584,7 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
static int check_id_error(X509_STORE_CTX *ctx, int errcode) static int check_id_error(X509_STORE_CTX *ctx, int errcode)
{ {
ctx->error = errcode; return verify_cb_cert(ctx, ctx->cert, 0, errcode);
ctx->current_cert = ctx->cert;
ctx->error_depth = 0;
return ctx->verify_cb(0, ctx);
} }
static int check_hosts(X509 *x, X509_VERIFY_PARAM *vpm) static int check_hosts(X509 *x, X509_VERIFY_PARAM *vpm)
@@ -618,7 +626,7 @@ static int check_id(X509_STORE_CTX *ctx)
static int check_trust(X509_STORE_CTX *ctx, int num_untrusted) static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
{ {
int i, ok = 0; int i;
X509 *x = NULL; X509 *x = NULL;
X509 *mx; X509 *mx;
struct dane_st *dane = (struct dane_st *)ctx->dane; struct dane_st *dane = (struct dane_st *)ctx->dane;
@@ -698,11 +706,7 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
return X509_TRUST_UNTRUSTED; return X509_TRUST_UNTRUSTED;
rejected: rejected:
ctx->error_depth = i; if (!verify_cb_cert(ctx, x, i, X509_V_ERR_CERT_REJECTED))
ctx->current_cert = x;
ctx->error = X509_V_ERR_CERT_REJECTED;
ok = ctx->verify_cb(0, ctx);
if (!ok)
return X509_TRUST_REJECTED; return X509_TRUST_REJECTED;
return X509_TRUST_UNTRUSTED; return X509_TRUST_UNTRUSTED;
@@ -742,17 +746,18 @@ static int check_revocation(X509_STORE_CTX *ctx)
static int check_cert(X509_STORE_CTX *ctx) static int check_cert(X509_STORE_CTX *ctx)
{ {
X509_CRL *crl = NULL, *dcrl = NULL; X509_CRL *crl = NULL, *dcrl = NULL;
X509 *x = NULL; int ok = 0;
int ok = 0, cnum = 0; int cnum = ctx->error_depth;
unsigned int last_reasons = 0; X509 *x = sk_X509_value(ctx->chain, cnum);
cnum = ctx->error_depth;
x = sk_X509_value(ctx->chain, cnum);
ctx->current_cert = x; ctx->current_cert = x;
ctx->current_issuer = NULL; ctx->current_issuer = NULL;
ctx->current_crl_score = 0; ctx->current_crl_score = 0;
ctx->current_reasons = 0; ctx->current_reasons = 0;
while (ctx->current_reasons != CRLDP_ALL_REASONS) { while (ctx->current_reasons != CRLDP_ALL_REASONS) {
last_reasons = ctx->current_reasons; unsigned int last_reasons = ctx->current_reasons;
/* Try to retrieve relevant CRL */ /* Try to retrieve relevant CRL */
if (ctx->get_crl) if (ctx->get_crl)
ok = ctx->get_crl(ctx, &crl, x); ok = ctx->get_crl(ctx, &crl, x);
@@ -762,22 +767,21 @@ static int check_cert(X509_STORE_CTX *ctx)
* If error looking up CRL, nothing we can do except notify callback * If error looking up CRL, nothing we can do except notify callback
*/ */
if (!ok) { if (!ok) {
ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL; ok = verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL);
ok = ctx->verify_cb(0, ctx); goto done;
goto err;
} }
ctx->current_crl = crl; ctx->current_crl = crl;
ok = ctx->check_crl(ctx, crl); ok = ctx->check_crl(ctx, crl);
if (!ok) if (!ok)
goto err; goto done;
if (dcrl) { if (dcrl) {
ok = ctx->check_crl(ctx, dcrl); ok = ctx->check_crl(ctx, dcrl);
if (!ok) if (!ok)
goto err; goto done;
ok = ctx->cert_crl(ctx, dcrl, x); ok = ctx->cert_crl(ctx, dcrl, x);
if (!ok) if (!ok)
goto err; goto done;
} else } else
ok = 1; ok = 1;
@@ -785,7 +789,7 @@ static int check_cert(X509_STORE_CTX *ctx)
if (ok != 2) { if (ok != 2) {
ok = ctx->cert_crl(ctx, crl, x); ok = ctx->cert_crl(ctx, crl, x);
if (!ok) if (!ok)
goto err; goto done;
} }
X509_CRL_free(crl); X509_CRL_free(crl);
@@ -797,18 +801,16 @@ static int check_cert(X509_STORE_CTX *ctx)
* so exit loop. * so exit loop.
*/ */
if (last_reasons == ctx->current_reasons) { if (last_reasons == ctx->current_reasons) {
ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL; ok = verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL);
ok = ctx->verify_cb(0, ctx); goto done;
goto err;
} }
} }
err: done:
X509_CRL_free(crl); X509_CRL_free(crl);
X509_CRL_free(dcrl); X509_CRL_free(dcrl);
ctx->current_crl = NULL; ctx->current_crl = NULL;
return ok; return ok;
} }
/* Check CRL times against values in X509_STORE_CTX */ /* Check CRL times against values in X509_STORE_CTX */
@@ -817,6 +819,7 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
{ {
time_t *ptime; time_t *ptime;
int i; int i;
if (notify) if (notify)
ctx->current_crl = crl; ctx->current_crl = crl;
if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME)
@@ -830,16 +833,14 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
if (i == 0) { if (i == 0) {
if (!notify) if (!notify)
return 0; return 0;
ctx->error = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD; if (!verify_cb_crl(ctx, X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD))
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
if (i > 0) { if (i > 0) {
if (!notify) if (!notify)
return 0; return 0;
ctx->error = X509_V_ERR_CRL_NOT_YET_VALID; if (!verify_cb_crl(ctx, X509_V_ERR_CRL_NOT_YET_VALID))
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
@@ -849,16 +850,14 @@ static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify)
if (i == 0) { if (i == 0) {
if (!notify) if (!notify)
return 0; return 0;
ctx->error = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD; if (!verify_cb_crl(ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD))
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
/* Ignore expiry of base CRL is delta is valid */ /* Ignore expiry of base CRL is delta is valid */
if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)) { if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)) {
if (!notify) if (!notify)
return 0; return 0;
ctx->error = X509_V_ERR_CRL_HAS_EXPIRED; if (!verify_cb_crl(ctx, X509_V_ERR_CRL_HAS_EXPIRED))
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
} }
@@ -1138,6 +1137,7 @@ static int check_crl_path(X509_STORE_CTX *ctx, X509 *x)
{ {
X509_STORE_CTX crl_ctx; X509_STORE_CTX crl_ctx;
int ret; int ret;
/* Don't allow recursive CRL path validation */ /* Don't allow recursive CRL path validation */
if (ctx->parent) if (ctx->parent)
return 0; return 0;
@@ -1153,12 +1153,10 @@ static int check_crl_path(X509_STORE_CTX *ctx, X509 *x)
/* Verify CRL issuer */ /* Verify CRL issuer */
ret = X509_verify_cert(&crl_ctx); ret = X509_verify_cert(&crl_ctx);
if (ret <= 0) if (ret <= 0)
goto err; goto err;
/* Check chain is acceptable */ /* Check chain is acceptable */
ret = check_crl_chain(ctx, ctx->chain, crl_ctx.chain); ret = check_crl_chain(ctx, ctx->chain, crl_ctx.chain);
err: err:
X509_STORE_CTX_cleanup(&crl_ctx); X509_STORE_CTX_cleanup(&crl_ctx);
@@ -1315,10 +1313,10 @@ static int get_crl_delta(X509_STORE_CTX *ctx,
X509_CRL *crl = NULL, *dcrl = NULL; X509_CRL *crl = NULL, *dcrl = NULL;
STACK_OF(X509_CRL) *skcrl; STACK_OF(X509_CRL) *skcrl;
X509_NAME *nm = X509_get_issuer_name(x); X509_NAME *nm = X509_get_issuer_name(x);
reasons = ctx->current_reasons; reasons = ctx->current_reasons;
ok = get_crl_sk(ctx, &crl, &dcrl, ok = get_crl_sk(ctx, &crl, &dcrl,
&issuer, &crl_score, &reasons, ctx->crls); &issuer, &crl_score, &reasons, ctx->crls);
if (ok) if (ok)
goto done; goto done;
@@ -1335,7 +1333,6 @@ static int get_crl_delta(X509_STORE_CTX *ctx,
sk_X509_CRL_pop_free(skcrl, X509_CRL_free); sk_X509_CRL_pop_free(skcrl, X509_CRL_free);
done: done:
/* If we got any kind of CRL use it and return success */ /* If we got any kind of CRL use it and return success */
if (crl) { if (crl) {
ctx->current_issuer = issuer; ctx->current_issuer = issuer;
@@ -1345,7 +1342,6 @@ static int get_crl_delta(X509_STORE_CTX *ctx,
*pdcrl = dcrl; *pdcrl = dcrl;
return 1; return 1;
} }
return 0; return 0;
} }
@@ -1354,13 +1350,12 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
{ {
X509 *issuer = NULL; X509 *issuer = NULL;
EVP_PKEY *ikey = NULL; EVP_PKEY *ikey = NULL;
int ok = 0, chnum, cnum; int cnum = ctx->error_depth;
cnum = ctx->error_depth; int chnum = sk_X509_num(ctx->chain) - 1;
chnum = sk_X509_num(ctx->chain) - 1;
/* if we have an alternative CRL issuer cert use that */ /* if we have an alternative CRL issuer cert use that */
if (ctx->current_issuer) if (ctx->current_issuer)
issuer = ctx->current_issuer; issuer = ctx->current_issuer;
/* /*
* Else find CRL issuer: if not last certificate then issuer is next * Else find CRL issuer: if not last certificate then issuer is next
* certificate in chain. * certificate in chain.
@@ -1370,120 +1365,85 @@ static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl)
else { else {
issuer = sk_X509_value(ctx->chain, chnum); issuer = sk_X509_value(ctx->chain, chnum);
/* If not self signed, can't check signature */ /* If not self signed, can't check signature */
if (!ctx->check_issued(ctx, issuer, issuer)) { if (!ctx->check_issued(ctx, issuer, issuer) &&
ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER; !verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER))
ok = ctx->verify_cb(0, ctx); return 0;
if (!ok)
goto err;
}
} }
if (issuer) { if (issuer == NULL)
/* return 1;
* Skip most tests for deltas because they have already been done
*/
if (!crl->base_crl_number) {
/* Check for cRLSign bit if keyUsage present */
if ((issuer->ex_flags & EXFLAG_KUSAGE) &&
!(issuer->ex_kusage & KU_CRL_SIGN)) {
ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
ok = ctx->verify_cb(0, ctx);
if (!ok)
goto err;
}
if (!(ctx->current_crl_score & CRL_SCORE_SCOPE)) { /*
ctx->error = X509_V_ERR_DIFFERENT_CRL_SCOPE; * Skip most tests for deltas because they have already been done
ok = ctx->verify_cb(0, ctx); */
if (!ok) if (!crl->base_crl_number) {
goto err; /* Check for cRLSign bit if keyUsage present */
} if ((issuer->ex_flags & EXFLAG_KUSAGE) &&
!(issuer->ex_kusage & KU_CRL_SIGN) &&
!verify_cb_crl(ctx, X509_V_ERR_KEYUSAGE_NO_CRL_SIGN))
return 0;
if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH)) { if (!(ctx->current_crl_score & CRL_SCORE_SCOPE) &&
if (check_crl_path(ctx, ctx->current_issuer) <= 0) { !verify_cb_crl(ctx, X509_V_ERR_DIFFERENT_CRL_SCOPE))
ctx->error = X509_V_ERR_CRL_PATH_VALIDATION_ERROR; return 0;
ok = ctx->verify_cb(0, ctx);
if (!ok)
goto err;
}
}
if (crl->idp_flags & IDP_INVALID) { if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH) &&
ctx->error = X509_V_ERR_INVALID_EXTENSION; check_crl_path(ctx, ctx->current_issuer) <= 0 &&
ok = ctx->verify_cb(0, ctx); !verify_cb_crl(ctx, X509_V_ERR_CRL_PATH_VALIDATION_ERROR))
if (!ok) return 0;
goto err;
}
} if ((crl->idp_flags & IDP_INVALID) &&
!verify_cb_crl(ctx, X509_V_ERR_INVALID_EXTENSION))
if (!(ctx->current_crl_score & CRL_SCORE_TIME)) { return 0;
ok = check_crl_time(ctx, crl, 1);
if (!ok)
goto err;
}
/* Attempt to get issuer certificate public key */
ikey = X509_get0_pubkey(issuer);
if (!ikey) {
ctx->error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
ok = ctx->verify_cb(0, ctx);
if (!ok)
goto err;
} else {
int rv;
rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags);
if (rv != X509_V_OK) {
ctx->error = rv;
ok = ctx->verify_cb(0, ctx);
if (!ok)
goto err;
}
/* Verify CRL signature */
if (X509_CRL_verify(crl, ikey) <= 0) {
ctx->error = X509_V_ERR_CRL_SIGNATURE_FAILURE;
ok = ctx->verify_cb(0, ctx);
if (!ok)
goto err;
}
}
} }
ok = 1; if (!(ctx->current_crl_score & CRL_SCORE_TIME) &&
!check_crl_time(ctx, crl, 1))
return 0;
err: /* Attempt to get issuer certificate public key */
return ok; ikey = X509_get0_pubkey(issuer);
if (!ikey &&
!verify_cb_crl(ctx, X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY))
return 0;
if (ikey) {
int rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags);
if (rv != X509_V_OK && !verify_cb_crl(ctx, rv))
return 0;
/* Verify CRL signature */
if (X509_CRL_verify(crl, ikey) <= 0 &&
!verify_cb_crl(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE))
return 0;
}
return 1;
} }
/* Check certificate against CRL */ /* Check certificate against CRL */
static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x)
{ {
int ok;
X509_REVOKED *rev; X509_REVOKED *rev;
/* /*
* The rules changed for this... previously if a CRL contained unhandled * The rules changed for this... previously if a CRL contained unhandled
* critical extensions it could still be used to indicate a certificate * critical extensions it could still be used to indicate a certificate
* was revoked. This has since been changed since critical extension can * was revoked. This has since been changed since critical extensions can
* change the meaning of CRL entries. * change the meaning of CRL entries.
*/ */
if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
&& (crl->flags & EXFLAG_CRITICAL)) { && (crl->flags & EXFLAG_CRITICAL) &&
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION; !verify_cb_crl(ctx, X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION))
ok = ctx->verify_cb(0, ctx); return 0;
if (!ok)
return 0;
}
/* /*
* Look for serial number of certificate in CRL If found make sure reason * Look for serial number of certificate in CRL. If found, make sure
* is not removeFromCRL. * reason is not removeFromCRL.
*/ */
if (X509_CRL_get0_by_cert(crl, &rev, x)) { if (X509_CRL_get0_by_cert(crl, &rev, x)) {
if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) if (rev->reason == CRL_REASON_REMOVE_FROM_CRL)
return 2; return 2;
ctx->error = X509_V_ERR_CERT_REVOKED; if (!verify_cb_crl(ctx, X509_V_ERR_CERT_REVOKED))
ok = ctx->verify_cb(0, ctx);
if (!ok)
return 0; return 0;
} }
@@ -1522,18 +1482,16 @@ static int check_policy(X509_STORE_CTX *ctx)
} }
/* Invalid or inconsistent extensions */ /* Invalid or inconsistent extensions */
if (ret == X509_PCY_TREE_INVALID) { if (ret == X509_PCY_TREE_INVALID) {
/*
* Locate certificates with bad extensions and notify callback.
*/
X509 *x;
int i; int i;
/* Locate certificates with bad extensions and notify callback. */
for (i = 1; i < sk_X509_num(ctx->chain); i++) { for (i = 1; i < sk_X509_num(ctx->chain); i++) {
x = sk_X509_value(ctx->chain, i); X509 *x = sk_X509_value(ctx->chain, i);
if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) if (!(x->ex_flags & EXFLAG_INVALID_POLICY))
continue; continue;
ctx->current_cert = x; if (!verify_cb_cert(ctx, x, i,
ctx->error = X509_V_ERR_INVALID_POLICY_EXTENSION; X509_V_ERR_INVALID_POLICY_EXTENSION))
if (!ctx->verify_cb(0, ctx))
return 0; return 0;
} }
return 1; return 1;
@@ -1558,7 +1516,14 @@ static int check_policy(X509_STORE_CTX *ctx)
return 1; return 1;
} }
int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int quiet) /*-
* Check certificate validity times.
* If depth >= 0, invoke verification callbacks on error, otherwise just return
* the validation status.
*
* Return 1 on success, 0 otherwise.
*/
int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth)
{ {
time_t *ptime; time_t *ptime;
int i; int i;
@@ -1571,55 +1536,30 @@ int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int quiet)
ptime = NULL; ptime = NULL;
i = X509_cmp_time(X509_get_notBefore(x), ptime); i = X509_cmp_time(X509_get_notBefore(x), ptime);
if (i == 0) { if (i >= 0 && depth < 0)
if (quiet) return 0;
return 0; if (i == 0 && !verify_cb_cert(ctx, x, depth,
ctx->error = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD))
ctx->current_cert = x; return 0;
if (!ctx->verify_cb(0, ctx)) if (i > 0 && !verify_cb_cert(ctx, x, depth, X509_V_ERR_CERT_NOT_YET_VALID))
return 0; return 0;
}
if (i > 0) {
if (quiet)
return 0;
ctx->error = X509_V_ERR_CERT_NOT_YET_VALID;
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0;
}
i = X509_cmp_time(X509_get_notAfter(x), ptime); i = X509_cmp_time(X509_get_notAfter(x), ptime);
if (i == 0) { if (i <= 0 && depth < 0)
if (quiet) return 0;
return 0; if (i == 0 && !verify_cb_cert(ctx, x, depth,
ctx->error = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD; X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD))
ctx->current_cert = x; return 0;
if (!ctx->verify_cb(0, ctx)) if (i < 0 && !verify_cb_cert(ctx, x, depth, X509_V_ERR_CERT_HAS_EXPIRED))
return 0; return 0;
}
if (i < 0) {
if (quiet)
return 0;
ctx->error = X509_V_ERR_CERT_HAS_EXPIRED;
ctx->current_cert = x;
if (!ctx->verify_cb(0, ctx))
return 0;
}
return 1; return 1;
} }
static int internal_verify(X509_STORE_CTX *ctx) static int internal_verify(X509_STORE_CTX *ctx)
{ {
int ok = 0, n; int n = sk_X509_num(ctx->chain) - 1;
X509 *xs, *xi; X509 *xi = sk_X509_value(ctx->chain, n);
EVP_PKEY *pkey = NULL; X509 *xs;
n = sk_X509_num(ctx->chain) - 1;
ctx->error_depth = n;
xi = sk_X509_value(ctx->chain, n);
/* /*
* With DANE-verified bare public key TA signatures, it remains only to * With DANE-verified bare public key TA signatures, it remains only to
@@ -1639,16 +1579,12 @@ static int internal_verify(X509_STORE_CTX *ctx)
xs = xi; xs = xi;
goto check_cert; goto check_cert;
} }
if (n <= 0) { if (n <= 0)
ctx->error = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; return verify_cb_cert(ctx, xi, 0,
ctx->current_cert = xi; X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
ok = ctx->verify_cb(0, ctx); n--;
goto end; ctx->error_depth = n;
} else { xs = sk_X509_value(ctx->chain, n);
n--;
ctx->error_depth = n;
xs = sk_X509_value(ctx->chain, n);
}
} }
/* /*
@@ -1656,50 +1592,47 @@ static int internal_verify(X509_STORE_CTX *ctx)
* is allowed to reset errors (at its own peril). * is allowed to reset errors (at its own peril).
*/ */
while (n >= 0) { while (n >= 0) {
ctx->error_depth = n; EVP_PKEY *pkey;
/* /*
* Skip signature check for self signed certificates unless * Skip signature check for self signed certificates unless explicitly
* explicitly asked for. It doesn't add any security and just wastes * asked for. It doesn't add any security and just wastes time. If
* time. * the issuer's public key is unusable, report the issuer certificate
* and its depth (rather than the depth of the subject).
*/ */
if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) { if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) {
if ((pkey = X509_get0_pubkey(xi)) == NULL) { if ((pkey = X509_get0_pubkey(xi)) == NULL) {
ctx->error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; if (!verify_cb_cert(ctx, xi, xi != xs ? n+1 : n,
ctx->current_cert = xi; X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY))
ok = ctx->verify_cb(0, ctx); return 0;
if (!ok)
goto end;
} else if (X509_verify(xs, pkey) <= 0) { } else if (X509_verify(xs, pkey) <= 0) {
ctx->error = X509_V_ERR_CERT_SIGNATURE_FAILURE; if (!verify_cb_cert(ctx, xs, n,
ctx->current_cert = xs; X509_V_ERR_CERT_SIGNATURE_FAILURE))
ok = ctx->verify_cb(0, ctx); return 0;
if (!ok)
goto end;
} }
} }
check_cert: check_cert:
ok = x509_check_cert_time(ctx, xs, 0); /* Calls verify callback as needed */
if (!ok) if (!x509_check_cert_time(ctx, xs, n))
goto end; return 0;
/* The last error (if any) is still in the error value */ /*
* Signal success at this depth. However, the previous error (if any)
* is retained.
*/
ctx->current_issuer = xi; ctx->current_issuer = xi;
ctx->current_cert = xs; ctx->current_cert = xs;
ok = ctx->verify_cb(1, ctx); ctx->error_depth = n;
if (!ok) if (!ctx->verify_cb(1, ctx))
goto end; return 0;
n--; if (--n >= 0) {
if (n >= 0) {
xi = xs; xi = xs;
xs = sk_X509_value(ctx->chain, n); xs = sk_X509_value(ctx->chain, n);
} }
} }
ok = 1; return 1;
end:
return ok;
} }
int X509_cmp_current_time(const ASN1_TIME *ctm) int X509_cmp_current_time(const ASN1_TIME *ctm)
@@ -2662,10 +2595,7 @@ static int check_leaf_suiteb(X509_STORE_CTX *ctx, X509 *cert)
if (err == X509_V_OK) if (err == X509_V_OK)
return 1; return 1;
ctx->current_cert = cert; return verify_cb_cert(ctx, cert, 0, err);
ctx->error_depth = 0;
ctx->error = err;
return ctx->verify_cb(0, ctx);
} }
static int dane_verify(X509_STORE_CTX *ctx) static int dane_verify(X509_STORE_CTX *ctx)
@@ -2696,8 +2626,10 @@ static int dane_verify(X509_STORE_CTX *ctx)
X509_get_pubkey_parameters(NULL, ctx->chain); X509_get_pubkey_parameters(NULL, ctx->chain);
if (matched > 0) { if (matched > 0) {
/* Callback invoked as needed */
if (!check_leaf_suiteb(ctx, cert)) if (!check_leaf_suiteb(ctx, cert))
return 0; return 0;
/* Bypass internal_verify(), issue depth 0 success callback */
ctx->error_depth = 0; ctx->error_depth = 0;
ctx->current_cert = cert; ctx->current_cert = cert;
return ctx->verify_cb(1, ctx); return ctx->verify_cb(1, ctx);
@@ -2714,10 +2646,7 @@ static int dane_verify(X509_STORE_CTX *ctx)
/* Fail early, TA-based success is not possible */ /* Fail early, TA-based success is not possible */
if (!check_leaf_suiteb(ctx, cert)) if (!check_leaf_suiteb(ctx, cert))
return 0; return 0;
ctx->current_cert = cert; return verify_cb_cert(ctx, cert, 0, X509_V_ERR_DANE_NO_MATCH);
ctx->error_depth = 0;
ctx->error = X509_V_ERR_DANE_NO_MATCH;
return ctx->verify_cb(0, ctx);
} }
/* /*
@@ -3021,25 +2950,27 @@ static int build_chain(X509_STORE_CTX *ctx)
case X509_TRUST_TRUSTED: case X509_TRUST_TRUSTED:
return 1; return 1;
case X509_TRUST_REJECTED: case X509_TRUST_REJECTED:
/* Callback already issued */
return 0; return 0;
case X509_TRUST_UNTRUSTED: case X509_TRUST_UNTRUSTED:
default: default:
num = sk_X509_num(ctx->chain); num = sk_X509_num(ctx->chain);
ctx->current_cert = sk_X509_value(ctx->chain, num - 1);
ctx->error_depth = num-1;
if (num > depth) if (num > depth)
ctx->error = X509_V_ERR_CERT_CHAIN_TOO_LONG; return verify_cb_cert(ctx, NULL, num-1,
else if (DANETLS_ENABLED(dane) && X509_V_ERR_CERT_CHAIN_TOO_LONG);
(!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0)) if (DANETLS_ENABLED(dane) &&
ctx->error = X509_V_ERR_DANE_NO_MATCH; (!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0))
else if (ss && sk_X509_num(ctx->chain) == 1) return verify_cb_cert(ctx, NULL, num-1, X509_V_ERR_DANE_NO_MATCH);
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; if (ss && sk_X509_num(ctx->chain) == 1)
else if (ss) return verify_cb_cert(ctx, NULL, num-1,
ctx->error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
else if (ctx->num_untrusted == num) if (ss)
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; return verify_cb_cert(ctx, NULL, num-1,
else X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; if (ctx->num_untrusted < num)
return ctx->verify_cb(0, ctx); return verify_cb_cert(ctx, NULL, num-1,
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT);
return verify_cb_cert(ctx, NULL, num-1,
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
} }
} }