Check chain extensions also for trusted certificates

This includes basic constraints, key usages, issuer EKUs and auxiliary
trust OIDs (given a trust suitably related to the intended purpose).

Added tests and updated documentation.

Reviewed-by: Dr. Stephen Henson <steve@openssl.org>
This commit is contained in:
Viktor Dukhovni 2016-01-28 03:01:45 -05:00
parent 1b4cf96f9b
commit 0daccd4dc1
15 changed files with 315 additions and 98 deletions

View File

@ -496,14 +496,25 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
X509_VERIFY_PARAM_add0_policy(vpm, otmp);
break;
case OPT_V_PURPOSE:
/* purpose name -> purpose index */
i = X509_PURPOSE_get_by_sname(opt_arg());
if (i < 0) {
BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg());
return 0;
}
/* purpose index -> purpose object */
xptmp = X509_PURPOSE_get0(i);
/* purpose object -> purpose value */
i = X509_PURPOSE_get_id(xptmp);
X509_VERIFY_PARAM_set_purpose(vpm, i);
if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) {
BIO_printf(bio_err,
"%s: Internal error setting purpose %s\n",
prog, opt_arg());
return 0;
}
break;
case OPT_V_VERIFY_NAME:
vtmp = X509_VERIFY_PARAM_lookup(opt_arg());

View File

@ -276,7 +276,7 @@ static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
static int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
{
if (x->aux)
if (x->aux && (x->aux->trust || x->aux->reject))
return obj_trust(trust->arg1, x, flags);
return X509_TRUST_UNTRUSTED;
}
@ -293,23 +293,26 @@ static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
static int obj_trust(int id, X509 *x, int flags)
{
ASN1_OBJECT *obj;
X509_CERT_AUX *ax = x->aux;
int i;
X509_CERT_AUX *ax;
ax = x->aux;
if (!ax)
return X509_TRUST_UNTRUSTED;
if (ax->reject) {
for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
obj = sk_ASN1_OBJECT_value(ax->reject, i);
if (OBJ_obj2nid(obj) == id)
ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->reject, i);
int nid = OBJ_obj2nid(obj);
if (nid == id || nid == NID_anyExtendedKeyUsage)
return X509_TRUST_REJECTED;
}
}
if (ax->trust) {
for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
obj = sk_ASN1_OBJECT_value(ax->trust, i);
if (OBJ_obj2nid(obj) == id)
ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->trust, i);
int nid = OBJ_obj2nid(obj);
if (nid == id || nid == NID_anyExtendedKeyUsage)
return X509_TRUST_TRUSTED;
}
/*

View File

@ -362,6 +362,48 @@ static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
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
@ -369,11 +411,12 @@ static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
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:
@ -402,8 +445,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
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)
@ -411,17 +453,15 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
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) {
@ -453,22 +493,12 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
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)
@ -477,9 +507,8 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
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))
@ -494,18 +523,15 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
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)
@ -2016,11 +2042,20 @@ void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk)
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);
}
@ -2054,6 +2089,11 @@ int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
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);
@ -2211,6 +2251,18 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509,
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;

View File

@ -133,7 +133,7 @@ static void x509_verify_param_zero(X509_VERIFY_PARAM *param)
return;
param->name = NULL;
param->purpose = 0;
param->trust = 0;
param->trust = X509_TRUST_DEFAULT;
/*
* param->inh_flags = X509_VP_FLAG_DEFAULT;
*/
@ -243,7 +243,7 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
to_overwrite = 0;
x509_verify_param_copy(purpose, 0);
x509_verify_param_copy(trust, 0);
x509_verify_param_copy(trust, X509_TRUST_DEFAULT);
x509_verify_param_copy(depth, -1);
/* If overwrite or check time not set, copy across */
@ -511,7 +511,7 @@ static const X509_VERIFY_PARAM default_table[] = {
"default", /* X509 default parameters */
0, /* Check time */
0, /* internal flags */
0, /* flags */
X509_V_FLAG_TRUSTED_FIRST, /* flags */
0, /* purpose */
0, /* trust */
100, /* depth */

View File

@ -198,14 +198,16 @@ When constructing the certificate chain, use the trusted certificates specified
via B<-CAfile>, B<-CApath> or B<-trusted> before any certificates specified via
B<-untrusted>.
This can be useful in environments with Bridge or Cross-Certified CAs.
As of OpenSSL 1.1.0 this option is on by default and cannot be disabled.
=item B<-no_alt_chains>
When building a certificate chain, if the first certificate chain found is not
trusted, then OpenSSL will continue to check to see if an alternative chain can
be found that is trusted. With this option that behaviour is suppressed so that
only the first chain found is ever used. Using this option will force the
behaviour to match that of OpenSSL versions prior to 1.1.0.
By default, unless B<-trusted_first> is specified, when building a certificate
chain, if the first certificate chain found is not trusted, then OpenSSL will
attempt to replace untrusted issuer certificates with certificates from the
trust store to see if an alternative chain can be found that is trusted.
As of OpenSSL 1.1.0, with B<-trusted_first> always on, this option has no
effect.
=item B<-untrusted file>
@ -264,13 +266,17 @@ the subject certificate.
Use default verification policies like trust model and required certificate
policies identified by B<name>.
The trust model determines which auxiliary trust or reject OIDs are applicable
to verifying the given certificate chain.
See the B<-addtrust> and B<-addreject> options of the L<x509(1)> command-line
utility.
Supported policy names include: B<default>, B<pkcs7>, B<smime_sign>,
B<ssl_client>, B<ssl_server>.
This checks not only the purpose of the leaf certificate, but also the
trust settings of the trusted CAs.
When in doubt, use this option rather than B<-purpose>.
The B<-verify_name> option more closely matches how certificates are checked in
e.g. SSL and S/MIME.
These mimics the combinations of purpose and trust settings used in SSL, CMS
and S/MIME.
As of OpenSSL 1.1.0, the trust model is inferred from the purpose when not
specified, so the B<-verify_name> options are functionally equivalent to the
corresponding B<-purpose> settings.
=item B<-x509_strict>

View File

@ -289,9 +289,12 @@ clears all the prohibited or rejected uses of the certificate.
=item B<-addtrust arg>
adds a trusted certificate use. Any object name can be used here
but currently only B<clientAuth> (SSL client use), B<serverAuth>
(SSL server use) and B<emailProtection> (S/MIME email) are used.
adds a trusted certificate use.
Any object name can be used here but currently only B<clientAuth> (SSL client
use), B<serverAuth> (SSL server use), B<emailProtection> (S/MIME email) and
B<anyExtendedKeyUsage> are used.
As of OpenSSL 1.1.0, the last of these blocks all purposes when rejected or
enables all purposes when trusted.
Other OpenSSL applications may define additional uses.
=item B<-addreject arg>

View File

@ -197,11 +197,20 @@ verification. If this flag is set then additional status codes will be sent
to the verification callback and it B<must> be prepared to handle such cases
without assuming they are hard errors.
If B<X509_V_FLAG_TRUSTED_FIRST> is set, when constructing the certificate chain,
L<X509_verify_cert(3)> will search the trust store for issuer certificates before
searching the provided untrusted certificates.
As of OpenSSL 1.1.0 this option is on by default and cannot be disabled.
The B<X509_V_FLAG_NO_ALT_CHAINS> flag suppresses checking for alternative
chains. By default, when building a certificate chain, if the first certificate
chain found is not trusted, then OpenSSL will continue to check to see if an
alternative chain can be found that is trusted. With this flag set the behaviour
will match that of OpenSSL versions prior to 1.1.0.
chains.
By default, unless B<X509_V_FLAG_TRUSTED_FIRST> is set, when building a
certificate chain, if the first certificate chain found is not trusted, then
OpenSSL will attempt to replace untrusted certificates supplied by the peer
with certificates from the trust store to see if an alternative chain can be
found that is trusted.
As of OpenSSL 1.1.0, with B<X509_V_FLAG_TRUSTED_FIRST> always set, this option
has no effect.
The B<X509_V_FLAG_NO_CHECK_TIME> flag suppresses checking the validity period
of certificates and CRLs against the current time. If X509_VERIFY_PARAM_set_time()

View File

@ -183,7 +183,7 @@ DEFINE_STACK_OF(X509_TRUST)
/* standard trust ids */
# define X509_TRUST_DEFAULT -1/* Only valid in purpose settings */
# define X509_TRUST_DEFAULT 0 /* Only valid in purpose settings */
# define X509_TRUST_COMPAT 1
# define X509_TRUST_SSL_CLIENT 2

View File

@ -0,0 +1,18 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
IENBMCAXDTE2MDExNTA4MTk0OVoYDzIxMTYwMTE2MDgxOTQ5WjASMRAwDgYDVQQD
DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4eYA9Qa8
oEY4eQ8/HnEZE20C3yubdmv8rLAh7daRCEI7pWM17FJboKJKxdYAlAOXWj25ZyjS
feMhXKTtxjyNjoTRnVTDPdl0opZ2Z3H5xhpQd7P9eO5b4OOMiSPCmiLsPtQ3ngfN
wCtVERc6NEIcaQ06GLDtFZRexv2eh8Yc55QaksBfBcFzQ+UD3gmRySTO2I6Lfi7g
MUjRhipqVSZ66As2Tpex4KTJ2lxpSwOACFaDox+yKrjBTP7FsU3UwAGq7b7OJb3u
aa32B81uK6GJVPVo65gJ7clgZsszYkoDsGjWDqtfwTVVfv1G7rrr3Laio+2Ff3ff
tWgiQ35mJCOvxQIDAQABo1AwTjAdBgNVHQ4EFgQUjvUlrx6ba4Q9fICayVOcTXL3
o1IwHwYDVR0jBBgwFoAUjvUlrx6ba4Q9fICayVOcTXL3o1IwDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEAyRRJx27WYOogPXZpPfAMt8ptapr/ugLWGLlw
bzKySoyLpoV2/YNAvTAGB90iFq6x/ujjrK41/ES0p3v38/Qfuxo24gcZgc/oYLV2
UqR+uGCx68p2OWLYctBsARtYWOEgPhHFb9aVxcOQKyZHtivDX0wLGX+nqZoHX9IY
mc0sbpRBRMzxRsChbzD5re9kZ5NrgkjA6DJ7jYh2GitOM6oIU3Dd9+pk3bCEkFUg
Ry9qN/k+AyeqH1Qcb5LU+MTmlw8bmyzmMOBZgdegtO4HshcBMO054KSB3WSfBPDO
bEhZ0vm/lw63TGi88yIMtlkmcU2g0RKpeQI96G6QeqHyKF3p8DAIMAYGBFUdJQA=
-----END TRUSTED CERTIFICATE-----

View File

@ -0,0 +1,18 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
IENBMCAXDTE2MDExNTA4MTk0OVoYDzIxMTYwMTE2MDgxOTQ5WjASMRAwDgYDVQQD
DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4eYA9Qa8
oEY4eQ8/HnEZE20C3yubdmv8rLAh7daRCEI7pWM17FJboKJKxdYAlAOXWj25ZyjS
feMhXKTtxjyNjoTRnVTDPdl0opZ2Z3H5xhpQd7P9eO5b4OOMiSPCmiLsPtQ3ngfN
wCtVERc6NEIcaQ06GLDtFZRexv2eh8Yc55QaksBfBcFzQ+UD3gmRySTO2I6Lfi7g
MUjRhipqVSZ66As2Tpex4KTJ2lxpSwOACFaDox+yKrjBTP7FsU3UwAGq7b7OJb3u
aa32B81uK6GJVPVo65gJ7clgZsszYkoDsGjWDqtfwTVVfv1G7rrr3Laio+2Ff3ff
tWgiQ35mJCOvxQIDAQABo1AwTjAdBgNVHQ4EFgQUjvUlrx6ba4Q9fICayVOcTXL3
o1IwHwYDVR0jBBgwFoAUjvUlrx6ba4Q9fICayVOcTXL3o1IwDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEAyRRJx27WYOogPXZpPfAMt8ptapr/ugLWGLlw
bzKySoyLpoV2/YNAvTAGB90iFq6x/ujjrK41/ES0p3v38/Qfuxo24gcZgc/oYLV2
UqR+uGCx68p2OWLYctBsARtYWOEgPhHFb9aVxcOQKyZHtivDX0wLGX+nqZoHX9IY
mc0sbpRBRMzxRsChbzD5re9kZ5NrgkjA6DJ7jYh2GitOM6oIU3Dd9+pk3bCEkFUg
Ry9qN/k+AyeqH1Qcb5LU+MTmlw8bmyzmMOBZgdegtO4HshcBMO054KSB3WSfBPDO
bEhZ0vm/lw63TGi88yIMtlkmcU2g0RKpeQI96G6QeqHyKF3p8DAIoAYGBFUdJQA=
-----END TRUSTED CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
IENBMCAXDTE2MDExNTA4MTk0OVoYDzIxMTYwMTE2MDgxOTQ5WjASMRAwDgYDVQQD
DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyB6dJAD5
wbStQf4HE0EhldtDShNVQ/jhDu6s2Ka30FdP4ml1+c2Py7ODUSjSCegXaBIOXCA+
R0zaBAJ3ZeqXx3UrE9PiXaHRGZcoPtX4mK9IOHhIdxwPUa6ceSOJn4cHY+p0cFLp
/5bnUErp4IqbL1bMd4v8fFxJ0ZDGJahfLiurnYUyalaNCHK+hK2+RaeRgPlsXfiU
/vwhhjFhdhixbPm8l+S+2xNySV1JAAzrUvEDdNZ0iBvuVcS2mlhSKTht5Zeg+0C6
7kYYqxM9CVZCwcV/aSUImwjeFsNMJsl/nFyEacu6vXz0rjvLwPzTAeVYZy592Gwv
akWOtiDdap7WJQIDAQABo1AwTjAdBgNVHQ4EFgQUnM5mQjCrHAgmX3MZbd8Pp65Y
Uh4wHwYDVR0jBBgwFoAUnM5mQjCrHAgmX3MZbd8Pp65YUh4wDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEADkH6+rUX2QD5TMBn8x4PR9mTQsxhD2k8K2bv
NpbsWX0ta2pDPhiBpIbrTrTmw656MMRkwMLYIAX7BFhyjO9gO0nVXfU1SSTDsso+
qu/K1t2US/rLeJQn8gYiTw6AqmvxHOndLaZQrYef4rUzsYnahNzxcoS1FMVxoJFM
o+1Wo0BFBlASv5Az0iFfjd1Uy3+AHB41+2vczNIWSki3mg4hzus2PSS4AA9IYeh+
zU/HJMddnVedLKNstTAfR85ftACtsP6JhBqCBqC4mCVsN2ZlgucETbsOMyWYB4+y
9b6JIYDA1wxNVBXwN+D4MyALxjmjwcTsL6pXgoVc0JEJWVqQ1zAMMAoGCCsGAQUF
BwMC
-----END TRUSTED CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
IENBMCAXDTE2MDExNTA4MTk0OVoYDzIxMTYwMTE2MDgxOTQ5WjASMRAwDgYDVQQD
DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyB6dJAD5
wbStQf4HE0EhldtDShNVQ/jhDu6s2Ka30FdP4ml1+c2Py7ODUSjSCegXaBIOXCA+
R0zaBAJ3ZeqXx3UrE9PiXaHRGZcoPtX4mK9IOHhIdxwPUa6ceSOJn4cHY+p0cFLp
/5bnUErp4IqbL1bMd4v8fFxJ0ZDGJahfLiurnYUyalaNCHK+hK2+RaeRgPlsXfiU
/vwhhjFhdhixbPm8l+S+2xNySV1JAAzrUvEDdNZ0iBvuVcS2mlhSKTht5Zeg+0C6
7kYYqxM9CVZCwcV/aSUImwjeFsNMJsl/nFyEacu6vXz0rjvLwPzTAeVYZy592Gwv
akWOtiDdap7WJQIDAQABo1AwTjAdBgNVHQ4EFgQUnM5mQjCrHAgmX3MZbd8Pp65Y
Uh4wHwYDVR0jBBgwFoAUnM5mQjCrHAgmX3MZbd8Pp65YUh4wDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEADkH6+rUX2QD5TMBn8x4PR9mTQsxhD2k8K2bv
NpbsWX0ta2pDPhiBpIbrTrTmw656MMRkwMLYIAX7BFhyjO9gO0nVXfU1SSTDsso+
qu/K1t2US/rLeJQn8gYiTw6AqmvxHOndLaZQrYef4rUzsYnahNzxcoS1FMVxoJFM
o+1Wo0BFBlASv5Az0iFfjd1Uy3+AHB41+2vczNIWSki3mg4hzus2PSS4AA9IYeh+
zU/HJMddnVedLKNstTAfR85ftACtsP6JhBqCBqC4mCVsN2ZlgucETbsOMyWYB4+y
9b6JIYDA1wxNVBXwN+D4MyALxjmjwcTsL6pXgoVc0JEJWVqQ1zAMMAoGCCsGAQUF
BwMB
-----END TRUSTED CERTIFICATE-----

View File

@ -0,0 +1,19 @@
-----BEGIN TRUSTED CERTIFICATE-----
MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
IENBMCAXDTE2MDExNTA4MTk0OVoYDzIxMTYwMTE2MDgxOTQ5WjASMRAwDgYDVQQD
DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyB6dJAD5
wbStQf4HE0EhldtDShNVQ/jhDu6s2Ka30FdP4ml1+c2Py7ODUSjSCegXaBIOXCA+
R0zaBAJ3ZeqXx3UrE9PiXaHRGZcoPtX4mK9IOHhIdxwPUa6ceSOJn4cHY+p0cFLp
/5bnUErp4IqbL1bMd4v8fFxJ0ZDGJahfLiurnYUyalaNCHK+hK2+RaeRgPlsXfiU
/vwhhjFhdhixbPm8l+S+2xNySV1JAAzrUvEDdNZ0iBvuVcS2mlhSKTht5Zeg+0C6
7kYYqxM9CVZCwcV/aSUImwjeFsNMJsl/nFyEacu6vXz0rjvLwPzTAeVYZy592Gwv
akWOtiDdap7WJQIDAQABo1AwTjAdBgNVHQ4EFgQUnM5mQjCrHAgmX3MZbd8Pp65Y
Uh4wHwYDVR0jBBgwFoAUnM5mQjCrHAgmX3MZbd8Pp65YUh4wDAYDVR0TBAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEADkH6+rUX2QD5TMBn8x4PR9mTQsxhD2k8K2bv
NpbsWX0ta2pDPhiBpIbrTrTmw656MMRkwMLYIAX7BFhyjO9gO0nVXfU1SSTDsso+
qu/K1t2US/rLeJQn8gYiTw6AqmvxHOndLaZQrYef4rUzsYnahNzxcoS1FMVxoJFM
o+1Wo0BFBlASv5Az0iFfjd1Uy3+AHB41+2vczNIWSki3mg4hzus2PSS4AA9IYeh+
zU/HJMddnVedLKNstTAfR85ftACtsP6JhBqCBqC4mCVsN2ZlgucETbsOMyWYB4+y
9b6JIYDA1wxNVBXwN+D4MyALxjmjwcTsL6pXgoVc0JEJWVqQ1zAMoAoGCCsGAQUF
BwMB
-----END TRUSTED CERTIFICATE-----

View File

@ -2,7 +2,7 @@
# Primary root: root-cert
# root certs variants: CA:false, key2, DN2
# trust variants: +serverAuth -serverAuth +clientAuth
# trust variants: +serverAuth -serverAuth +clientAuth +anyEKU -anyEKU
#
./mkcert.sh genroot "Root CA" root-key root-cert
./mkcert.sh genss "Root CA" root-key root-nonca
@ -15,6 +15,16 @@ openssl x509 -in root-cert.pem -trustout \
-addreject serverAuth -out root-serverAuth.pem
openssl x509 -in root-cert.pem -trustout \
-addtrust clientAuth -out root+clientAuth.pem
openssl x509 -in root-cert.pem -trustout \
-addreject anyExtendedKeyUsage -out root-anyEKU.pem
openssl x509 -in root-cert.pem -trustout \
-addtrust anyExtendedKeyUsage -out root+anyEKU.pem
openssl x509 -in root-cert2.pem -trustout \
-addtrust serverAuth -out root2+serverAuth.pem
openssl x509 -in root-cert2.pem -trustout \
-addreject serverAuth -out root2-serverAuth.pem
openssl x509 -in root-cert2.pem -trustout \
-addtrust clientAuth -out root2+clientAuth.pem
# Primary intermediate ca: ca-cert
# ca variants: CA:false, key2, DN2, issuer2, expired

View File

@ -9,80 +9,110 @@ use OpenSSL::Test qw/:DEFAULT top_file/;
setup("test_verify");
sub verify {
my ($cert, $vname, $trusted, $untrusted, @opts) = @_;
my @args = qw(openssl verify -verify_name);
my ($cert, $purpose, $trusted, $untrusted, @opts) = @_;
my @args = qw(openssl verify -purpose);
my @path = qw(test certs);
push(@args, "$vname", @opts);
push(@args, "$purpose", @opts);
for (@$trusted) { push(@args, "-trusted", top_file(@path, "$_.pem")) }
for (@$untrusted) { push(@args, "-untrusted", top_file(@path, "$_.pem")) }
push(@args, top_file(@path, "$cert.pem"));
run(app([@args]));
}
plan tests => 29;
plan tests => 38;
# Canonical success
ok(verify("ee-cert", "ssl_server", ["root-cert"], ["ca-cert"]),
ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]),
"verify valid chain");
# Root CA variants
ok(verify("ee-cert", "ssl_server", [qw(root-nonca)], [qw(ca-cert)]),
"Trusted certs not subject to CA:true checks");
ok(!verify("ee-cert", "ssl_server", [qw(root-cert2)], [qw(ca-cert)]),
ok(!verify("ee-cert", "sslserver", [qw(root-nonca)], [qw(ca-cert)]),
"Trusted CA certs now subject to CA:true checks");
ok(!verify("ee-cert", "sslserver", [qw(root-cert2)], [qw(ca-cert)]),
"fail wrong root key");
ok(!verify("ee-cert", "ssl_server", [qw(root-name2)], [qw(ca-cert)]),
ok(!verify("ee-cert", "sslserver", [qw(root-name2)], [qw(ca-cert)]),
"fail wrong root DN");
ok(verify("ee-cert", "ssl_server", [qw(root+serverAuth)], [qw(ca-cert)]),
ok(verify("ee-cert", "sslserver", [qw(root+serverAuth)], [qw(ca-cert)]),
"accept right EKU");
ok(!verify("ee-cert", "ssl_server", [qw(root-serverAuth)], [qw(ca-cert)]),
ok(verify("ee-cert", "sslserver", [qw(root+anyEKU)], [qw(ca-cert)]),
"accept anyEKU");
ok(!verify("ee-cert", "sslserver", [qw(root-serverAuth)], [qw(ca-cert)]),
"fail rejected EKU");
ok(!verify("ee-cert", "ssl_server", [qw(root+clientAuth)], [qw(ca-cert)]),
ok(!verify("ee-cert", "sslserver", [qw(root-anyEKU)], [qw(ca-cert)]),
"fail rejected anyEKU");
ok(!verify("ee-cert", "sslserver", [qw(root+clientAuth)], [qw(ca-cert)]),
"fail wrong EKU");
# Check that trusted-first is on by setting up paths to different roots
# depending on whether the intermediate is the trusted or untrusted one.
#
ok(verify("ee-cert", "sslserver", [qw(root-serverAuth root-cert2 ca-root2)],
[qw(ca-cert)]),
"verify trusted-first path");
ok(verify("ee-cert", "sslserver", [qw(root-cert root2+serverAuth ca-root2)],
[qw(ca-cert)]),
"verify trusted-first path right EKU");
ok(!verify("ee-cert", "sslserver", [qw(root-cert root2-serverAuth ca-root2)],
[qw(ca-cert)]),
"fail trusted-first path rejected EKU");
ok(!verify("ee-cert", "sslserver", [qw(root-cert root2+clientAuth ca-root2)],
[qw(ca-cert)]),
"fail trusted-first path wrong EKU");
# CA variants
ok(!verify("ee-cert", "ssl_server", [qw(root-cert)], [qw(ca-nonca)]),
ok(!verify("ee-cert", "sslserver", [qw(root-cert)], [qw(ca-nonca)]),
"fail non-CA");
ok(!verify("ee-cert", "ssl_server", [qw(root-cert)], [qw(ca-cert2)]),
ok(!verify("ee-cert", "sslserver", [qw(root-cert)], [qw(ca-cert2)]),
"fail wrong CA key");
ok(!verify("ee-cert", "ssl_server", [qw(root-cert)], [qw(ca-name2)]),
ok(!verify("ee-cert", "sslserver", [qw(root-cert)], [qw(ca-name2)]),
"fail wrong CA DN");
ok(!verify("ee-cert", "ssl_server", [qw(root-cert)], [qw(ca-root2)]),
ok(!verify("ee-cert", "sslserver", [qw(root-cert)], [qw(ca-root2)]),
"fail wrong CA issuer");
ok(!verify("ee-cert", "ssl_server", [], [qw(ca-cert)], "-partial_chain"),
ok(!verify("ee-cert", "sslserver", [], [qw(ca-cert)], "-partial_chain"),
"fail untrusted partial");
ok(!verify("ee-cert", "ssl_server", [], [qw(ca+serverAuth)], "-partial_chain"),
ok(!verify("ee-cert", "sslserver", [], [qw(ca+serverAuth)], "-partial_chain"),
"fail untrusted EKU partial");
ok(verify("ee-cert", "ssl_server", [qw(ca+serverAuth)], [], "-partial_chain"),
ok(verify("ee-cert", "sslserver", [qw(ca+serverAuth)], [], "-partial_chain"),
"accept trusted EKU partial");
ok(!verify("ee-cert", "ssl_server", [qw(ca-serverAuth)], [], "-partial_chain"),
ok(!verify("ee-cert", "sslserver", [qw(ca-serverAuth)], [], "-partial_chain"),
"fail rejected EKU partial");
ok(!verify("ee-cert", "ssl_server", [qw(ca+clientAuth)], [], "-partial_chain"),
ok(!verify("ee-cert", "sslserver", [qw(ca+clientAuth)], [], "-partial_chain"),
"fail wrong EKU partial");
# We now test auxiliary trust even for intermediate trusted certs without
# -partial_chain. Note that "-trusted_first" is now always on and cannot
# be disabled.
ok(verify("ee-cert", "sslserver", [qw(root-cert ca+serverAuth)], [qw(ca-cert)]),
"accept trusted EKU");
ok(!verify("ee-cert", "sslserver", [qw(root-cert ca-serverAuth)], [qw(ca-cert)]),
"fail rejected EKU");
ok(!verify("ee-cert", "sslserver", [qw(root-cert ca+clientAuth)], [qw(ca-cert)]),
"fail wrong EKU");
# EE variants
ok(verify("ee-client", "ssl_client", [qw(root-cert)], [qw(ca-cert)]),
ok(verify("ee-client", "sslclient", [qw(root-cert)], [qw(ca-cert)]),
"accept client cert");
ok(!verify("ee-client", "ssl_server", [qw(root-cert)], [qw(ca-cert)]),
ok(!verify("ee-client", "sslserver", [qw(root-cert)], [qw(ca-cert)]),
"fail wrong leaf purpose");
ok(!verify("ee-cert", "ssl_client", [qw(root-cert)], [qw(ca-cert)]),
ok(!verify("ee-cert", "sslclient", [qw(root-cert)], [qw(ca-cert)]),
"fail wrong leaf purpose");
ok(!verify("ee-cert2", "ssl_server", [qw(root-cert)], [qw(ca-cert)]),
ok(!verify("ee-cert2", "sslserver", [qw(root-cert)], [qw(ca-cert)]),
"fail wrong CA key");
ok(!verify("ee-name2", "ssl_server", [qw(root-cert)], [qw(ca-cert)]),
ok(!verify("ee-name2", "sslserver", [qw(root-cert)], [qw(ca-cert)]),
"fail wrong CA name");
ok(!verify("ee-expired", "ssl_server", [qw(root-cert)], [qw(ca-cert)]),
ok(!verify("ee-expired", "sslserver", [qw(root-cert)], [qw(ca-cert)]),
"fail expired leaf");
ok(verify("ee-cert", "ssl_server", [qw(ee-cert)], [], "-partial_chain"),
ok(verify("ee-cert", "sslserver", [qw(ee-cert)], [], "-partial_chain"),
"accept last-resort direct leaf match");
ok(verify("ee-client", "ssl_client", [qw(ee-client)], [], "-partial_chain"),
ok(verify("ee-client", "sslclient", [qw(ee-client)], [], "-partial_chain"),
"accept last-resort direct leaf match");
ok(!verify("ee-cert", "ssl_server", [qw(ee-client)], [], "-partial_chain"),
ok(!verify("ee-cert", "sslserver", [qw(ee-client)], [], "-partial_chain"),
"fail last-resort direct leaf non-match");
ok(verify("ee-cert", "ssl_server", [qw(ee+serverAuth)], [], "-partial_chain"),
ok(verify("ee-cert", "sslserver", [qw(ee+serverAuth)], [], "-partial_chain"),
"accept direct match with trusted EKU");
ok(!verify("ee-cert", "ssl_server", [qw(ee-serverAuth)], [], "-partial_chain"),
ok(!verify("ee-cert", "sslserver", [qw(ee-serverAuth)], [], "-partial_chain"),
"reject direct match with rejected EKU");
ok(verify("ee-client", "ssl_client", [qw(ee+clientAuth)], [], "-partial_chain"),
ok(verify("ee-client", "sslclient", [qw(ee+clientAuth)], [], "-partial_chain"),
"accept direct match with trusted EKU");
ok(!verify("ee-client", "ssl_client", [qw(ee-clientAuth)], [], "-partial_chain"),
ok(!verify("ee-client", "sslclient", [qw(ee-clientAuth)], [], "-partial_chain"),
"reject direct match with rejected EKU");