-/* crypto/x509/x509_vfy.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
static int verify_chain(X509_STORE_CTX *ctx)
{
- int (*cb) (int xok, X509_STORE_CTX *xctx) = ctx->verify_cb;
int err;
int ok;
if (err != X509_V_OK) {
ctx->error = err;
ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth);
- if ((ok = cb(0, ctx)) == 0)
+ if ((ok = ctx->verify_cb(0, ctx)) == 0)
return ok;
}
}
}
- if (ret == X509_V_OK)
- return 1;
- /* If we haven't asked for issuer errors don't set ctx */
- if (!(ctx->param->flags & X509_V_FLAG_CB_ISSUER_CHECK))
- return 0;
-
- ctx->error = ret;
- ctx->current_cert = x;
- ctx->current_issuer = issuer;
- return ctx->verify_cb(0, ctx);
+ return (ret == X509_V_OK);
}
/* Alternative lookup method: look from a STACK stored in other_ctx */
return 0;
}
+static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
+{
+ STACK_OF(X509) *sk = NULL;
+ X509 *x;
+ int i;
+ for (i = 0; i < sk_X509_num(ctx->other_ctx); i++) {
+ x = sk_X509_value(ctx->other_ctx, i);
+ if (X509_NAME_cmp(nm, X509_get_subject_name(x)) == 0) {
+ if (sk == NULL)
+ sk = sk_X509_new_null();
+ if (sk == NULL || sk_X509_push(sk, x) == 0) {
+ sk_X509_pop_free(sk, X509_free);
+ return NULL;
+ }
+ X509_up_ref(x);
+ }
+ }
+ return sk;
+}
+
+/*
+ * Check EE or CA certificate purpose. For trusted certificates explicit local
+ * auxiliary trust can be used to override EKU-restrictions.
+ */
+static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth,
+ int must_be_ca)
+{
+ int tr_ok = X509_TRUST_UNTRUSTED;
+
+ /*
+ * For trusted certificates we want to see whether any auxiliary trust
+ * settings trump the purpose constraints.
+ *
+ * This is complicated by the fact that the trust ordinals in
+ * ctx->param->trust are entirely independent of the purpose ordinals in
+ * ctx->param->purpose!
+ *
+ * What connects them is their mutual initialization via calls from
+ * X509_STORE_CTX_set_default() into X509_VERIFY_PARAM_lookup() which sets
+ * related values of both param->trust and param->purpose. It is however
+ * typically possible to infer associated trust values from a purpose value
+ * via the X509_PURPOSE API.
+ *
+ * Therefore, we can only check for trust overrides when the purpose we're
+ * checking is the same as ctx->param->purpose and ctx->param->trust is
+ * also set.
+ */
+ if (depth >= ctx->num_untrusted && purpose == ctx->param->purpose)
+ tr_ok = X509_check_trust(x, ctx->param->trust, X509_TRUST_NO_SS_COMPAT);
+
+ switch (tr_ok) {
+ case X509_TRUST_TRUSTED:
+ return 1;
+ case X509_TRUST_REJECTED:
+ break;
+ default:
+ switch (X509_check_purpose(x, purpose, must_be_ca > 0)) {
+ case 1:
+ return 1;
+ case 0:
+ break;
+ default:
+ if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) == 0)
+ return 1;
+ }
+ break;
+ }
+
+ ctx->error = X509_V_ERR_INVALID_PURPOSE;
+ ctx->error_depth = depth;
+ ctx->current_cert = x;
+ return ctx->verify_cb(0, ctx);
+}
+
/*
* Check a certificate chains extensions for consistency with the supplied
* purpose
static int check_chain_extensions(X509_STORE_CTX *ctx)
{
- int i, ok = 0, must_be_ca, plen = 0;
+ int i, must_be_ca, plen = 0;
X509 *x;
- int (*cb) (int xok, X509_STORE_CTX *xctx);
int proxy_path_length = 0;
int purpose;
int allow_proxy_certs;
- cb = ctx->verify_cb;
+ int num = sk_X509_num(ctx->chain);
/*-
* must_be_ca can have 1 of 3 values:
purpose = ctx->param->purpose;
}
- /* Check all untrusted certificates */
- for (i = 0; i == 0 || i < ctx->num_untrusted; i++) {
+ for (i = 0; i < num; i++) {
int ret;
x = sk_X509_value(ctx->chain, i);
if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL)
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
ctx->error_depth = i;
ctx->current_cert = x;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
}
if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) {
ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
ctx->error_depth = i;
ctx->current_cert = x;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
}
ret = X509_check_ca(x);
switch (must_be_ca) {
ret = 1;
break;
default:
+ /* X509_V_FLAG_X509_STRICT is implicit for intermediate CAs */
if ((ret == 0)
- || ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
+ || ((i + 1 < num || ctx->param->flags & X509_V_FLAG_X509_STRICT)
&& (ret != 1))) {
ret = 0;
ctx->error = X509_V_ERR_INVALID_CA;
if (ret == 0) {
ctx->error_depth = i;
ctx->current_cert = x;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
}
- if (ctx->param->purpose > 0) {
- ret = X509_check_purpose(x, purpose, must_be_ca > 0);
- if ((ret == 0)
- || ((ctx->param->flags & X509_V_FLAG_X509_STRICT)
- && (ret != 1))) {
- ctx->error = X509_V_ERR_INVALID_PURPOSE;
- ctx->error_depth = i;
- ctx->current_cert = x;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
- }
+ if (purpose > 0) {
+ if (!check_purpose(ctx, x, purpose, i, must_be_ca))
+ return 0;
}
/* Check pathlen if not self issued */
if ((i > 1) && !(x->ex_flags & EXFLAG_SI)
ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED;
ctx->error_depth = i;
ctx->current_cert = x;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
}
/* Increment path length if not self issued */
if (!(x->ex_flags & EXFLAG_SI))
ctx->error = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
ctx->error_depth = i;
ctx->current_cert = x;
- ok = cb(0, ctx);
- if (!ok)
- goto end;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
}
proxy_path_length++;
must_be_ca = 0;
} else
must_be_ca = 1;
}
- ok = 1;
- end:
- return ok;
+ return 1;
}
static int check_name_constraints(X509_STORE_CTX *ctx)
int i, ok = 0;
X509 *x = NULL;
X509 *mx;
- int (*cb) (int xok, X509_STORE_CTX *xctx) = ctx->verify_cb;
struct dane_st *dane = (struct dane_st *)ctx->dane;
int num = sk_X509_num(ctx->chain);
int trust;
- if (DANETLS_HAS_TA(dane) && num_untrusted > 0) {
+ /*
+ * Check for a DANE issuer at depth 1 or greater, if it is a DANE-TA(2)
+ * match, we're done, otherwise we'll merely record the match depth.
+ */
+ if (DANETLS_HAS_TA(dane) && num_untrusted > 0 && num_untrusted < num) {
switch (trust = check_dane_issuer(ctx, num_untrusted)) {
case X509_TRUST_TRUSTED:
case X509_TRUST_REJECTED:
return X509_TRUST_UNTRUSTED;
}
- if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
+ if (num_untrusted == num && ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
/*
* Last-resort call with no new trusted certificates, check the leaf
* for a direct trust store match.
*/
- x = sk_X509_value(ctx->chain, 0);
+ i = 0;
+ x = sk_X509_value(ctx->chain, i);
mx = lookup_cert_match(ctx, x);
if (!mx)
return X509_TRUST_UNTRUSTED;
ctx->error_depth = i;
ctx->current_cert = x;
ctx->error = X509_V_ERR_CERT_REJECTED;
- ok = cb(0, ctx);
+ ok = ctx->verify_cb(0, ctx);
if (!ok)
return X509_TRUST_REJECTED;
return X509_TRUST_UNTRUSTED;
static int check_policy(X509_STORE_CTX *ctx)
{
int ret;
+
if (ctx->parent)
return 1;
+ /*
+ * With DANE, the trust anchor might be a bare public key, not a
+ * certificate! In that case our chain does not have the trust anchor
+ * certificate as a top-most element. This comports well with RFC5280
+ * chain verification, since there too, the trust anchor is not part of the
+ * chain to be verified. In particular, X509_policy_check() does not look
+ * at the TA cert, but assumes that it is present as the top-most chain
+ * element. We therefore temporarily push a NULL cert onto the chain if it
+ * was verified via a bare public key, and pop it off right after the
+ * X509_policy_check() call.
+ */
+ if (ctx->bare_ta_signed && !sk_X509_push(ctx->chain, NULL)) {
+ X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain,
ctx->param->policies, ctx->param->flags);
- if (ret == 0) {
+ if (ctx->bare_ta_signed)
+ sk_X509_pop(ctx->chain);
+
+ if (ret == X509_PCY_TREE_INTERNAL) {
X509err(X509_F_CHECK_POLICY, ERR_R_MALLOC_FAILURE);
return 0;
}
/* Invalid or inconsistent extensions */
- if (ret == -1) {
+ if (ret == X509_PCY_TREE_INVALID) {
/*
* Locate certificates with bad extensions and notify callback.
*/
}
return 1;
}
- if (ret == -2) {
+ if (ret == X509_PCY_TREE_FAILURE) {
ctx->current_cert = NULL;
ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY;
return ctx->verify_cb(0, ctx);
}
+ if (ret != X509_PCY_TREE_VALID) {
+ X509err(X509_F_CHECK_POLICY, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) {
ctx->current_cert = NULL;
int ok = 0, n;
X509 *xs, *xi;
EVP_PKEY *pkey = NULL;
- int (*cb) (int xok, X509_STORE_CTX *xctx);
-
- cb = ctx->verify_cb;
n = sk_X509_num(ctx->chain) - 1;
ctx->error_depth = n;
if (n <= 0) {
ctx->error = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
ctx->current_cert = xi;
- ok = cb(0, ctx);
+ ok = ctx->verify_cb(0, ctx);
goto end;
} else {
n--;
* explicitly asked for. It doesn't add any security and just wastes
* time.
*/
- if (!xs->valid
- && (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) {
ctx->error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
ctx->current_cert = xi;
- ok = (*cb) (0, ctx);
+ ok = ctx->verify_cb(0, ctx);
if (!ok)
goto end;
} else if (X509_verify(xs, pkey) <= 0) {
ctx->error = X509_V_ERR_CERT_SIGNATURE_FAILURE;
ctx->current_cert = xs;
- ok = (*cb) (0, ctx);
+ ok = ctx->verify_cb(0, ctx);
if (!ok)
goto end;
}
}
- xs->valid = 1;
-
check_cert:
ok = x509_check_cert_time(ctx, xs, 0);
if (!ok)
/* The last error (if any) is still in the error value */
ctx->current_issuer = xi;
ctx->current_cert = xs;
- ok = (*cb) (1, ctx);
+ ok = ctx->verify_cb(1, ctx);
if (!ok)
goto end;
int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose)
{
+ /*
+ * XXX: Why isn't this function always used to set the associated trust?
+ * Should there even be a VPM->trust field at all? Or should the trust
+ * always be inferred from the purpose by X509_STORE_CTX_init().
+ */
return X509_STORE_CTX_purpose_inherit(ctx, 0, purpose, 0);
}
int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust)
{
+ /*
+ * XXX: See above, this function would only be needed when the default
+ * trust for the purpose needs an override in a corner case.
+ */
return X509_STORE_CTX_purpose_inherit(ctx, 0, 0, trust);
}
ptmp = X509_PURPOSE_get0(idx);
if (ptmp->trust == X509_TRUST_DEFAULT) {
idx = X509_PURPOSE_get_by_id(def_purpose);
+ /*
+ * XXX: In the two callers above def_purpose is always 0, which is
+ * not a known value, so idx will always be -1. How is the
+ * X509_TRUST_DEFAULT case actually supposed to be handled?
+ */
if (idx == -1) {
X509err(X509_F_X509_STORE_CTX_PURPOSE_INHERIT,
X509_R_UNKNOWN_PURPOSE_ID);
void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
{
- if (!ctx)
+ if (ctx == NULL)
return;
+
X509_STORE_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
if (store && store->get_crl)
ctx->get_crl = store->get_crl;
+ else
+ ctx->get_crl = NULL;
if (store && store->check_crl)
ctx->check_crl = store->check_crl;
goto err;
}
+ /*
+ * XXX: For now, continue to inherit trust from VPM, but infer from the
+ * purpose if this still yields the default value.
+ */
+ if (ctx->param->trust == X509_TRUST_DEFAULT) {
+ int idx = X509_PURPOSE_get_by_id(ctx->param->purpose);
+ X509_PURPOSE *xp = X509_PURPOSE_get0(idx);
+
+ if (xp != NULL)
+ ctx->param->trust = X509_PURPOSE_get_trust(xp);
+ }
+
if (CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509_STORE_CTX, ctx,
&ctx->ex_data))
return 1;
{
ctx->other_ctx = sk;
ctx->get_issuer = get_issuer_sk;
+ ctx->lookup_certs = lookup_certs_sk;
}
void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
/*
* If we've previously matched a PKIX-?? record, no need to test any
- * furher PKIX-?? records, it remains to just build the PKIX chain.
+ * further PKIX-?? records, it remains to just build the PKIX chain.
* Had the match been a DANE-?? record, we'd be done already.
*/
if (dane->mdpth >= 0)
*
* As soon as we find a match at any given depth, we stop, because either
* we've matched a DANE-?? record and the peer is authenticated, or, after
- * exhausing all DANE-?? records, we've matched a PKIX-?? record, which is
+ * exhausting all DANE-?? records, we've matched a PKIX-?? record, which is
* sufficient for DANE, and what remains to do is ordinary PKIX validation.
*/
recnum = (dane->umask & mask) ? sk_danetls_record_num(dane->trecs) : 0;
return X509_TRUST_UNTRUSTED;
/*
- * Record any DANE trust anchor matches, for the first depth to test, if
+ * Record any DANE trust-anchor matches, for the first depth to test, if
* there's one at that depth. (This'll be false for length 1 chains looking
* for an exact match for the leaf certificate).
*/
X509_verify(cert, t->spki) <= 0)
continue;
- /* Clear PKIX-?? matches that failed to panned out to a full chain */
+ /* Clear any PKIX-?? matches that failed to extend to a full chain */
X509_free(dane->mcert);
dane->mcert = NULL;
dane->pdpth = -1;
}
+static int check_leaf_suiteb(X509_STORE_CTX *ctx, X509 *cert)
+{
+ int err = X509_chain_check_suiteb(NULL, cert, NULL, ctx->param->flags);
+
+ if (err == X509_V_OK)
+ return 1;
+ ctx->current_cert = cert;
+ ctx->error_depth = 0;
+ ctx->error = err;
+ return ctx->verify_cb(0, ctx);
+}
+
static int dane_verify(X509_STORE_CTX *ctx)
{
X509 *cert = ctx->cert;
- int (*cb)(int xok, X509_STORE_CTX *xctx) = ctx->verify_cb;
struct dane_st *dane = (struct dane_st *)ctx->dane;
int matched;
int done;
dane_reset(dane);
+ /*-
+ * When testing the leaf certificate, if we match a DANE-EE(3) record,
+ * dane_match() returns 1 and we're done. If however we match a PKIX-EE(1)
+ * record, the match depth and matching TLSA record are recorded, but the
+ * return value is 0, because we still need to find a PKIX trust-anchor.
+ * Therefore, when DANE authentication is enabled (required), we're done
+ * if:
+ * + matched < 0, internal error.
+ * + matched == 1, we matched a DANE-EE(3) record
+ * + matched == 0, mdepth < 0 (no PKIX-EE match) and there are no
+ * DANE-TA(2) or PKIX-TA(0) to test.
+ */
matched = dane_match(ctx, ctx->cert, 0);
done = matched != 0 || (!DANETLS_HAS_TA(dane) && dane->mdpth < 0);
X509_get_pubkey_parameters(NULL, ctx->chain);
if (matched > 0) {
+ if (!check_leaf_suiteb(ctx, cert))
+ return 0;
ctx->error_depth = 0;
ctx->current_cert = cert;
- return cb(1, ctx);
+ return ctx->verify_cb(1, ctx);
}
if (matched < 0) {
if (done) {
/* Fail early, TA-based success is not possible */
+ if (!check_leaf_suiteb(ctx, cert))
+ return 0;
ctx->current_cert = cert;
ctx->error_depth = 0;
- ctx->error = X509_V_ERR_CERT_UNTRUSTED;
- return cb(0, ctx);
+ ctx->error = X509_V_ERR_DANE_NO_MATCH;
+ return ctx->verify_cb(0, ctx);
}
/*
static int build_chain(X509_STORE_CTX *ctx)
{
struct dane_st *dane = (struct dane_st *)ctx->dane;
- int (*cb) (int, X509_STORE_CTX *) = ctx->verify_cb;
int num = sk_X509_num(ctx->chain);
X509 *cert = sk_X509_value(ctx->chain, num - 1);
int ss = cert_self_signed(cert);
* Last chance to make a trusted chain, either bare DANE-TA public-key
* signers, or else direct leaf PKIX trust.
*/
- if (sk_X509_num(ctx->chain) <= depth) {
+ num = sk_X509_num(ctx->chain);
+ if (num <= depth) {
if (trust == X509_TRUST_UNTRUSTED && DANETLS_HAS_DANE_TA(dane))
trust = check_dane_pkeys(ctx);
- if (trust == X509_TRUST_UNTRUSTED &&
- sk_X509_num(ctx->chain) == ctx->num_untrusted)
- trust = check_trust(ctx, 1);
+ if (trust == X509_TRUST_UNTRUSTED && num == ctx->num_untrusted)
+ trust = check_trust(ctx, num);
}
switch (trust) {
ctx->error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
else if (DANETLS_ENABLED(dane) &&
(!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0))
- ctx->error = X509_V_ERR_CERT_UNTRUSTED;
+ ctx->error = X509_V_ERR_DANE_NO_MATCH;
else if (ss && sk_X509_num(ctx->chain) == 1)
ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
else if (ss)
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
else
ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
- if (DANETLS_ENABLED(dane))
- dane_reset(dane);
- return cb(0, ctx);
+ return ctx->verify_cb(0, ctx);
}
}