Move peer chain security checks into x509_vfy.c
authorViktor Dukhovni <openssl-users@dukhovni.org>
Sat, 19 Mar 2016 02:09:41 +0000 (22:09 -0400)
committerViktor Dukhovni <openssl-users@dukhovni.org>
Sun, 3 Apr 2016 15:35:35 +0000 (11:35 -0400)
A new X509_VERIFY_PARAM_set_auth_level() function sets the
authentication security level.  For verification of SSL peers, this
is automatically set from the SSL security level.  Otherwise, for
now, the authentication security level remains at (effectively) 0
by default.

The new "-auth_level" verify(1) option is available in all the
command-line tools that support the standard verify(1) options.

New verify(1) tests added to check enforcement of chain signature
and public key security levels.  Also added new tests of enforcement
of the verify_depth limit.

Updated documentation.

Reviewed-by: Dr. Stephen Henson <steve@openssl.org>
31 files changed:
apps/apps.h
apps/opt.c
crypto/x509/x509_lcl.h
crypto/x509/x509_txt.c
crypto/x509/x509_vfy.c
crypto/x509/x509_vpm.c
doc/apps/cms.pod
doc/apps/ocsp.pod
doc/apps/s_client.pod
doc/apps/s_server.pod
doc/apps/smime.pod
doc/apps/ts.pod
doc/apps/verify.pod
doc/crypto/X509_VERIFY_PARAM_set_flags.pod
include/openssl/x509_vfy.h
ssl/ssl_cert.c
test/certs/ca-cert-768.pem [new file with mode: 0644]
test/certs/ca-cert-768i.pem [new file with mode: 0644]
test/certs/ca-cert-md5-any.pem [new file with mode: 0644]
test/certs/ca-cert-md5.pem [new file with mode: 0644]
test/certs/ca-key-768.pem [new file with mode: 0644]
test/certs/ee-cert-768.pem [new file with mode: 0644]
test/certs/ee-cert-768i.pem [new file with mode: 0644]
test/certs/ee-cert-md5.pem [new file with mode: 0644]
test/certs/ee-key-768.pem [new file with mode: 0644]
test/certs/mkcert.sh
test/certs/root-cert-768.pem [new file with mode: 0644]
test/certs/root-cert-md5.pem [new file with mode: 0644]
test/certs/root-key-768.pem [new file with mode: 0644]
test/certs/setup.sh
test/recipes/25-test_verify.t

index 434ca54b7daf7f544d4653dcb859d52cc6a3e0d9..a310dd2b7831ec2e4fa5a9bf26c91773d396ddda 100644 (file)
@@ -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: \
index af994bb74318ee98f95bd3bc638f70226842b6b2..462894a9380b5523b02d5568554f4bf356db7966 100644 (file)
@@ -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;
index 0726201e8f90abcd63009a5be9fe6671c5282217..603c17737f1b0f84d585b0b9eaa88b1b6d0f8b22 100644 (file)
@@ -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 */
index f7f27e97ef37f4207bc91733498f4ec20ca7b6dd..8a9a7f04449a542fa2f4b4439c571b570a2db0a0 100644 (file)
@@ -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 */
index 92f1c5c44751f46ca1ec24d597b5828d125c90ee..10fbeeff6d41735f2df537429f2e53a4939149ea 100644 (file)
@@ -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,22 +2958,20 @@ 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.
              */
@@ -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];
+}
index 41b0fde4a55067ff2dbdf1390e015f48d97b79b1..4a0bed021c4606f35c525b60101e7ce538dde2c3 100644 (file)
@@ -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}
 };
index 36e6b3ca3ac1ab4cec8f002d62fd3f2e8e9ccff1..42c351489cd402c7164f4d550f352c48a0f8585e 100644 (file)
@@ -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.
index be195bcb308fda2b0ad0a9c66f59d420f161ada3..c796fd5966d86983cfa0a1b6f778f58009e99448 100644 (file)
@@ -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>
 
index 1873293ea836f552c8d508a55595e7c40899ce82..881fbcfefe1be6e2eb9529193604f98a9edb5513 100644 (file)
@@ -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.
index 25e544468a6444030f15d0b6f540e80d03caf45c..08554f453046affdeac486b03fe8c867e19ed79d 100644 (file)
@@ -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.
index 418d8faa2d5e47ffcd3e7c533cb8b0e4ce562807..e6323ad0b026baa5387da4847785915009c853d9 100644 (file)
@@ -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.
index 93ea9e059ae62fb954e98dfc1c946149808ffc15..e64e5fcf34c5a47712c52136abd7e95776bc7aae 100644 (file)
@@ -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
 
index ecde35fe8a813eb34d804e150128bd6cce51555e..96d6be4a4db992a160f731e4ec9d726f5333af9d 100644 (file)
@@ -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>
 
index 6fb33edd9101312b0e9e3d772e3b8fe4553393cb..04f521506fc0d133ff58496b0645af1e5ff263e9 100644 (file)
@@ -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
index e883349d3481722c41c1b353049e311015333bd3..093b0f3d0ae5b4bddc606390bff86b1e2ee766d0 100644 (file)
@@ -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);
index 4081ebe4ffbdcfcb0895b1e04d69c2684bfcf0de..24ac352d1da47c4644475b5d55069be32bed1f30 100644 (file)
@@ -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 (file)
index 0000000..0c8ff29
--- /dev/null
@@ -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 (file)
index 0000000..acc432f
--- /dev/null
@@ -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 (file)
index 0000000..7c2b53f
--- /dev/null
@@ -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 (file)
index 0000000..be564dd
--- /dev/null
@@ -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 (file)
index 0000000..7aea5ed
--- /dev/null
@@ -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 (file)
index 0000000..794f93c
--- /dev/null
@@ -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 (file)
index 0000000..d6532fb
--- /dev/null
@@ -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 (file)
index 0000000..8c26422
--- /dev/null
@@ -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 (file)
index 0000000..0d44f85
--- /dev/null
@@ -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-----
index 99e7d2a342a6512eb6a83cdfb960c3ca1f497dbd..ec2e3740380bb2a6dbe43c1d0e6f77899c9495b1 100755 (executable)
 #
 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 (file)
index 0000000..4392ef0
--- /dev/null
@@ -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 (file)
index 0000000..b6ed10c
--- /dev/null
@@ -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 (file)
index 0000000..4ecdcd3
--- /dev/null
@@ -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-----
index 9606c77bb79b30b524cbf4dae37a3a04e4289277..f34104613fb0ea4945a9e5473ec46b2107f00efb 100755 (executable)
@@ -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
index d4131ccd3eb52dcdd4e146808bb430bdc5a7b215..e0257393683bd5dc57f211cda5f3a8ffaedcf25b 100644 (file)
@@ -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");