From 63830384e90d9b36d2793d4891501ec024827433 Mon Sep 17 00:00:00 2001
From: Emilia Kasper <emilia@openssl.org>
Date: Tue, 19 May 2015 12:05:22 +0200
Subject: [PATCH 5/5] client: reject handshakes with DH parameters < 1024 bits.

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       |  3 ++-
 ssl/s3_clnt.c | 22 ++++++++++++++++------
 ssl/ssl.h     |  1 +
 ssl/ssl_err.c |  1 +
 4 files changed, 20 insertions(+), 7 deletions(-)

Index: openssl-1.0.1i/CHANGES
===================================================================
--- openssl-1.0.1i.orig/CHANGES	2015-06-12 13:25:24.308393444 +0200
+++ openssl-1.0.1i/CHANGES	2015-06-12 13:25:50.681740239 +0200
@@ -2,6 +2,9 @@
  OpenSSL CHANGES
  _______________
 
+  *) Reject DH handshakes with parameters shorter than 1024 bits.
+     [Kurt Roeckx and Emilia Kasper]
+
  Changes between 1.0.1h and 1.0.1i [6 Aug 2014]
   *) Add support for TLS_FALLBACK_SCSV.
      Client applications doing fallback retries should call
Index: openssl-1.0.1i/ssl/s3_clnt.c
===================================================================
--- openssl-1.0.1i.orig/ssl/s3_clnt.c	2015-06-12 13:25:24.309393457 +0200
+++ openssl-1.0.1i/ssl/s3_clnt.c	2015-06-12 13:29:40.896761553 +0200
@@ -3322,26 +3322,34 @@ 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 < 1024)
+            || (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: openssl-1.0.1i/ssl/ssl.h
===================================================================
--- openssl-1.0.1i.orig/ssl/ssl.h	2015-06-12 13:25:24.310393470 +0200
+++ openssl-1.0.1i/ssl/ssl.h	2015-06-12 13:30:24.446331928 +0200
@@ -2369,6 +2369,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: openssl-1.0.1i/ssl/ssl_err.c
===================================================================
--- openssl-1.0.1i.orig/ssl/ssl_err.c	2015-06-12 13:25:24.311393483 +0200
+++ openssl-1.0.1i/ssl/ssl_err.c	2015-06-12 13:30:48.525647135 +0200
@@ -363,6 +363,7 @@ static ERR_STRING_DATA SSL_str_reasons[]
 {ERR_REASON(SSL_R_DATA_LENGTH_TOO_LONG)  ,"data length too long"},
 {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"},
 {ERR_REASON(SSL_R_DTLS_MESSAGE_TOO_BIG)  ,"dtls message too big"},
