client: reject handshakes with DH parameters < 768 bits.
authorEmilia Kasper <emilia@openssl.org>
Tue, 19 May 2015 10:05:22 +0000 (12:05 +0200)
committerEmilia Kasper <emilia@openssl.org>
Wed, 20 May 2015 13:01:36 +0000 (15:01 +0200)
Since the client has no way of communicating her supported parameter
range to the server, connections to servers that choose weak DH will
simply fail.

Reviewed-by: Kurt Roeckx <kurt@openssl.org>
CHANGES
ssl/s3_clnt.c
ssl/ssl.h
ssl/ssl_err.c

diff --git a/CHANGES b/CHANGES
index 11bdbbd6926dec9a07e0487ead491e52e7721d4f..9d2f9f9fa8bd2145b8591c12b8d62a4f3aafc67d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,7 +4,8 @@
 
  Changes between 1.0.1m and 1.0.1n [xx XXX xxxx]
 
-  *)
+  *) Reject DH handshakes with parameters shorter than 768 bits.
+     [Kurt Roeckx and Emilia Kasper]
 
  Changes between 1.0.1l and 1.0.1m [19 Mar 2015]
 
index a521d56fe4fdf20182531d980edc81f456e4d4a9..780a03f1e6e852f7539e55e7061ba057be9c46c1 100644 (file)
@@ -3295,23 +3295,33 @@ int ssl3_check_cert_and_algorithm(SSL *s)
     }
 #endif
 #ifndef OPENSSL_NO_DH
-    if ((alg_k & SSL_kEDH) &&
-        !(has_bits(i, EVP_PK_DH | EVP_PKT_EXCH) || (dh != NULL))) {
-        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_DH_KEY);
+    if ((alg_k & SSL_kEDH) && dh == NULL) {
+        SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR);
         goto f_err;
-    } else if ((alg_k & SSL_kDHr) && !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
+    }
+    if ((alg_k & SSL_kDHr) && !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) {
         SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
                SSL_R_MISSING_DH_RSA_CERT);
         goto f_err;
     }
 # ifndef OPENSSL_NO_DSA
-    else if ((alg_k & SSL_kDHd) && !has_bits(i, EVP_PK_DH | EVP_PKS_DSA)) {
+    if ((alg_k & SSL_kDHd) && !has_bits(i, EVP_PK_DH | EVP_PKS_DSA)) {
         SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,
                SSL_R_MISSING_DH_DSA_CERT);
         goto f_err;
     }
 # endif
-#endif
+
+    /* Check DHE only: static DH not implemented. */
+    if (alg_k & SSL_kEDH) {
+        int dh_size = BN_num_bits(dh->p);
+        if ((!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 768)
+            || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 512)) {
+            SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_DH_KEY_TOO_SMALL);
+            goto f_err;
+        }
+    }
+#endif  /* !OPENSSL_NO_DH */
 
     if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i, EVP_PKT_EXP)) {
 #ifndef OPENSSL_NO_RSA
index 62472a1e3c0166e1f5e70b8af64beaf8f75b96fe..32e27c6fbf91b47f6c12af9eb016640115c1f8a9 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -2524,6 +2524,7 @@ void ERR_load_SSL_strings(void);
 # define SSL_R_DATA_LENGTH_TOO_LONG                       146
 # define SSL_R_DECRYPTION_FAILED                          147
 # define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC        281
+# define SSL_R_DH_KEY_TOO_SMALL                           372
 # define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG            148
 # define SSL_R_DIGEST_CHECK_FAILED                        149
 # define SSL_R_DTLS_MESSAGE_TOO_BIG                       334
index 835b43ce67cbd453ba295e7ae65a2b2fddbc1279..fef324d46295b79f2bf37624d5940ec84015cee6 100644 (file)
@@ -441,6 +441,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_REASON(SSL_R_DECRYPTION_FAILED), "decryption failed"},
     {ERR_REASON(SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC),
      "decryption failed or bad record mac"},
+    {ERR_REASON(SSL_R_DH_KEY_TOO_SMALL), "dh key too small"},
     {ERR_REASON(SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG),
      "dh public value length is wrong"},
     {ERR_REASON(SSL_R_DIGEST_CHECK_FAILED), "digest check failed"},