aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/apps.h8
-rw-r--r--apps/opt.c5
-rw-r--r--crypto/x509/x509_lcl.h1
-rw-r--r--crypto/x509/x509_txt.c6
-rw-r--r--crypto/x509/x509_vfy.c160
-rw-r--r--crypto/x509/x509_vpm.c17
-rw-r--r--doc/apps/cms.pod5
-rw-r--r--doc/apps/ocsp.pod7
-rw-r--r--doc/apps/s_client.pod5
-rw-r--r--doc/apps/s_server.pod5
-rw-r--r--doc/apps/smime.pod5
-rw-r--r--doc/apps/ts.pod21
-rw-r--r--doc/apps/verify.pod24
-rw-r--r--doc/crypto/X509_VERIFY_PARAM_set_flags.pod42
-rw-r--r--include/openssl/x509_vfy.h7
-rw-r--r--ssl/ssl_cert.c25
-rw-r--r--test/certs/ca-cert-768.pem15
-rw-r--r--test/certs/ca-cert-768i.pem15
-rw-r--r--test/certs/ca-cert-md5-any.pem18
-rw-r--r--test/certs/ca-cert-md5.pem18
-rw-r--r--test/certs/ca-key-768.pem13
-rw-r--r--test/certs/ee-cert-768.pem16
-rw-r--r--test/certs/ee-cert-768i.pem16
-rw-r--r--test/certs/ee-cert-md5.pem19
-rw-r--r--test/certs/ee-key-768.pem13
-rwxr-xr-xtest/certs/mkcert.sh10
-rw-r--r--test/certs/root-cert-768.pem11
-rw-r--r--test/certs/root-cert-md5.pem18
-rw-r--r--test/certs/root-key-768.pem13
-rwxr-xr-xtest/certs/setup.sh30
-rw-r--r--test/recipes/25-test_verify.t48
31 files changed, 543 insertions, 73 deletions
diff --git a/apps/apps.h b/apps/apps.h
index 434ca54b7d..a310dd2b78 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -180,6 +180,7 @@ void wait_for_async(SSL *s);
OPT_V_POLICY_PRINT, OPT_V_CHECK_SS_SIG, OPT_V_TRUSTED_FIRST, \
OPT_V_SUITEB_128_ONLY, OPT_V_SUITEB_128, OPT_V_SUITEB_192, \
OPT_V_PARTIAL_CHAIN, OPT_V_NO_ALT_CHAINS, OPT_V_NO_CHECK_TIME, \
+ OPT_V_VERIFY_AUTH_LEVEL, \
OPT_V__LAST
# define OPT_V_OPTIONS \
@@ -187,8 +188,10 @@ void wait_for_async(SSL *s);
{ "purpose", OPT_V_PURPOSE, 's', \
"certificate chain purpose"}, \
{ "verify_name", OPT_V_VERIFY_NAME, 's', "verification policy name"}, \
- { "verify_depth", OPT_V_VERIFY_DEPTH, 'p', \
- "chain depth limit"}, \
+ { "verify_depth", OPT_V_VERIFY_DEPTH, 'n', \
+ "chain depth limit" }, \
+ { "auth_level", OPT_V_VERIFY_AUTH_LEVEL, 'n', \
+ "chain authentication security level" }, \
{ "attime", OPT_V_ATTIME, 'M', "verification epoch time" }, \
{ "verify_hostname", OPT_V_VERIFY_HOSTNAME, 's', \
"expected peer hostname" }, \
@@ -235,6 +238,7 @@ void wait_for_async(SSL *s);
case OPT_V_PURPOSE: \
case OPT_V_VERIFY_NAME: \
case OPT_V_VERIFY_DEPTH: \
+ case OPT_V_VERIFY_AUTH_LEVEL: \
case OPT_V_ATTIME: \
case OPT_V_VERIFY_HOSTNAME: \
case OPT_V_VERIFY_EMAIL: \
diff --git a/apps/opt.c b/apps/opt.c
index af994bb743..462894a938 100644
--- a/apps/opt.c
+++ b/apps/opt.c
@@ -526,6 +526,11 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
if (i >= 0)
X509_VERIFY_PARAM_set_depth(vpm, i);
break;
+ case OPT_V_VERIFY_AUTH_LEVEL:
+ i = atoi(opt_arg());
+ if (i >= 0)
+ X509_VERIFY_PARAM_set_auth_level(vpm, i);
+ break;
case OPT_V_ATTIME:
if (!opt_imax(opt_arg(), &t))
return 0;
diff --git a/crypto/x509/x509_lcl.h b/crypto/x509/x509_lcl.h
index 0726201e8f..603c17737f 100644
--- a/crypto/x509/x509_lcl.h
+++ b/crypto/x509/x509_lcl.h
@@ -70,6 +70,7 @@ struct X509_VERIFY_PARAM_st {
int purpose; /* purpose to check untrusted certificates */
int trust; /* trust setting to check */
int depth; /* Verify depth */
+ int auth_level; /* Security level for chain verification */
STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */
/* Peer identity details */
STACK_OF(OPENSSL_STRING) *hosts; /* Set of acceptable names */
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
index f7f27e97ef..8a9a7f0444 100644
--- a/crypto/x509/x509_txt.c
+++ b/crypto/x509/x509_txt.c
@@ -203,6 +203,12 @@ const char *X509_verify_cert_error_string(long n)
return ("IP address mismatch");
case X509_V_ERR_DANE_NO_MATCH:
return ("No matching DANE TLSA records");
+ case X509_V_ERR_EE_KEY_TOO_SMALL:
+ return ("EE certificate key too weak");
+ case X509_V_ERR_CA_KEY_TOO_SMALL:
+ return ("CA certificate key too weak");
+ case X509_V_ERR_CA_MD_TOO_WEAK:
+ return ("CA signature digest algorithm too weak");
default:
/* Printing an error number into a static buffer is not thread-safe */
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 92f1c5c447..10fbeeff6d 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -126,6 +126,8 @@ static int check_cert(X509_STORE_CTX *ctx);
static int check_policy(X509_STORE_CTX *ctx);
static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
static int check_dane_issuer(X509_STORE_CTX *ctx, int depth);
+static int check_key_level(X509_STORE_CTX *ctx, X509 *cert);
+static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert);
static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer,
unsigned int *preasons, X509_CRL *crl, X509 *x);
@@ -221,6 +223,35 @@ static int verify_cb_crl(X509_STORE_CTX *ctx, int err)
return ctx->verify_cb(0, ctx);
}
+static int check_auth_level(X509_STORE_CTX *ctx)
+{
+ int i;
+ int num = sk_X509_num(ctx->chain);
+
+ if (ctx->param->auth_level <= 0)
+ return 1;
+
+ for (i = 0; i < num; ++i) {
+ X509 *cert = sk_X509_value(ctx->chain, i);
+
+ /*
+ * We've already checked the security of the leaf key, so here we only
+ * check the security of issuer keys.
+ */
+ if (i > 0 && !check_key_level(ctx, cert) &&
+ verify_cb_cert(ctx, cert, i, X509_V_ERR_CA_KEY_TOO_SMALL) == 0)
+ return 0;
+ /*
+ * We also check the signature algorithm security of all certificates
+ * except those of the trust anchor at index num-1.
+ */
+ if (i < num - 1 && !check_sig_level(ctx, cert) &&
+ verify_cb_cert(ctx, cert, i, X509_V_ERR_CA_MD_TOO_WEAK) == 0)
+ return 0;
+ }
+ return 1;
+}
+
static int verify_chain(X509_STORE_CTX *ctx)
{
int err;
@@ -232,6 +263,7 @@ static int verify_chain(X509_STORE_CTX *ctx)
*/
if ((ok = build_chain(ctx)) == 0 ||
(ok = check_chain_extensions(ctx)) == 0 ||
+ (ok = check_auth_level(ctx)) == 0 ||
(ok = check_name_constraints(ctx)) == 0 ||
(ok = check_id(ctx)) == 0 || 1)
X509_get_pubkey_parameters(NULL, ctx->chain);
@@ -294,6 +326,11 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
X509_up_ref(ctx->cert);
ctx->num_untrusted = 1;
+ /* If the peer's public key is too weak, we can stop early. */
+ if (!check_key_level(ctx, ctx->cert) &&
+ !verify_cb_cert(ctx, ctx->cert, 0, X509_V_ERR_EE_KEY_TOO_SMALL))
+ return 0;
+
/*
* If dane->trecs is an empty stack, we'll fail, since the user enabled
* DANE. If none of the TLSA records were usable, and it makes sense to
@@ -308,20 +345,19 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
/*
* Given a STACK_OF(X509) find the issuer of cert (if any)
*/
-
static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x)
{
int i;
- X509 *issuer, *rv = NULL;;
+
for (i = 0; i < sk_X509_num(sk); i++) {
- issuer = sk_X509_value(sk, i);
- if (ctx->check_issued(ctx, x, issuer)) {
- rv = issuer;
- if (x509_check_cert_time(ctx, rv, -1))
- break;
- }
+ X509 *issuer = sk_X509_value(sk, i);
+
+ if (!ctx->check_issued(ctx, x, issuer))
+ continue;
+ if (x509_check_cert_time(ctx, issuer, -1))
+ return issuer;
}
- return rv;
+ return NULL;
}
/* Given a possible certificate and issuer check them */
@@ -2656,6 +2692,19 @@ static int dane_verify(X509_STORE_CTX *ctx)
return verify_chain(ctx);
}
+/* Get issuer, without duplicate suppression */
+static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *cert)
+{
+ STACK_OF(X509) *saved_chain = ctx->chain;
+ int ok;
+
+ ctx->chain = NULL;
+ ok = ctx->get_issuer(issuer, ctx, cert);
+ ctx->chain = saved_chain;
+
+ return ok;
+}
+
static int build_chain(X509_STORE_CTX *ctx)
{
struct dane_st *dane = (struct dane_st *)ctx->dane;
@@ -2735,12 +2784,19 @@ static int build_chain(X509_STORE_CTX *ctx)
/*
* Look in the trust store if enabled for first lookup, or we've run
- * out of untrusted issuers and search here is not disabled. When
- * we exceed the depth limit, we simulate absence of a match.
+ * out of untrusted issuers and search here is not disabled. When we
+ * reach the depth limit, we stop extending the chain, if by that point
+ * we've not found a trust-anchor, any trusted chain would be too long.
+ *
+ * The error reported to the application verify callback is at the
+ * maximal valid depth with the current certificate equal to the last
+ * not ultimately-trusted issuer. For example, with verify_depth = 0,
+ * the callback will report errors at depth=1 when the immediate issuer
+ * of the leaf certificate is not a trust anchor. No attempt will be
+ * made to locate an issuer for that certificate, since such a chain
+ * would be a-priori too long.
*/
if ((search & S_DOTRUSTED) != 0) {
- STACK_OF(X509) *hide = ctx->chain;
-
i = num = sk_X509_num(ctx->chain);
if ((search & S_DOALTERNATE) != 0) {
/*
@@ -2762,10 +2818,7 @@ static int build_chain(X509_STORE_CTX *ctx)
}
x = sk_X509_value(ctx->chain, i-1);
- /* Suppress duplicate suppression */
- ctx->chain = NULL;
- ok = (depth < num) ? 0 : ctx->get_issuer(&xtmp, ctx, x);
- ctx->chain = hide;
+ ok = (depth < num) ? 0 : get_issuer(&xtmp, ctx, x);
if (ok < 0) {
trust = X509_TRUST_REJECTED;
@@ -2892,12 +2945,12 @@ static int build_chain(X509_STORE_CTX *ctx)
num = sk_X509_num(ctx->chain);
OPENSSL_assert(num == ctx->num_untrusted);
x = sk_X509_value(ctx->chain, num-1);
- xtmp = (depth < num) ? NULL : find_issuer(ctx, sktmp, x);
/*
* Once we run out of untrusted issuers, we stop looking for more
* and start looking only in the trust store if enabled.
*/
+ xtmp = (ss || depth < num) ? NULL : find_issuer(ctx, sktmp, x);
if (xtmp == NULL) {
search &= ~S_DOUNTRUSTED;
if (may_trusted)
@@ -2905,23 +2958,21 @@ static int build_chain(X509_STORE_CTX *ctx)
continue;
}
- if (!sk_X509_push(ctx->chain, x = xtmp)) {
+ /* Drop this issuer from future consideration */
+ (void) sk_X509_delete_ptr(sktmp, xtmp);
+
+ if (!sk_X509_push(ctx->chain, xtmp)) {
X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE);
trust = X509_TRUST_REJECTED;
search = 0;
continue;
}
- X509_up_ref(x);
+
+ X509_up_ref(x = xtmp);
++ctx->num_untrusted;
ss = cert_self_signed(xtmp);
/*
- * Not strictly necessary, but saves cycles looking at the same
- * certificates over and over.
- */
- (void) sk_X509_delete_ptr(sktmp, x);
-
- /*
* Check for DANE-TA trust of the topmost untrusted certificate.
*/
switch (trust = check_dane_issuer(ctx, ctx->num_untrusted - 1)) {
@@ -2974,3 +3025,60 @@ static int build_chain(X509_STORE_CTX *ctx)
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
}
}
+
+static const int minbits_table[] = { 80, 112, 128, 192, 256 };
+static const int NUM_AUTH_LEVELS = OSSL_NELEM(minbits_table);
+
+/*
+ * Check whether the public key of ``cert`` meets the security level of
+ * ``ctx``.
+ *
+ * Returns 1 on success, 0 otherwise.
+ */
+static int check_key_level(X509_STORE_CTX *ctx, X509 *cert)
+{
+ EVP_PKEY *pkey = X509_get0_pubkey(cert);
+ int level = ctx->param->auth_level;
+
+ /* Unsupported or malformed keys are not secure */
+ if (pkey == NULL)
+ return 0;
+
+ if (level <= 0)
+ return 1;
+ if (level > NUM_AUTH_LEVELS)
+ level = NUM_AUTH_LEVELS;
+
+ return EVP_PKEY_security_bits(pkey) >= minbits_table[level - 1];
+}
+
+/*
+ * Check whether the signature digest algorithm of ``cert`` meets the security
+ * level of ``ctx``. Should not be checked for trust anchors (whether
+ * self-signed or otherwise).
+ *
+ * Returns 1 on success, 0 otherwise.
+ */
+static int check_sig_level(X509_STORE_CTX *ctx, X509 *cert)
+{
+ int nid = X509_get_signature_nid(cert);
+ int mdnid = NID_undef;
+ int secbits = -1;
+ int level = ctx->param->auth_level;
+
+ if (level <= 0)
+ return 1;
+ if (level > NUM_AUTH_LEVELS)
+ level = NUM_AUTH_LEVELS;
+
+ /* Lookup signature algorithm digest */
+ if (nid && OBJ_find_sigid_algs(nid, &mdnid, NULL)) {
+ const EVP_MD *md;
+
+ /* Assume 4 bits of collision resistance for each hash octet */
+ if (mdnid != NID_undef && (md = EVP_get_digestbynid(mdnid)) != NULL)
+ secbits = EVP_MD_size(md) * 4;
+ }
+
+ return secbits >= minbits_table[level - 1];
+}
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
index 41b0fde4a5..4a0bed021c 100644
--- a/crypto/x509/x509_vpm.c
+++ b/crypto/x509/x509_vpm.c
@@ -140,6 +140,7 @@ static void x509_verify_param_zero(X509_VERIFY_PARAM *param)
param->inh_flags = 0;
param->flags = 0;
param->depth = -1;
+ param->auth_level = -1; /* -1 means unset, 0 is explicit */
sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
param->policies = NULL;
sk_OPENSSL_STRING_pop_free(param->hosts, str_free);
@@ -245,6 +246,7 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
x509_verify_param_copy(purpose, 0);
x509_verify_param_copy(trust, X509_TRUST_DEFAULT);
x509_verify_param_copy(depth, -1);
+ x509_verify_param_copy(auth_level, -1);
/* If overwrite or check time not set, copy across */
@@ -368,6 +370,11 @@ void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth)
param->depth = depth;
}
+void X509_VERIFY_PARAM_set_auth_level(X509_VERIFY_PARAM *param, int auth_level)
+{
+ param->auth_level = auth_level;
+}
+
void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t)
{
param->check_time = t;
@@ -493,6 +500,11 @@ int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
return param->depth;
}
+int X509_VERIFY_PARAM_get_auth_level(const X509_VERIFY_PARAM *param)
+{
+ return param->auth_level;
+}
+
const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
{
return param->name;
@@ -515,6 +527,7 @@ static const X509_VERIFY_PARAM default_table[] = {
0, /* purpose */
0, /* trust */
100, /* depth */
+ -1, /* auth_level */
NULL, /* policies */
vpm_empty_id},
{
@@ -525,6 +538,7 @@ static const X509_VERIFY_PARAM default_table[] = {
X509_PURPOSE_SMIME_SIGN, /* purpose */
X509_TRUST_EMAIL, /* trust */
-1, /* depth */
+ -1, /* auth_level */
NULL, /* policies */
vpm_empty_id},
{
@@ -535,6 +549,7 @@ static const X509_VERIFY_PARAM default_table[] = {
X509_PURPOSE_SMIME_SIGN, /* purpose */
X509_TRUST_EMAIL, /* trust */
-1, /* depth */
+ -1, /* auth_level */
NULL, /* policies */
vpm_empty_id},
{
@@ -545,6 +560,7 @@ static const X509_VERIFY_PARAM default_table[] = {
X509_PURPOSE_SSL_CLIENT, /* purpose */
X509_TRUST_SSL_CLIENT, /* trust */
-1, /* depth */
+ -1, /* auth_level */
NULL, /* policies */
vpm_empty_id},
{
@@ -555,6 +571,7 @@ static const X509_VERIFY_PARAM default_table[] = {
X509_PURPOSE_SSL_SERVER, /* purpose */
X509_TRUST_SSL_SERVER, /* trust */
-1, /* depth */
+ -1, /* auth_level */
NULL, /* policies */
vpm_empty_id}
};
diff --git a/doc/apps/cms.pod b/doc/apps/cms.pod
index 36e6b3ca3a..42c351489c 100644
--- a/doc/apps/cms.pod
+++ b/doc/apps/cms.pod
@@ -58,6 +58,7 @@ B<openssl> B<cms>
[B<-trusted_first>]
[B<-no_alt_chains>]
[B<-use_deltas>]
+[B<-auth_level num>]
[B<-verify_depth num>]
[B<-verify_email email>]
[B<-verify_hostname hostname>]
@@ -475,8 +476,8 @@ B<-explicit_policy>, B<-extended_crl>, B<-ignore_critical>, B<-inhibit_any>,
B<-inhibit_map>, B<-no_alt_chains>, B<-partial_chain>, B<-policy>,
B<-policy_check>, B<-policy_print>, B<-purpose>, B<-suiteB_128>,
B<-suiteB_128_only>, B<-suiteB_192>, B<-trusted_first>, B<-use_deltas>,
-B<-verify_depth>, B<-verify_email>, B<-verify_hostname>, B<-verify_ip>,
-B<-verify_name>, B<-x509_strict>
+B<-auth_level>, B<-verify_depth>, B<-verify_email>, B<-verify_hostname>,
+B<-verify_ip>, B<-verify_name>, B<-x509_strict>
Set various certificate chain validation options. See the
L<verify(1)> manual page for details.
diff --git a/doc/apps/ocsp.pod b/doc/apps/ocsp.pod
index be195bcb30..c796fd5966 100644
--- a/doc/apps/ocsp.pod
+++ b/doc/apps/ocsp.pod
@@ -53,6 +53,7 @@ B<openssl> B<ocsp>
[B<-trusted_first>]
[B<-no_alt_chains>]
[B<-use_deltas>]
+[B<-auth_level num>]
[B<-verify_depth num>]
[B<-verify_email email>]
[B<-verify_hostname hostname>]
@@ -197,11 +198,11 @@ B<-explicit_policy>, B<-extended_crl>, B<-ignore_critical>, B<-inhibit_any>,
B<-inhibit_map>, B<-no_alt_chains>, B<-partial_chain>, B<-policy>,
B<-policy_check>, B<-policy_print>, B<-purpose>, B<-suiteB_128>,
B<-suiteB_128_only>, B<-suiteB_192>, B<-trusted_first>, B<-use_deltas>,
-B<-verify_depth>, B<-verify_email>, B<-verify_hostname>, B<-verify_ip>,
-B<-verify_name>, B<-x509_strict>
+B<-auth_level>, B<-verify_depth>, B<-verify_email>, B<-verify_hostname>,
+B<-verify_ip>, B<-verify_name>, B<-x509_strict>
Set different certificate verification options.
-See L<B<verify>|verify(1)> manual page for details.
+See L<verify(1)> manual page for details.
=item B<-verify_other file>
diff --git a/doc/apps/s_client.pod b/doc/apps/s_client.pod
index 1873293ea8..881fbcfefe 100644
--- a/doc/apps/s_client.pod
+++ b/doc/apps/s_client.pod
@@ -45,6 +45,7 @@ B<openssl> B<s_client>
[B<-trusted_first>]
[B<-no_alt_chains>]
[B<-use_deltas>]
+[B<-auth_level num>]
[B<-verify_depth num>]
[B<-verify_email email>]
[B<-verify_hostname hostname>]
@@ -229,8 +230,8 @@ B<-explicit_policy>, B<-extended_crl>, B<-ignore_critical>, B<-inhibit_any>,
B<-inhibit_map>, B<-no_alt_chains>, B<-partial_chain>, B<-policy>,
B<-policy_check>, B<-policy_print>, B<-purpose>, B<-suiteB_128>,
B<-suiteB_128_only>, B<-suiteB_192>, B<-trusted_first>, B<-use_deltas>,
-B<-verify_depth>, B<-verify_email>, B<-verify_hostname>, B<-verify_ip>,
-B<-verify_name>, B<-x509_strict>
+B<-auth_level>, B<-verify_depth>, B<-verify_email>, B<-verify_hostname>,
+B<-verify_ip>, B<-verify_name>, B<-x509_strict>
Set various certificate chain validation options. See the
L<verify(1)> manual page for details.
diff --git a/doc/apps/s_server.pod b/doc/apps/s_server.pod
index 25e544468a..08554f4530 100644
--- a/doc/apps/s_server.pod
+++ b/doc/apps/s_server.pod
@@ -55,6 +55,7 @@ B<openssl> B<s_server>
[B<-trusted_first>]
[B<-no_alt_chains>]
[B<-use_deltas>]
+[B<-auth_level num>]
[B<-verify_depth num>]
[B<-verify_return_error>]
[B<-verify_email email>]
@@ -234,8 +235,8 @@ B<-explicit_policy>, B<-extended_crl>, B<-ignore_critical>, B<-inhibit_any>,
B<-inhibit_map>, B<-no_alt_chains>, B<-partial_chain>, B<-policy>,
B<-policy_check>, B<-policy_print>, B<-purpose>, B<-suiteB_128>,
B<-suiteB_128_only>, B<-suiteB_192>, B<-trusted_first>, B<-use_deltas>,
-B<-verify_depth>, B<-verify_email>, B<-verify_hostname>, B<-verify_ip>,
-B<-verify_name>, B<-x509_strict>
+B<-auth_level>, B<-verify_depth>, B<-verify_email>, B<-verify_hostname>,
+B<-verify_ip>, B<-verify_name>, B<-x509_strict>
Set different peer certificate verification options.
See the L<verify(1)> manual page for details.
diff --git a/doc/apps/smime.pod b/doc/apps/smime.pod
index 418d8faa2d..e6323ad0b0 100644
--- a/doc/apps/smime.pod
+++ b/doc/apps/smime.pod
@@ -40,6 +40,7 @@ B<openssl> B<smime>
[B<-trusted_first>]
[B<-no_alt_chains>]
[B<-use_deltas>]
+[B<-auth_level num>]
[B<-verify_depth num>]
[B<-verify_email email>]
[B<-verify_hostname hostname>]
@@ -307,8 +308,8 @@ B<-explicit_policy>, B<-extended_crl>, B<-ignore_critical>, B<-inhibit_any>,
B<-inhibit_map>, B<-no_alt_chains>, B<-partial_chain>, B<-policy>,
B<-policy_check>, B<-policy_print>, B<-purpose>, B<-suiteB_128>,
B<-suiteB_128_only>, B<-suiteB_192>, B<-trusted_first>, B<-use_deltas>,
-B<-verify_depth>, B<-verify_email>, B<-verify_hostname>, B<-verify_ip>,
-B<-verify_name>, B<-x509_strict>
+B<-auth_level>, B<-verify_depth>, B<-verify_email>, B<-verify_hostname>,
+B<-verify_ip>, B<-verify_name>, B<-x509_strict>
Set various options of certificate chain verification. See
L<verify(1)> manual page for details.
diff --git a/doc/apps/ts.pod b/doc/apps/ts.pod
index 93ea9e059a..e64e5fcf34 100644
--- a/doc/apps/ts.pod
+++ b/doc/apps/ts.pod
@@ -73,6 +73,7 @@ I<verify options:>
[-suiteB_192]
[-trusted_first]
[-use_deltas]
+[-auth_level num]
[-verify_depth num]
[-verify_email email]
[-verify_hostname hostname]
@@ -371,17 +372,15 @@ all intermediate CA certificates unless the response includes them.
=item I<verify options>
-The options [-attime timestamp], [-check_ss_sig], [-crl_check],
-[-crl_check_all], [-explicit_policy], [-extended_crl],
-[-ignore_critical], [-inhibit_any], [-inhibit_map],
-[-issuer_checks], [-no_alt_chains], [-no_check_time],
-[-partial_chain], [-policy arg], [-policy_check],
-[-policy_print], [-purpose purpose], [-suiteB_128],
-[-suiteB_128_only], [-suiteB_192], [-trusted_first],
-[-use_deltas], [-verify_depth num], [-verify_email email],
-[-verify_hostname hostname], [-verify_ip ip], [-verify_name name],
-and [-x509_strict] can be used to control timestamp verification.
-See L<verify(1)>.
+The options B<-attime timestamp>, B<-check_ss_sig>, B<-crl_check>,
+B<-crl_check_all>, B<-explicit_policy>, B<-extended_crl>, B<-ignore_critical>,
+B<-inhibit_any>, B<-inhibit_map>, B<-issuer_checks>, B<-no_alt_chains>,
+B<-no_check_time>, B<-partial_chain>, B<-policy>, B<-policy_check>,
+B<-policy_print>, B<-purpose>, B<-suiteB_128>, B<-suiteB_128_only>,
+B<-suiteB_192>, B<-trusted_first>, B<-use_deltas>, B<-auth_level>,
+B<-verify_depth>, B<-verify_email>, B<-verify_hostname>, B<-verify_ip>,
+B<-verify_name>, and B<-x509_strict> can be used to control timestamp
+verification. See L<verify(1)>.
=back
diff --git a/doc/apps/verify.pod b/doc/apps/verify.pod
index ecde35fe8a..96d6be4a4d 100644
--- a/doc/apps/verify.pod
+++ b/doc/apps/verify.pod
@@ -38,6 +38,7 @@ B<openssl> B<verify>
[B<-trusted file>]
[B<-use_deltas>]
[B<-verbose>]
+[B<-auth_level level>]
[B<-verify_depth num>]
[B<-verify_email email>]
[B<-verify_hostname hostname>]
@@ -227,9 +228,30 @@ Enable support for delta CRLs.
Print extra information about the operations being performed.
+=item B<-auth_level level>
+
+Set the certificate chain authentication security level to B<level>.
+The authentication security level determines the acceptable signature and
+public key strength when verifying certificate chains.
+For a certificate chain to validate, the public keys of all the certificates
+must meet the specified security B<level>.
+The signature algorithm security level is enforced for all the certificates in
+the chain except for the chain's I<trust anchor>, which is either directly
+trusted or validated by means other than its signature.
+See L<SSL_CTX_set_security_level(3)> for the definitions of the available
+levels.
+The default security level is -1, or "not set".
+At security level 0 or lower all algorithms are acceptable.
+Security level 1 requires at least 80-bit-equivalent security and is broadly
+interoperable, though it will, for example, reject MD5 signatures or RSA keys
+shorter than 1024 bits.
+
=item B<-verify_depth num>
-Limit the maximum depth of the certificate chain to B<num> certificates.
+Limit the certificate chain to B<num> intermediate CA certificates.
+A maximal depth chain can have up to B<num+2> certificates, since neither the
+end-entity certificate nor the trust-anchor certificate count against the
+B<-verify_depth> limit.
=item B<-verify_email email>
diff --git a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod b/doc/crypto/X509_VERIFY_PARAM_set_flags.pod
index 6fb33edd91..04f521506f 100644
--- a/doc/crypto/X509_VERIFY_PARAM_set_flags.pod
+++ b/doc/crypto/X509_VERIFY_PARAM_set_flags.pod
@@ -2,15 +2,16 @@
=head1 NAME
-X509_VERIFY_PARAM_set_flags, X509_VERIFY_PARAM_clear_flags, X509_VERIFY_PARAM_get_flags, X509_VERIFY_PARAM_set_purpose, X509_VERIFY_PARAM_set_trust, X509_VERIFY_PARAM_set_depth, X509_VERIFY_PARAM_get_depth, X509_VERIFY_PARAM_set_time, X509_VERIFY_PARAM_add0_policy, X509_VERIFY_PARAM_set1_policies, X509_VERIFY_PARAM_set1_host, X509_VERIFY_PARAM_add1_host, X509_VERIFY_PARAM_set_hostflags, X509_VERIFY_PARAM_get0_peername, X509_VERIFY_PARAM_set1_email, X509_VERIFY_PARAM_set1_ip, X509_VERIFY_PARAM_set1_ip_asc - X509 verification parameters
+X509_VERIFY_PARAM_set_flags, X509_VERIFY_PARAM_clear_flags, X509_VERIFY_PARAM_get_flags, X509_VERIFY_PARAM_set_purpose, X509_VERIFY_PARAM_set_trust, X509_VERIFY_PARAM_set_depth, X509_VERIFY_PARAM_get_depth, X509_VERIFY_PARAM_set_auth_level, X509_VERIFY_PARAM_get_auth_level, X509_VERIFY_PARAM_set_time, X509_VERIFY_PARAM_add0_policy, X509_VERIFY_PARAM_set1_policies, X509_VERIFY_PARAM_set1_host, X509_VERIFY_PARAM_add1_host, X509_VERIFY_PARAM_set_hostflags, X509_VERIFY_PARAM_get0_peername, X509_VERIFY_PARAM_set1_email, X509_VERIFY_PARAM_set1_ip, X509_VERIFY_PARAM_set1_ip_asc - X509 verification parameters
=head1 SYNOPSIS
#include <openssl/x509_vfy.h>
- int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags);
+ int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param,
+ unsigned long flags);
int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param,
- unsigned long flags);
+ unsigned long flags);
unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose);
@@ -19,13 +20,17 @@ X509_VERIFY_PARAM_set_flags, X509_VERIFY_PARAM_clear_flags, X509_VERIFY_PARAM_ge
void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t);
int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
- ASN1_OBJECT *policy);
+ ASN1_OBJECT *policy);
int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
STACK_OF(ASN1_OBJECT) *policies);
void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth);
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
+ void X509_VERIFY_PARAM_set_auth_level(X509_VERIFY_PARAM *param,
+ int auth_level);
+ int X509_VERIFY_PARAM_get_auth_level(const X509_VERIFY_PARAM *param);
+
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen);
int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
@@ -71,8 +76,32 @@ policy set is cleared. The B<policies> parameter can be B<NULL> to clear
an existing policy set.
X509_VERIFY_PARAM_set_depth() sets the maximum verification depth to B<depth>.
-That is the maximum number of untrusted CA certificates that can appear in a
+That is the maximum number of intermediate CA certificates that can appear in a
chain.
+A maximal depth chain contains 2 more certificates than the limit, since
+neither the end-entity ceritificate nor the trust-anchor count against this
+limit.
+Thus a B<depth> limit of 0 only allows the end-entity certificate to be signed
+directly by the trust-anchor, while with a B<depth> limit of 1 there can be one
+intermediate CA certificate between the trust-anchor and the end-entity
+certificate.
+
+X509_VERIFY_PARAM_set_auth_level() sets the authentication security level to
+B<auth_level>.
+The authentication security level determines the acceptable signature and public
+key strength when verifying certificate chains.
+For a certificate chain to validate, the public keys of all the certificates
+must meet the specified security level.
+The signature algorithm security level is not enforced for the chain's I<trust
+anchor> certificate, which is either directly trusted or validated by means other
+than its signature.
+See L<SSL_CTX_set_security_level(3)> for the definitions of the available
+levels.
+The default security level is -1, or "not set".
+At security level 0 or lower all algorithms are acceptable.
+Security level 1 requires at least 80-bit-equivalent security and is broadly
+interoperable, though it will, for example, reject MD5 signatures or RSA keys
+shorter than 1024 bits.
X509_VERIFY_PARAM_set1_host() sets the expected DNS hostname to
B<name> clearing any previously specified host name or names. If
@@ -139,6 +168,9 @@ values.
X509_VERIFY_PARAM_get_depth() returns the current verification depth.
+X509_VERIFY_PARAM_get_auth_level() returns the current authentication security
+level.
+
=head1 VERIFICATION FLAGS
The verification flags consists of zero or more of the following flags
diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h
index e883349d34..093b0f3d0a 100644
--- a/include/openssl/x509_vfy.h
+++ b/include/openssl/x509_vfy.h
@@ -355,7 +355,10 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
# define X509_V_ERR_IP_ADDRESS_MISMATCH 64
/* DANE TLSA errors */
# define X509_V_ERR_DANE_NO_MATCH 65
-
+/* security level errors */
+# define X509_V_ERR_EE_KEY_TOO_SMALL 66
+# define X509_V_ERR_CA_KEY_TOO_SMALL 67
+# define X509_V_ERR_CA_MD_TOO_WEAK 68
/* Certificate verify flags */
@@ -552,6 +555,7 @@ unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose);
int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust);
void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth);
+void X509_VERIFY_PARAM_set_auth_level(X509_VERIFY_PARAM *param, int auth_level);
void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t);
int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
ASN1_OBJECT *policy);
@@ -574,6 +578,7 @@ int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param,
const char *ipasc);
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
+int X509_VERIFY_PARAM_get_auth_level(const X509_VERIFY_PARAM *param);
const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param);
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c
index 4081ebe4ff..24ac352d1d 100644
--- a/ssl/ssl_cert.c
+++ b/ssl/ssl_cert.c
@@ -494,6 +494,12 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk)
return (0);
}
param = X509_STORE_CTX_get0_param(&ctx);
+ /*
+ * XXX: Separate @AUTHSECLEVEL and @TLSSECLEVEL would be useful at some
+ * point, for now a single @SECLEVEL sets the same policy for TLS crypto
+ * and PKI authentication.
+ */
+ X509_VERIFY_PARAM_set_auth_level(param, SSL_get_security_level(s));
/* Set suite B flags if needed */
X509_STORE_CTX_set_flags(&ctx, tls1_suiteb(s));
@@ -520,17 +526,8 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk)
if (s->ctx->app_verify_callback != NULL)
i = s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg);
- else {
+ else
i = X509_verify_cert(&ctx);
-# if 0
- /* Dummy error calls so mkerr generates them */
- SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, SSL_R_EE_KEY_TOO_SMALL);
- SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, SSL_R_CA_KEY_TOO_SMALL);
- SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, SSL_R_CA_MD_TOO_WEAK);
-# endif
- if (i > 0)
- i = ssl_security_cert_chain(s, ctx.chain, NULL, 1);
- }
s->verify_result = ctx.error;
sk_X509_pop_free(s->verified_chain, X509_free);
@@ -894,12 +891,18 @@ int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l)
* ignore the error return from this call. We're not actually verifying
* the cert - we're just building as much of the chain as we can
*/
- X509_verify_cert(&xs_ctx);
+ (void) X509_verify_cert(&xs_ctx);
/* Don't leave errors in the queue */
ERR_clear_error();
i = ssl_security_cert_chain(s, xs_ctx.chain, NULL, 0);
if (i != 1) {
X509_STORE_CTX_cleanup(&xs_ctx);
+#if 0
+ /* Dummy error calls so mkerr generates them */
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_EE_KEY_TOO_SMALL);
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_CA_KEY_TOO_SMALL);
+ SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, SSL_R_CA_MD_TOO_WEAK);
+#endif
SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, i);
return 0;
}
diff --git a/test/certs/ca-cert-768.pem b/test/certs/ca-cert-768.pem
new file mode 100644
index 0000000000..0c8ff29440
--- /dev/null
+++ b/test/certs/ca-cert-768.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICRDCCASygAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE2MDMyMDA2MjcyN1oYDzIxMTYwMzIxMDYyNzI3WjANMQswCQYDVQQD
+DAJDQTB8MA0GCSqGSIb3DQEBAQUAA2sAMGgCYQC3wNLc1A9gAjz1H94ozPrLOhE2
+R8c6RQjkUIALCOuw8xbZV+AEDSqP11Bw8MVzvmpksR9s1idJhLOugwMNTHfTXJjV
+DWoQh9ofR51J5sOph4yDhQBXRmiuvqMDj+a81UkCAwEAAaNQME4wHQYDVR0OBBYE
+FKrzei/LKJop6yShiJupKskW0ZQcMB8GA1UdIwQYMBaAFI71Ja8em2uEPXyAmslT
+nE1y96NSMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFr4hjVtLuZz
+gxLILAOREEtanckfnapUrhTLukog9Q8uzqMUE+YDEhkcP4YAVjcab6HaXrbcxXsn
+zn+v+GPszD9G3doGbUjuwEEAHz+k/9sjsn8QAGw/XslYhd5dktaRRCqaTNiWT+Ks
+xKntAsgXcgWNIpvGikzTB/W7IrjIV8/S1JjLABtoY88tFUX81Ohr3bFFsRc9EHVS
+MtGnEwfoBOSlCUjaTWBNHHi1HstK9sG2SNT/nhN1HATk/aiCiQRKr/bm6ezPC2If
+6mRidaNiQN8+vzvtn86BqtRJOEi8jj5CBax6IqwfE+lDZIwT7H9C9Cu8Yp4mTM0x
+wwzRDnFVisM=
+-----END CERTIFICATE-----
diff --git a/test/certs/ca-cert-768i.pem b/test/certs/ca-cert-768i.pem
new file mode 100644
index 0000000000..acc432fadd
--- /dev/null
+++ b/test/certs/ca-cert-768i.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAdSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE2MDMyMDA2MjcyN1oYDzIxMTYwMzIxMDYyNzI3WjANMQswCQYDVQQD
+DAJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJadpD0ASxxfxsvd
+j9IxsogVzMSGLFziaYuE9KejU9+R479RifvwfBANO62sNWJ19X//9G5UjwWmkiOz
+n1k50DkYsBBA3mJzik6wjt/c58lBIlSEgAgpvDU8ht8w3t20JP9+YqXAeugqFj/W
+l9rFQtsvaWSRywjXVlp5fxuEQelNnXcJEKhsKTNExsBUZebo4/J1BWpklWzA9P0l
+YW5INvDAAwcF1nzlEf0Y6Eot03IMNyg2MTE4hehxjdgCSci8GYnFirE/ojXqqpAc
+ZGh7r2dqWgZUD1Dh+bT2vjrUzj8eTH3GdzI+oljt29102JIUaqj3yzRYkah8FLF9
+CLNNsUcCAwEAAaNQME4wHQYDVR0OBBYEFLQRM/HX4l73U54gIhBPhga/H8leMB8G
+A1UdIwQYMBaAFFjzE/eu8wvKwzb2aODw52C+0gLVMAwGA1UdEwQFMAMBAf8wDQYJ
+KoZIhvcNAQELBQADYQCZM1sSpIyjyuGirBYvezFryUq5EyZiME3HIHJ7AbmquPtE
+LcoE8lwxEYXl7OTbLZHxIKkt6+WX2TL/0yshJLq/42nh5DZwyug7fIITmkzmzidF
+rbnl7fIop7OJX/kELbY=
+-----END CERTIFICATE-----
diff --git a/test/certs/ca-cert-md5-any.pem b/test/certs/ca-cert-md5-any.pem
new file mode 100644
index 0000000000..7c2b53f5da
--- /dev/null
+++ b/test/certs/ca-cert-md5-any.pem
@@ -0,0 +1,18 @@
+-----BEGIN TRUSTED CERTIFICATE-----
+MIIC7DCCAdSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE2MDMyMDA2MjcyN1oYDzIxMTYwMzIxMDYyNzI3WjANMQswCQYDVQQD
+DAJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJadpD0ASxxfxsvd
+j9IxsogVzMSGLFziaYuE9KejU9+R479RifvwfBANO62sNWJ19X//9G5UjwWmkiOz
+n1k50DkYsBBA3mJzik6wjt/c58lBIlSEgAgpvDU8ht8w3t20JP9+YqXAeugqFj/W
+l9rFQtsvaWSRywjXVlp5fxuEQelNnXcJEKhsKTNExsBUZebo4/J1BWpklWzA9P0l
+YW5INvDAAwcF1nzlEf0Y6Eot03IMNyg2MTE4hehxjdgCSci8GYnFirE/ojXqqpAc
+ZGh7r2dqWgZUD1Dh+bT2vjrUzj8eTH3GdzI+oljt29102JIUaqj3yzRYkah8FLF9
+CLNNsUcCAwEAAaNQME4wHQYDVR0OBBYEFLQRM/HX4l73U54gIhBPhga/H8leMB8G
+A1UdIwQYMBaAFI71Ja8em2uEPXyAmslTnE1y96NSMAwGA1UdEwQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBACTmLO0KOkXFNjj6hXozC9GzQYMXdCfNmgMuetk8xdVm
+TqkF/qIGK2FBWn91IH0/9ydZbL83EKjPjqjwqzXqExJ0Un+fy7XbYMKtjGJ21egJ
+x97jzKey5phEwRD/4fJ+PCml9eE/SNzBV0xKSDq4qQYvSJ3GF6KCATVlr0bDzQJZ
+yTY3FeNoy+K7Mb0rHtsGru60C/Ft1dl9uiJ+yKXMiCxPcDjYb+95mA9QJ1kXfR8J
+JVfeKhEEK+QIVpz/37aQ4jx/zbGblFsruALK22aLnpgrfUzrsYQ8W8T/DV2dV1ra
+4wHz/QtlE4isInOaK2+pvXwyGar+1/s3+VxXEiPlZ7IwCDAGBgRVHSUA
+-----END TRUSTED CERTIFICATE-----
diff --git a/test/certs/ca-cert-md5.pem b/test/certs/ca-cert-md5.pem
new file mode 100644
index 0000000000..be564ddd10
--- /dev/null
+++ b/test/certs/ca-cert-md5.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC7DCCAdSgAwIBAgIBAjANBgkqhkiG9w0BAQQFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE2MDMyMDA2MjcyN1oYDzIxMTYwMzIxMDYyNzI3WjANMQswCQYDVQQD
+DAJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJadpD0ASxxfxsvd
+j9IxsogVzMSGLFziaYuE9KejU9+R479RifvwfBANO62sNWJ19X//9G5UjwWmkiOz
+n1k50DkYsBBA3mJzik6wjt/c58lBIlSEgAgpvDU8ht8w3t20JP9+YqXAeugqFj/W
+l9rFQtsvaWSRywjXVlp5fxuEQelNnXcJEKhsKTNExsBUZebo4/J1BWpklWzA9P0l
+YW5INvDAAwcF1nzlEf0Y6Eot03IMNyg2MTE4hehxjdgCSci8GYnFirE/ojXqqpAc
+ZGh7r2dqWgZUD1Dh+bT2vjrUzj8eTH3GdzI+oljt29102JIUaqj3yzRYkah8FLF9
+CLNNsUcCAwEAAaNQME4wHQYDVR0OBBYEFLQRM/HX4l73U54gIhBPhga/H8leMB8G
+A1UdIwQYMBaAFI71Ja8em2uEPXyAmslTnE1y96NSMAwGA1UdEwQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBACTmLO0KOkXFNjj6hXozC9GzQYMXdCfNmgMuetk8xdVm
+TqkF/qIGK2FBWn91IH0/9ydZbL83EKjPjqjwqzXqExJ0Un+fy7XbYMKtjGJ21egJ
+x97jzKey5phEwRD/4fJ+PCml9eE/SNzBV0xKSDq4qQYvSJ3GF6KCATVlr0bDzQJZ
+yTY3FeNoy+K7Mb0rHtsGru60C/Ft1dl9uiJ+yKXMiCxPcDjYb+95mA9QJ1kXfR8J
+JVfeKhEEK+QIVpz/37aQ4jx/zbGblFsruALK22aLnpgrfUzrsYQ8W8T/DV2dV1ra
+4wHz/QtlE4isInOaK2+pvXwyGar+1/s3+VxXEiPlZ7I=
+-----END CERTIFICATE-----
diff --git a/test/certs/ca-key-768.pem b/test/certs/ca-key-768.pem
new file mode 100644
index 0000000000..7aea5eda13
--- /dev/null
+++ b/test/certs/ca-key-768.pem
@@ -0,0 +1,13 @@
+-----BEGIN PRIVATE KEY-----
+MIIB5QIBADANBgkqhkiG9w0BAQEFAASCAc8wggHLAgEAAmEAt8DS3NQPYAI89R/e
+KMz6yzoRNkfHOkUI5FCACwjrsPMW2VfgBA0qj9dQcPDFc75qZLEfbNYnSYSzroMD
+DUx301yY1Q1qEIfaH0edSebDqYeMg4UAV0Zorr6jA4/mvNVJAgMBAAECYQCJAsu3
+QJ9eNQ0CsQpTXdO6aMegs5CHkCX7J1Lx52rl+7uTv4QXQUH1EtS2AbEYhmdGzMFN
+ZlBrg1vDsW/yn02NZzvT6xT/kvzFhQVw1i8B0YyB8wPao3f2ZxPkAfeoAAECMQDa
+6VkNYlHgPOlTtwU1WYUirFczpipQsuk/lIf7B3+rVRUHoAE4nbeIRJgkKZaJEAEC
+MQDW4pYsyN79HEqFpOFlfsrERw3y4hLRXGeHxbfJFdAe7SUfNj28ZI2EPFE0DJhX
+RUkCMA39M2+jhM/rlI2A+Jg8LEHW+YuXZsTZagZiG35zMDlmqn1eQDW5/mx61a4Z
+6kDAAQIwIlbZWtTK1bX0rsC3iEmny4/zSbIZAb37iXXuNcM3nAmXmhJH8Vg8STp+
+W4v7uE6JAjEAwiB9wCVwG4UhvKNQ4Wd2mfJiKZQNF4rL4ID0g+Wk6kX67c7u2hfH
+sSaluw9nM91s
+-----END PRIVATE KEY-----
diff --git a/test/certs/ee-cert-768.pem b/test/certs/ee-cert-768.pem
new file mode 100644
index 0000000000..794f93c012
--- /dev/null
+++ b/test/certs/ee-cert-768.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICeDCCAWCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg
+Fw0xNjAzMjAwNjI3MjdaGA8yMTE2MDMyMTA2MjcyN1owGTEXMBUGA1UEAwwOc2Vy
+dmVyLmV4YW1wbGUwfDANBgkqhkiG9w0BAQEFAANrADBoAmEAwCvrPAynx+7VtpFz
+4cWZW3/n3/nMwK4fxkWSB0kbVUhQaYiaQGWEfB4JpRz5rPt8NW5m2aVGT7mMjScu
+8YyFa3IDdpBeQL1n8VQUH3FLySgQHC1bkkzwyzQM8JirCdl/AgMBAAGjfTB7MB0G
+A1UdDgQWBBSRBasp1P/UDCesreviw4Lwz8tFBDAfBgNVHSMEGDAWgBS0ETPx1+Je
+91OeICIQT4YGvx/JXjAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMBkG
+A1UdEQQSMBCCDnNlcnZlci5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQB5xled
+do7U++n86KmJDGnXd4XMpr1QbTFVSO7fhSiObeGm961re/TI7AhuLlsZYP601YhZ
+pRe9B7tiEuzu3iCD4kKB0yxgUCSsF0u1KbHSUNe2H5bBJC21c2eLZh6U54y014nL
+gFSDOsA8M1301+Hlh5AS+4iTR0Ra02RaZb3L5HCR2wtkJubh3rSj8eBzb6fx+Lhw
+JoeRg34lhycGC4bBVwkRT8bo73Nrs71JUP2A6/PjdsIfF2rtVMEuIq8AMQ5wInZ+
+2mIxJ4MwCClwLCq3VxI1bzdf1TYsPNxYTUS1POb2VgNofG0mBTHNUYUO20aF0ct8
+PCQqIqxUIegfS3f5
+-----END CERTIFICATE-----
diff --git a/test/certs/ee-cert-768i.pem b/test/certs/ee-cert-768i.pem
new file mode 100644
index 0000000000..d6532fb5d2
--- /dev/null
+++ b/test/certs/ee-cert-768i.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICfjCCAgigAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg
+Fw0xNjAzMjAwNjI3MjdaGA8yMTE2MDMyMTA2MjcyN1owGTEXMBUGA1UEAwwOc2Vy
+dmVyLmV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo/4lY
+YYWu3tssD9Vz++K3qBt6dWAr1H08c3a1rt6TL38kkG3JHPSKOM2fooAWVsu0LLuT
+5Rcf/w3GQ/4xNPgo2HXpo7uIgu+jcuJTYgVFTeAxl++qnRDSWA2eBp4yuxsIVl1l
+Dz9mjsI2oBH/wFk1/Ukc3RxCMwZ4rgQ4I+XndWfTlK1aqUAfrFkQ9QzBZK1KxMY1
+U7OWaoIbFYvRmavknm+UqtKW5Vf7jJFkijwkFsbSGb6CYBM7YrDtPh2zyvlr3zG5
+ep5LR2inKcc/SuIiJ7TvkGPX79ByST5brbkb1Ctvhmjd1XMSuEPJ3EEPoqNGT4tn
+iIQPYf55NB9KiR+3AgMBAAGjfTB7MB0GA1UdDgQWBBTnm+IqrYpsOst2UeWOB5gi
+l+FzojAfBgNVHSMEGDAWgBSq83ovyyiaKeskoYibqSrJFtGUHDAJBgNVHRMEAjAA
+MBMGA1UdJQQMMAoGCCsGAQUFBwMBMBkGA1UdEQQSMBCCDnNlcnZlci5leGFtcGxl
+MA0GCSqGSIb3DQEBCwUAA2EASAwDwXsYGnhQDyWixI9eKZwXAA9E4rEIdmKNvVjU
+jWkMh1oC0FZl4TTHU+sAaXmv2QItZOcG2QEHoTIZDPYiy+7eZC7pPQY25dkxeSZ9
+TIlMnfePzYTc3BnfxZj82Mny
+-----END CERTIFICATE-----
diff --git a/test/certs/ee-cert-md5.pem b/test/certs/ee-cert-md5.pem
new file mode 100644
index 0000000000..8c26422fca
--- /dev/null
+++ b/test/certs/ee-cert-md5.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBAjANBgkqhkiG9w0BAQQFADANMQswCQYDVQQDDAJDQTAg
+Fw0xNjAzMjAwNjI3MjdaGA8yMTE2MDMyMTA2MjcyN1owGTEXMBUGA1UEAwwOc2Vy
+dmVyLmV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo/4lY
+YYWu3tssD9Vz++K3qBt6dWAr1H08c3a1rt6TL38kkG3JHPSKOM2fooAWVsu0LLuT
+5Rcf/w3GQ/4xNPgo2HXpo7uIgu+jcuJTYgVFTeAxl++qnRDSWA2eBp4yuxsIVl1l
+Dz9mjsI2oBH/wFk1/Ukc3RxCMwZ4rgQ4I+XndWfTlK1aqUAfrFkQ9QzBZK1KxMY1
+U7OWaoIbFYvRmavknm+UqtKW5Vf7jJFkijwkFsbSGb6CYBM7YrDtPh2zyvlr3zG5
+ep5LR2inKcc/SuIiJ7TvkGPX79ByST5brbkb1Ctvhmjd1XMSuEPJ3EEPoqNGT4tn
+iIQPYf55NB9KiR+3AgMBAAGjfTB7MB0GA1UdDgQWBBTnm+IqrYpsOst2UeWOB5gi
+l+FzojAfBgNVHSMEGDAWgBS0ETPx1+Je91OeICIQT4YGvx/JXjAJBgNVHRMEAjAA
+MBMGA1UdJQQMMAoGCCsGAQUFBwMBMBkGA1UdEQQSMBCCDnNlcnZlci5leGFtcGxl
+MA0GCSqGSIb3DQEBBAUAA4IBAQBqCPfIEZOVUiq2exiRFoxVOvq668Y55lJZ9+4j
+E5Ncq9mdbuD7GIxJSKByf899yBJUG32ZIbmwnSHfBkPolc/LjQhUDxJtSBE8vFaA
+8AZ1rsOcaWapPQ94gYIgncBS15t7RjTX1l04fY0NPqVsWmTji+ummA5e7iCj6l6t
+CqRGhMeSZWa1mc+Plurmz7oWEqkUK5cfTrlDnXeQNOI8EK8lc636elqqdnw0amO4
+yKJlaXRlm/I1nQdUQ0G5Bk2Tp/QGoJCtJ25XsoIbnCs0tIbpQllTdLsRQmOussAP
+NvdwbKtAAolgMAxH9pl1Mc6OIo2e8405EWs1jvGEMgE0IFAY
+-----END CERTIFICATE-----
diff --git a/test/certs/ee-key-768.pem b/test/certs/ee-key-768.pem
new file mode 100644
index 0000000000..0d44f85529
--- /dev/null
+++ b/test/certs/ee-key-768.pem
@@ -0,0 +1,13 @@
+-----BEGIN PRIVATE KEY-----
+MIIB5QIBADANBgkqhkiG9w0BAQEFAASCAc8wggHLAgEAAmEAwCvrPAynx+7VtpFz
+4cWZW3/n3/nMwK4fxkWSB0kbVUhQaYiaQGWEfB4JpRz5rPt8NW5m2aVGT7mMjScu
+8YyFa3IDdpBeQL1n8VQUH3FLySgQHC1bkkzwyzQM8JirCdl/AgMBAAECYQCzO0MW
+qqcBrhvdPyPZerZhxJW7K/xv6PbxsYlVCjZYAC4ff6x+SzCZolpUiQXE9Hdyhlyk
+alcqn2vT5TagWk64YUmIMP7BCT2Ps/IW0nQl07k27c2BNq3IzdRnBz5SbQECMQDg
+9UxISqFOG6sLdZIKA88Q+M2HE/MdzwiJby/bSUXhn5aluZqjR60nGPqAb2S/r98C
+MQDasGzUTXqEYOPsAL4irzKMMiMdqbj6dNHsmo1GIYKx8PuN193i/cNd5XDv78Gm
+imECMQC10IvewbKtVl9f2540ye9JYE18pvsPVI0pxtt++DGqsTkoqGH7JasktmN/
++ogLBTECMBf9/xKTpXtcfeTod/OqMOt8nKmmcyrXIijJE/K7vnDzNUXshuVeXc6x
+W2CXdzFkQQIweyLLA6etAJGsmCRwIgnfp1ubmVdfPou68byHSnzAf4/GxBriSd5b
+EQcYwjE7SDI7
+-----END PRIVATE KEY-----
diff --git a/test/certs/mkcert.sh b/test/certs/mkcert.sh
index 99e7d2a342..ec2e374038 100755
--- a/test/certs/mkcert.sh
+++ b/test/certs/mkcert.sh
@@ -10,6 +10,10 @@
#
DAYS=36525
+if [ -z "$OPENSSL_SIGALG" ]; then
+ OPENSSL_SIGALG=sha256
+fi
+
stderr_onerror() {
(
err=$("$@" >&3 2>&1) || {
@@ -53,7 +57,7 @@ req() {
local errs
stderr_onerror \
- openssl req -new -sha256 -key "${key}.pem" \
+ openssl req -new -"${OPENSSL_SIGALG}" -key "${key}.pem" \
-config <(printf "[req]\n%s\n%s\n[dn]\nCN=%s\n" \
"prompt = no" "distinguished_name = dn" "${cn}")
}
@@ -63,7 +67,7 @@ req_nocn() {
key "$key"
stderr_onerror \
- openssl req -new -sha256 -subj / -key "${key}.pem" \
+ openssl req -new -"${OPENSSL_SIGALG}" -subj / -key "${key}.pem" \
-config <(printf "[req]\n%s\n[dn]\nCN_default =\n" \
"distinguished_name = dn")
}
@@ -73,7 +77,7 @@ cert() {
local exts=$1; shift
stderr_onerror \
- openssl x509 -req -sha256 -out "${cert}.pem" \
+ openssl x509 -req -"${OPENSSL_SIGALG}" -out "${cert}.pem" \
-extfile <(printf "%s\n" "$exts") "$@"
}
diff --git a/test/certs/root-cert-768.pem b/test/certs/root-cert-768.pem
new file mode 100644
index 0000000000..4392ef0e48
--- /dev/null
+++ b/test/certs/root-cert-768.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBpzCCATGgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE2MDMyMDA2MjcyN1oYDzIxMTYwMzIxMDYyNzI3WjASMRAwDgYDVQQD
+DAdSb290IENBMHwwDQYJKoZIhvcNAQEBBQADawAwaAJhALntqSk2YVnhNalAikA2
+tuSOvHUKVSJlqjKmzlUPI+gQFyBWxtyQdwepI87tl8EW1in2IiOeN49W+OtVOlBi
+Mxwqi/BcBltTbbSrlRpoSKOH6V7zIXvfsqjwWsDi37V1xQIDAQABo1AwTjAdBgNV
+HQ4EFgQUWPMT967zC8rDNvZo4PDnYL7SAtUwHwYDVR0jBBgwFoAUWPMT967zC8rD
+NvZo4PDnYL7SAtUwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANhAFDU7FyF
+Ma6EG0OBS4IYws2US9t3IQwlI5noQwm9R3Nk/3AIUrdPG8ydRyV1N4GuRhRpprh0
+sEbX3ZO9/E54DbPYfS5kqfZZtohUNy+Wmx8XY9OSv4SWUrrMSIRFXS63MA==
+-----END CERTIFICATE-----
diff --git a/test/certs/root-cert-md5.pem b/test/certs/root-cert-md5.pem
new file mode 100644
index 0000000000..b6ed10c62f
--- /dev/null
+++ b/test/certs/root-cert-md5.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQQFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE2MDMyMDA2MjcyN1oYDzIxMTYwMzIxMDYyNzI3WjASMRAwDgYDVQQD
+DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4eYA9Qa8
+oEY4eQ8/HnEZE20C3yubdmv8rLAh7daRCEI7pWM17FJboKJKxdYAlAOXWj25ZyjS
+feMhXKTtxjyNjoTRnVTDPdl0opZ2Z3H5xhpQd7P9eO5b4OOMiSPCmiLsPtQ3ngfN
+wCtVERc6NEIcaQ06GLDtFZRexv2eh8Yc55QaksBfBcFzQ+UD3gmRySTO2I6Lfi7g
+MUjRhipqVSZ66As2Tpex4KTJ2lxpSwOACFaDox+yKrjBTP7FsU3UwAGq7b7OJb3u
+aa32B81uK6GJVPVo65gJ7clgZsszYkoDsGjWDqtfwTVVfv1G7rrr3Laio+2Ff3ff
+tWgiQ35mJCOvxQIDAQABo1AwTjAdBgNVHQ4EFgQUjvUlrx6ba4Q9fICayVOcTXL3
+o1IwHwYDVR0jBBgwFoAUjvUlrx6ba4Q9fICayVOcTXL3o1IwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQQFAAOCAQEAwSTZo97psLqiNmgvCC/Z51F3S9bFKPjGK4dc
+Kqh8pMJsb8DnfGlPnsYXq/0oPcBThTRGZDqTeZa0ms8G+g4GS21TPF7lmvVJUJhz
+GRLJxX7TYB8xriSJ15DwZgGmEGPfzmoIq27nwrO4TRAi0TCLdw01XZwiq2V7anl+
+jrIpJPDuaT3oBqnGTMZ5IoaQq2TX8PS/ZW6icJiRmXLMp/HUycKpDUshiuARR5Mi
+UOzX8IHwn76Zj6z1R8xW9j1WcEycFYevTMaRuS6hnYagiSaAytIQU8hgMR4AWodM
+NFYv5t9rguJnimGUGMMBIYXnPNE2kaoq9qCVgjuC14gWU0kq6Q==
+-----END CERTIFICATE-----
diff --git a/test/certs/root-key-768.pem b/test/certs/root-key-768.pem
new file mode 100644
index 0000000000..4ecdcd3fdb
--- /dev/null
+++ b/test/certs/root-key-768.pem
@@ -0,0 +1,13 @@
+-----BEGIN PRIVATE KEY-----
+MIIB5AIBADANBgkqhkiG9w0BAQEFAASCAc4wggHKAgEAAmEAue2pKTZhWeE1qUCK
+QDa25I68dQpVImWqMqbOVQ8j6BAXIFbG3JB3B6kjzu2XwRbWKfYiI543j1b461U6
+UGIzHCqL8FwGW1NttKuVGmhIo4fpXvMhe9+yqPBawOLftXXFAgMBAAECYH1FP4Bg
+/16Lepg6v+tb8gY0lY1WFN5EGVRfRw3QUaT9kldboEjjnQ8wSswVEPYr56IHZ8mH
+Or8LtJVrB3fjriq5vNOt7lRscuV7IcVtOyVWu5+MoJmO67Q2vRJXLWTdAQIxANtp
+AiqObXo8vyT+EDcOEW104PfKNVh/4fhyrDwAk/yTcxkv4dcnuTykeLPvkXq4cQIx
+ANjvQa+9LubMy3N1uXIbWWsiEBi4BdNK+xuppJ2puckaiQU42Mfmw/Nj4LMEJLfc
+lQIwCYcv3uU8f9hvfI3D6oAj5Zrzwg737hXvnDhunlRwGMHWd7uKlStWcfm6fCXl
+LW0hAjEAneK0egVEp3IR+PyLdcL194UZFgSJKNj/nYiAaMdokjcf1o8jJ4qKvw/I
+MEIpvy9pAjAzaFHKRugCN01V2dgXYYGL8+zkcwG4ehDXH1XEs4v8r3WtHBPPKED6
+AemfAQJLvh8=
+-----END PRIVATE KEY-----
diff --git a/test/certs/setup.sh b/test/certs/setup.sh
index 9606c77bb7..f34104613f 100755
--- a/test/certs/setup.sh
+++ b/test/certs/setup.sh
@@ -32,6 +32,14 @@ openssl x509 -in root-nonca.pem -trustout \
openssl x509 -in root-nonca.pem -trustout \
-addtrust anyExtendedKeyUsage -out nroot+anyEKU.pem
+# Root CA security level variants:
+# MD5 self-signature
+OPENSSL_SIGALG=md5 \
+./mkcert.sh genroot "Root CA" root-key root-cert-md5
+# 768-bit key
+OPENSSL_KEYBITS=768 \
+./mkcert.sh genroot "Root CA" root-key-768 root-cert-768
+
# primary client-EKU root: croot-cert
# trust variants: +serverAuth -serverAuth +clientAuth +anyEKU -anyEKU
#
@@ -97,6 +105,18 @@ openssl x509 -in ca-nonca.pem -trustout \
openssl x509 -in ca-nonca.pem -trustout \
-addtrust serverAuth -out nca+anyEKU.pem
+# Intermediate CA security variants:
+# MD5 issuer signature,
+OPENSSL_SIGALG=md5 \
+./mkcert.sh genca "CA" ca-key ca-cert-md5 root-key root-cert
+openssl x509 -in ca-cert-md5.pem -trustout \
+ -addtrust anyExtendedKeyUsage -out ca-cert-md5-any.pem
+# Issuer has 768-bit key
+./mkcert.sh genca "CA" ca-key ca-cert-768i root-key-768 root-cert-768
+# CA has 768-bit key
+OPENSSL_KEYBITS=768 \
+./mkcert.sh genca "CA" ca-key-768 ca-cert-768 root-key root-cert
+
# client intermediate ca: cca-cert
# trust variants: +serverAuth, -serverAuth, +clientAuth, -clientAuth
#
@@ -152,3 +172,13 @@ openssl x509 -in ee-client.pem -trustout \
-addtrust clientAuth -out ee+clientAuth.pem
openssl x509 -in ee-client.pem -trustout \
-addreject clientAuth -out ee-clientAuth.pem
+
+# Leaf cert security level variants
+# MD5 issuer signature
+OPENSSL_SIGALG=md5 \
+./mkcert.sh genee server.example ee-key ee-cert-md5 ca-key ca-cert
+# 768-bit issuer key
+./mkcert.sh genee server.example ee-key ee-cert-768i ca-key-768 ca-cert-768
+# 768-bit leaf key
+OPENSSL_KEYBITS=768 \
+./mkcert.sh genee server.example ee-key-768 ee-cert-768 ca-key ca-cert
diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t
index d4131ccd3e..e025739368 100644
--- a/test/recipes/25-test_verify.t
+++ b/test/recipes/25-test_verify.t
@@ -10,7 +10,7 @@ setup("test_verify");
sub verify {
my ($cert, $purpose, $trusted, $untrusted, @opts) = @_;
- my @args = qw(openssl verify -purpose);
+ my @args = qw(openssl verify -auth_level 1 -purpose);
my @path = qw(test certs);
push(@args, "$purpose", @opts);
for (@$trusted) { push(@args, "-trusted", srctop_file(@path, "$_.pem")) }
@@ -19,7 +19,7 @@ sub verify {
run(app([@args]));
}
-plan tests => 83;
+plan tests => 101;
# Canonical success
ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]),
@@ -214,3 +214,47 @@ ok(verify("ee-client", "sslclient", [qw(ee+clientAuth)], [], "-partial_chain"),
"accept direct match with client trust");
ok(!verify("ee-client", "sslclient", [qw(ee-clientAuth)], [], "-partial_chain"),
"reject direct match with client mistrust");
+
+# Security level tests
+ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"], "-auth_level", "2"),
+ "accept RSA 2048 chain at auth level 2");
+ok(!verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"], "-auth_level", "3"),
+ "reject RSA 2048 root at auth level 3");
+ok(verify("ee-cert", "sslserver", ["root-cert-768"], ["ca-cert-768i"], "-auth_level", "0"),
+ "accept RSA 768 root at auth level 0");
+ok(!verify("ee-cert", "sslserver", ["root-cert-768"], ["ca-cert-768i"]),
+ "reject RSA 768 root at auth level 1");
+ok(verify("ee-cert-768i", "sslserver", ["root-cert"], ["ca-cert-768"], "-auth_level", "0"),
+ "accept RSA 768 intermediate at auth level 0");
+ok(!verify("ee-cert-768i", "sslserver", ["root-cert"], ["ca-cert-768"]),
+ "reject RSA 768 intermediate at auth level 1");
+ok(verify("ee-cert-768", "sslserver", ["root-cert"], ["ca-cert"], "-auth_level", "0"),
+ "accept RSA 768 leaf at auth level 0");
+ok(!verify("ee-cert-768", "sslserver", ["root-cert"], ["ca-cert"]),
+ "reject RSA 768 leaf at auth level 1");
+#
+ok(verify("ee-cert", "sslserver", ["root-cert-md5"], ["ca-cert"], "-auth_level", "2"),
+ "accept md5 self-signed TA at auth level 2");
+ok(verify("ee-cert", "sslserver", ["ca-cert-md5-any"], [], "-auth_level", "2"),
+ "accept md5 intermediate TA at auth level 2");
+ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert-md5"], "-auth_level", "0"),
+ "accept md5 intermediate at auth level 0");
+ok(!verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert-md5"]),
+ "reject md5 intermediate at auth level 1");
+ok(verify("ee-cert-md5", "sslserver", ["root-cert"], ["ca-cert"], "-auth_level", "0"),
+ "accept md5 leaf at auth level 0");
+ok(!verify("ee-cert-md5", "sslserver", ["root-cert"], ["ca-cert"]),
+ "reject md5 leaf at auth level 1");
+
+# Depth tests, note the depth limit bounds the number of CA certificates
+# between the trust-anchor and the leaf, so, for example, with a root->ca->leaf
+# chain, depth = 1 is sufficient, but depth == 0 is not.
+#
+ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"], "-verify_depth", "2"),
+ "accept chain with verify_depth 2");
+ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"], "-verify_depth", "1"),
+ "accept chain with verify_depth 1");
+ok(!verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"], "-verify_depth", "0"),
+ "accept chain with verify_depth 0");
+ok(verify("ee-cert", "sslserver", ["ca-cert-md5-any"], [], "-verify_depth", "0"),
+ "accept md5 intermediate TA with verify_depth 0");