Don't negotiate TLSv1.3 if our EC cert isn't TLSv1.3 capable
authorMatt Caswell <matt@openssl.org>
Fri, 19 Oct 2018 13:01:22 +0000 (14:01 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 12 Nov 2018 11:08:51 +0000 (11:08 +0000)
TLSv1.3 is more restrictive about the curve used. There must be a matching
sig alg defined for that curve. Therefore if we are using some other curve
in our certificate then we should not negotiate TLSv1.3.

Fixes #7435

Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/7442)

ssl/ssl_locl.h
ssl/statem/statem_lib.c
ssl/t1_lib.c

index c22c1f9ee8f69a2f6507c0afd6d2e8ebc63ba404..46719b00cab204a903b4c65ff21fbbbcfe11f471 100644 (file)
@@ -2564,6 +2564,7 @@ __owur int tls1_process_sigalgs(SSL *s);
 __owur int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey);
 __owur int tls1_lookup_md(const SIGALG_LOOKUP *lu, const EVP_MD **pmd);
 __owur size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs);
+__owur int tls_check_sigalg_curve(const SSL *s, int curve);
 __owur int tls12_check_peer_sigalg(SSL *s, uint16_t, EVP_PKEY *pkey);
 __owur int ssl_set_client_disabled(SSL *s);
 __owur int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op, int echde);
index 75cf321b9868a7807766aea98a72625033f82c98..dc2bd20e936d22efbb4f0d2b329d0f57c1c30d98 100644 (file)
@@ -1506,7 +1506,8 @@ static int ssl_method_error(const SSL *s, const SSL_METHOD *method)
  */
 static int is_tls13_capable(const SSL *s)
 {
-    int i;
+    int i, curve;
+    EC_KEY *eckey;
 
 #ifndef OPENSSL_NO_PSK
     if (s->psk_server_callback != NULL)
@@ -1527,7 +1528,20 @@ static int is_tls13_capable(const SSL *s)
         default:
             break;
         }
-        if (ssl_has_cert(s, i))
+        if (!ssl_has_cert(s, i))
+            continue;
+        if (i != SSL_PKEY_ECC)
+            return 1;
+        /*
+         * Prior to TLSv1.3 sig algs allowed any curve to be used. TLSv1.3 is
+         * more restrictive so check that our sig algs are consistent with this
+         * EC cert. See section 4.2.3 of RFC8446.
+         */
+        eckey = EVP_PKEY_get0_EC_KEY(s->cert->pkeys[SSL_PKEY_ECC].privatekey);
+        if (eckey == NULL)
+            continue;
+        curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey));
+        if (tls_check_sigalg_curve(s, curve))
             return 1;
     }
 
index 91353e738a0f7b00799589c2e0962aef8af9fe48..ddafa0c623dab82f18e738609f8dd344bd3c8353 100644 (file)
@@ -949,6 +949,37 @@ size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs)
     }
 }
 
+/*
+ * Called by servers only. Checks that we have a sig alg that supports the
+ * specified EC curve.
+ */
+int tls_check_sigalg_curve(const SSL *s, int curve)
+{
+   const uint16_t *sigs;
+   size_t siglen, i;
+
+    if (s->cert->conf_sigalgs) {
+        sigs = s->cert->conf_sigalgs;
+        siglen = s->cert->conf_sigalgslen;
+    } else {
+        sigs = tls12_sigalgs;
+        siglen = OSSL_NELEM(tls12_sigalgs);
+    }
+
+    for (i = 0; i < siglen; i++) {
+        const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(sigs[i]);
+
+        if (lu == NULL)
+            continue;
+        if (lu->sig == EVP_PKEY_EC
+                && lu->curve != NID_undef
+                && curve == lu->curve)
+            return 1;
+    }
+
+    return 0;
+}
+
 /*
  * Check signature algorithm is consistent with sent supported signature
  * algorithms and if so set relevant digest and signature scheme in