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 pu_ok = X509_check_purpose(x, purpose, must_be_ca > 0);
+ int tr_ok = X509_TRUST_UNTRUSTED;
+
+ /*
+ * For trusted certificates we want to see whether any auxiliary trust
+ * settings override the purpose constraints we failed to meet above.
+ *
+ * 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, or can be inferred from the purpose.
+ */
+ if (depth >= ctx->num_untrusted && purpose == ctx->param->purpose)
+ tr_ok = X509_check_trust(x, ctx->param->trust, X509_TRUST_NO_SS_COMPAT);
+
+ if (tr_ok != X509_TRUST_REJECTED &&
+ (pu_ok == 1 ||
+ (pu_ok != 0 && (ctx->param->flags & X509_V_FLAG_X509_STRICT) == 0)))
+ return 1;
+
+ 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 proxy_path_length = 0;
int purpose;
int allow_proxy_certs;
+ 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 = ctx->verify_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 = ctx->verify_cb(0, ctx);
- if (!ok)
- goto end;
+ if (!ctx->verify_cb(0, ctx))
+ return 0;
}
ret = X509_check_ca(x);
switch (must_be_ca) {
if (ret == 0) {
ctx->error_depth = i;
ctx->current_cert = x;
- ok = ctx->verify_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 = ctx->verify_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 = ctx->verify_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 = ctx->verify_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 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);
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;