Check Suite-B constraints with EE DANE records
[openssl.git] / crypto / x509 / x509_vfy.c
index c395acc0128fd28c1343f99be233a5b908477b6e..c9dd6fa60cbd1aa31e00509a6eca1702b5e2a380 100644 (file)
@@ -193,7 +193,6 @@ static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
 
 static int verify_chain(X509_STORE_CTX *ctx)
 {
-    int (*cb) (int xok, X509_STORE_CTX *xctx) = ctx->verify_cb;
     int err;
     int ok;
 
@@ -214,7 +213,7 @@ static int verify_chain(X509_STORE_CTX *ctx)
     if (err != X509_V_OK) {
         ctx->error = err;
         ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth);
-        if ((ok = cb(0, ctx)) == 0)
+        if ((ok = ctx->verify_cb(0, ctx)) == 0)
             return ok;
     }
 
@@ -344,6 +343,26 @@ static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
         return 0;
 }
 
+static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, X509_NAME *nm)
+{
+    STACK_OF(X509) *sk = NULL;
+    X509 *x;
+    int i;
+    for (i = 0; i < sk_X509_num(ctx->other_ctx); i++) {
+        x = sk_X509_value(ctx->other_ctx, i);
+        if (X509_NAME_cmp(nm, X509_get_subject_name(x)) == 0) {
+            if (sk == NULL)
+                sk = sk_X509_new_null();
+            if (sk == NULL || sk_X509_push(sk, x) == 0) {
+                sk_X509_pop_free(sk, X509_free);
+                return NULL;
+            }
+            X509_up_ref(x);
+        }
+    }
+    return sk;
+}
+
 /*
  * Check a certificate chains extensions for consistency with the supplied
  * purpose
@@ -353,11 +372,9 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
 {
     int i, ok = 0, must_be_ca, plen = 0;
     X509 *x;
-    int (*cb) (int xok, X509_STORE_CTX *xctx);
     int proxy_path_length = 0;
     int purpose;
     int allow_proxy_certs;
-    cb = ctx->verify_cb;
 
     /*-
      *  must_be_ca can have 1 of 3 values:
@@ -395,7 +412,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
             ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
             ctx->error_depth = i;
             ctx->current_cert = x;
-            ok = cb(0, ctx);
+            ok = ctx->verify_cb(0, ctx);
             if (!ok)
                 goto end;
         }
@@ -403,7 +420,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
             ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
             ctx->error_depth = i;
             ctx->current_cert = x;
-            ok = cb(0, ctx);
+            ok = ctx->verify_cb(0, ctx);
             if (!ok)
                 goto end;
         }
@@ -437,7 +454,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
         if (ret == 0) {
             ctx->error_depth = i;
             ctx->current_cert = x;
-            ok = cb(0, ctx);
+            ok = ctx->verify_cb(0, ctx);
             if (!ok)
                 goto end;
         }
@@ -449,7 +466,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
                 ctx->error = X509_V_ERR_INVALID_PURPOSE;
                 ctx->error_depth = i;
                 ctx->current_cert = x;
-                ok = cb(0, ctx);
+                ok = ctx->verify_cb(0, ctx);
                 if (!ok)
                     goto end;
             }
@@ -461,7 +478,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
             ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED;
             ctx->error_depth = i;
             ctx->current_cert = x;
-            ok = cb(0, ctx);
+            ok = ctx->verify_cb(0, ctx);
             if (!ok)
                 goto end;
         }
@@ -478,7 +495,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
                 ctx->error = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
                 ctx->error_depth = i;
                 ctx->current_cert = x;
-                ok = cb(0, ctx);
+                ok = ctx->verify_cb(0, ctx);
                 if (!ok)
                     goto end;
             }
@@ -575,12 +592,15 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
     int i, ok = 0;
     X509 *x = NULL;
     X509 *mx;
-    int (*cb) (int xok, X509_STORE_CTX *xctx) = ctx->verify_cb;
     struct dane_st *dane = (struct dane_st *)ctx->dane;
     int num = sk_X509_num(ctx->chain);
     int trust;
 
-    if (DANETLS_HAS_TA(dane) && num_untrusted > 0) {
+    /*
+     * Check for a DANE issuer at depth 1 or greater, if it is a DANE-TA(2)
+     * match, we're done, otherwise we'll merely record the match depth.
+     */
+    if (DANETLS_HAS_TA(dane) && num_untrusted > 0 && num_untrusted < num) {
         switch (trust = check_dane_issuer(ctx, num_untrusted)) {
         case X509_TRUST_TRUSTED:
         case X509_TRUST_REJECTED:
@@ -614,12 +634,13 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
         return X509_TRUST_UNTRUSTED;
     }
 
-    if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
+    if (num_untrusted == num && ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) {
         /*
          * Last-resort call with no new trusted certificates, check the leaf
          * for a direct trust store match.
          */
-        x = sk_X509_value(ctx->chain, 0);
+        i = 0;
+        x = sk_X509_value(ctx->chain, i);
         mx = lookup_cert_match(ctx, x);
         if (!mx)
             return X509_TRUST_UNTRUSTED;
@@ -651,7 +672,7 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted)
     ctx->error_depth = i;
     ctx->current_cert = x;
     ctx->error = X509_V_ERR_CERT_REJECTED;
-    ok = cb(0, ctx);
+    ok = ctx->verify_cb(0, ctx);
     if (!ok)
         return X509_TRUST_REJECTED;
     return X509_TRUST_UNTRUSTED;
@@ -1543,9 +1564,6 @@ static int internal_verify(X509_STORE_CTX *ctx)
     int ok = 0, n;
     X509 *xs, *xi;
     EVP_PKEY *pkey = NULL;
-    int (*cb) (int xok, X509_STORE_CTX *xctx);
-
-    cb = ctx->verify_cb;
 
     n = sk_X509_num(ctx->chain) - 1;
     ctx->error_depth = n;
@@ -1572,7 +1590,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
         if (n <= 0) {
             ctx->error = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
             ctx->current_cert = xi;
-            ok = cb(0, ctx);
+            ok = ctx->verify_cb(0, ctx);
             goto end;
         } else {
             n--;
@@ -1593,26 +1611,22 @@ static int internal_verify(X509_STORE_CTX *ctx)
          * explicitly asked for. It doesn't add any security and just wastes
          * time.
          */
-        if (!xs->valid
-            && (xs != xi
-                || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE))) {
+        if (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE)) {
             if ((pkey = X509_get0_pubkey(xi)) == NULL) {
                 ctx->error = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
                 ctx->current_cert = xi;
-                ok = (*cb) (0, ctx);
+                ok = ctx->verify_cb(0, ctx);
                 if (!ok)
                     goto end;
             } else if (X509_verify(xs, pkey) <= 0) {
                 ctx->error = X509_V_ERR_CERT_SIGNATURE_FAILURE;
                 ctx->current_cert = xs;
-                ok = (*cb) (0, ctx);
+                ok = ctx->verify_cb(0, ctx);
                 if (!ok)
                     goto end;
             }
         }
 
-        xs->valid = 1;
-
  check_cert:
         ok = x509_check_cert_time(ctx, xs, 0);
         if (!ok)
@@ -1621,7 +1635,7 @@ static int internal_verify(X509_STORE_CTX *ctx)
         /* The last error (if any) is still in the error value */
         ctx->current_issuer = xi;
         ctx->current_cert = xs;
-        ok = (*cb) (1, ctx);
+        ok = ctx->verify_cb(1, ctx);
         if (!ok)
             goto end;
 
@@ -2221,6 +2235,7 @@ void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk)
 {
     ctx->other_ctx = sk;
     ctx->get_issuer = get_issuer_sk;
+    ctx->lookup_certs = lookup_certs_sk;
 }
 
 void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx)
@@ -2562,10 +2577,21 @@ static void dane_reset(struct dane_st *dane)
     dane->pdpth = -1;
 }
 
+static int check_leaf_suiteb(X509_STORE_CTX *ctx, X509 *cert)
+{
+    int err = X509_chain_check_suiteb(NULL, cert, NULL, ctx->param->flags);
+
+    if (err == X509_V_OK)
+        return 1;
+    ctx->current_cert = cert;
+    ctx->error_depth = 0;
+    ctx->error = err;
+    return ctx->verify_cb(0, ctx);
+}
+
 static int dane_verify(X509_STORE_CTX *ctx)
 {
     X509 *cert = ctx->cert;
-    int (*cb)(int xok, X509_STORE_CTX *xctx) = ctx->verify_cb;
     struct dane_st *dane = (struct dane_st *)ctx->dane;
     int matched;
     int done;
@@ -2579,9 +2605,11 @@ static int dane_verify(X509_STORE_CTX *ctx)
         X509_get_pubkey_parameters(NULL, ctx->chain);
 
     if (matched > 0) {
+        if (!check_leaf_suiteb(ctx, cert))
+            return 0;
         ctx->error_depth = 0;
         ctx->current_cert = cert;
-        return cb(1, ctx);
+        return ctx->verify_cb(1, ctx);
     }
 
     if (matched < 0) {
@@ -2593,10 +2621,12 @@ static int dane_verify(X509_STORE_CTX *ctx)
 
     if (done) {
         /* Fail early, TA-based success is not possible */
+        if (!check_leaf_suiteb(ctx, cert))
+            return 0;
         ctx->current_cert = cert;
         ctx->error_depth = 0;
         ctx->error = X509_V_ERR_CERT_UNTRUSTED;
-        return cb(0, ctx);
+        return ctx->verify_cb(0, ctx);
     }
 
     /*
@@ -2609,7 +2639,6 @@ static int dane_verify(X509_STORE_CTX *ctx)
 static int build_chain(X509_STORE_CTX *ctx)
 {
     struct dane_st *dane = (struct dane_st *)ctx->dane;
-    int (*cb) (int, X509_STORE_CTX *) = ctx->verify_cb;
     int num = sk_X509_num(ctx->chain);
     X509 *cert = sk_X509_value(ctx->chain, num - 1);
     int ss = cert_self_signed(cert);
@@ -2889,12 +2918,12 @@ static int build_chain(X509_STORE_CTX *ctx)
      * Last chance to make a trusted chain, either bare DANE-TA public-key
      * signers, or else direct leaf PKIX trust.
      */
-    if (sk_X509_num(ctx->chain) <= depth) {
+    num = sk_X509_num(ctx->chain);
+    if (num <= depth) {
         if (trust == X509_TRUST_UNTRUSTED && DANETLS_HAS_DANE_TA(dane))
             trust = check_dane_pkeys(ctx);
-        if (trust == X509_TRUST_UNTRUSTED &&
-            sk_X509_num(ctx->chain) == ctx->num_untrusted)
-            trust = check_trust(ctx, 1);
+        if (trust == X509_TRUST_UNTRUSTED && num == ctx->num_untrusted)
+            trust = check_trust(ctx, num);
     }
 
     switch (trust) {
@@ -2922,6 +2951,6 @@ static int build_chain(X509_STORE_CTX *ctx)
             ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
         if (DANETLS_ENABLED(dane))
             dane_reset(dane);
-        return cb(0, ctx);
+        return ctx->verify_cb(0, ctx);
     }
 }