Support for fixed DH ciphersuites.

The cipher definitions of these ciphersuites have been around since SSLeay
but were always disabled. Now OpenSSL supports DH certificates they can be
finally enabled.

Various additional changes were needed to make them work properly: many
unused fixed DH sections of code were untested.
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index be766aa..c58713f 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -594,6 +594,18 @@
 		{
 		ret = SSL_PKEY_GOST01;
 		}
+	else if (x && i == EVP_PKEY_DH)
+		{
+		/* For DH two cases: DH certificate signed with RSA and
+		 * DH certificate signed with DSA.
+		 */
+		i = X509_certificate_type(x, pk);
+		if (i & EVP_PKS_RSA)
+			ret = SSL_PKEY_DH_RSA;
+		else if (i & EVP_PKS_DSA)
+			ret = SSL_PKEY_DH_DSA;
+		}
+		
 err:
 	if(!pkey) EVP_PKEY_free(pk);
 	return(ret);
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 3a27f93..62648fe 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -2396,24 +2396,39 @@
 		else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
 			{
 			DH *dh_srvr,*dh_clnt;
+			SESS_CERT *scert = s->session->sess_cert;
 
-			if (s->session->sess_cert == NULL) 
+			if (scert == NULL) 
 				{
 				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
 				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
 				goto err;
 				}
 
-			if (s->session->sess_cert->peer_dh_tmp != NULL)
-				dh_srvr=s->session->sess_cert->peer_dh_tmp;
+			if (scert->peer_dh_tmp != NULL)
+				dh_srvr=scert->peer_dh_tmp;
 			else
 				{
 				/* we get them from the cert */
-				ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
-				SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
-				goto err;
+				int idx = scert->peer_cert_type;
+				EVP_PKEY *spkey = NULL;
+				dh_srvr = NULL;
+				if (idx >= 0)
+					spkey = X509_get_pubkey(
+						scert->peer_pkeys[idx].x509);
+				if (spkey)
+					{
+					dh_srvr = EVP_PKEY_get1_DH(spkey);
+					EVP_PKEY_free(spkey);
+					}
+				if (dh_srvr == NULL)
+					{
+					SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+					    ERR_R_INTERNAL_ERROR);
+					goto err;
+					}
 				}
-			
+
 			/* generate a new random key */
 			if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
 				{
@@ -2431,6 +2446,8 @@
 			 * make sure to clear it out afterwards */
 
 			n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
+			if (scert->peer_dh_tmp == NULL)
+				DH_free(dh_srvr);
 
 			if (n <= 0)
 				{
@@ -3132,7 +3149,7 @@
 	alg_a=s->s3->tmp.new_cipher->algorithm_auth;
 
 	/* we don't have a certificate */
-	if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+	if ((alg_a & (SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
 		return(1);
 
 	sc=s->session->sess_cert;
@@ -3194,19 +3211,21 @@
 		}
 #endif
 #ifndef OPENSSL_NO_DH
-	if ((alg_k & SSL_kEDH) &&
+	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);
 		goto f_err;
 		}
-	else if ((alg_k & SSL_kDHr) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
+	else if ((alg_k & SSL_kDHr) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+		!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))
+	else if ((alg_k & SSL_kDHd) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+		!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;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 3e4a95d..b488cdb 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -335,7 +335,7 @@
 /* The DH ciphers */
 /* Cipher 0B */
 	{
-	0,
+	1,
 	SSL3_TXT_DH_DSS_DES_40_CBC_SHA,
 	SSL3_CK_DH_DSS_DES_40_CBC_SHA,
 	SSL_kDHd,
@@ -351,7 +351,7 @@
 
 /* Cipher 0C */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	SSL3_TXT_DH_DSS_DES_64_CBC_SHA,
 	SSL3_CK_DH_DSS_DES_64_CBC_SHA,
 	SSL_kDHd,
@@ -367,7 +367,7 @@
 
 /* Cipher 0D */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	SSL3_TXT_DH_DSS_DES_192_CBC3_SHA,
 	SSL3_CK_DH_DSS_DES_192_CBC3_SHA,
 	SSL_kDHd,
@@ -383,7 +383,7 @@
 
 /* Cipher 0E */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	SSL3_TXT_DH_RSA_DES_40_CBC_SHA,
 	SSL3_CK_DH_RSA_DES_40_CBC_SHA,
 	SSL_kDHr,
@@ -399,7 +399,7 @@
 
 /* Cipher 0F */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	SSL3_TXT_DH_RSA_DES_64_CBC_SHA,
 	SSL3_CK_DH_RSA_DES_64_CBC_SHA,
 	SSL_kDHr,
@@ -415,7 +415,7 @@
 
 /* Cipher 10 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	SSL3_TXT_DH_RSA_DES_192_CBC3_SHA,
 	SSL3_CK_DH_RSA_DES_192_CBC3_SHA,
 	SSL_kDHr,
@@ -902,7 +902,7 @@
 	},
 /* Cipher 30 */
 	{
-	0,
+	1,
 	TLS1_TXT_DH_DSS_WITH_AES_128_SHA,
 	TLS1_CK_DH_DSS_WITH_AES_128_SHA,
 	SSL_kDHd,
@@ -917,7 +917,7 @@
 	},
 /* Cipher 31 */
 	{
-	0,
+	1,
 	TLS1_TXT_DH_RSA_WITH_AES_128_SHA,
 	TLS1_CK_DH_RSA_WITH_AES_128_SHA,
 	SSL_kDHr,
@@ -993,7 +993,7 @@
 	},
 /* Cipher 36 */
 	{
-	0,
+	1,
 	TLS1_TXT_DH_DSS_WITH_AES_256_SHA,
 	TLS1_CK_DH_DSS_WITH_AES_256_SHA,
 	SSL_kDHd,
@@ -1009,7 +1009,7 @@
 
 /* Cipher 37 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_RSA_WITH_AES_256_SHA,
 	TLS1_CK_DH_RSA_WITH_AES_256_SHA,
 	SSL_kDHr,
@@ -1122,7 +1122,7 @@
 
 	/* Cipher 3E */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_DSS_WITH_AES_128_SHA256,
 	TLS1_CK_DH_DSS_WITH_AES_128_SHA256,
 	SSL_kDHr,
@@ -1138,7 +1138,7 @@
 
 	/* Cipher 3F */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_RSA_WITH_AES_128_SHA256,
 	TLS1_CK_DH_RSA_WITH_AES_128_SHA256,
 	SSL_kDHr,
@@ -1189,7 +1189,7 @@
 
 	/* Cipher 42 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
 	TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
 	SSL_kDHd,
@@ -1205,7 +1205,7 @@
 
 	/* Cipher 43 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
 	TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
 	SSL_kDHr,
@@ -1404,7 +1404,7 @@
 
 	/* Cipher 68 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_DSS_WITH_AES_256_SHA256,
 	TLS1_CK_DH_DSS_WITH_AES_256_SHA256,
 	SSL_kDHr,
@@ -1420,7 +1420,7 @@
 
 	/* Cipher 69 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_RSA_WITH_AES_256_SHA256,
 	TLS1_CK_DH_RSA_WITH_AES_256_SHA256,
 	SSL_kDHr,
@@ -1577,7 +1577,7 @@
 	},
 	/* Cipher 85 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
 	TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
 	SSL_kDHd,
@@ -1593,7 +1593,7 @@
 
 	/* Cipher 86 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
 	TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
 	SSL_kDHr,
@@ -1743,7 +1743,7 @@
 
 	/* Cipher 97 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_DSS_WITH_SEED_SHA,
 	TLS1_CK_DH_DSS_WITH_SEED_SHA,
 	SSL_kDHd,
@@ -1759,7 +1759,7 @@
 
 	/* Cipher 98 */
 	{
-	0, /* not implemented (non-ephemeral DH) */
+	1,
 	TLS1_TXT_DH_RSA_WITH_SEED_SHA,
 	TLS1_CK_DH_RSA_WITH_SEED_SHA,
 	SSL_kDHr,
@@ -1891,7 +1891,7 @@
 
 	/* Cipher A0 */
 	{
-	0,
+	1,
 	TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256,
 	TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256,
 	SSL_kDHr,
@@ -1907,7 +1907,7 @@
 
 	/* Cipher A1 */
 	{
-	0,
+	1,
 	TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384,
 	TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384,
 	SSL_kDHr,
@@ -1955,7 +1955,7 @@
 
 	/* Cipher A4 */
 	{
-	0,
+	1,
 	TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256,
 	TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256,
 	SSL_kDHr,
@@ -1971,7 +1971,7 @@
 
 	/* Cipher A5 */
 	{
-	0,
+	1,
 	TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384,
 	TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384,
 	SSL_kDHr,
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 53b3515..a23d36f 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -478,7 +478,7 @@
 			    /* SRP: send ServerKeyExchange */
 			    || (alg_k & SSL_kSRP)
 #endif
-			    || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH))
+			    || (alg_k & SSL_kEDH)
 			    || (alg_k & SSL_kEECDH)
 			    || ((alg_k & SSL_kRSA)
 				&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
@@ -2289,7 +2289,25 @@
 			}
 		else
 			{
-			if (s->s3->tmp.dh == NULL)
+			int idx = -1;
+			if (alg_k & SSL_kDHr)
+				idx = SSL_PKEY_DH_RSA;
+			else if (alg_k & SSL_kDHd)
+				idx = SSL_PKEY_DH_DSA;
+			if (idx >= 0)
+				{
+				EVP_PKEY *skey = s->cert->pkeys[idx].privatekey;
+				if ((skey == NULL) ||
+					(skey->type != EVP_PKEY_DH) ||
+					(skey->pkey.dh == NULL))
+					{
+					al=SSL_AD_HANDSHAKE_FAILURE;
+					SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
+					goto f_err;
+					}
+				dh_srvr = skey->pkey.dh;
+				}
+			else if (s->s3->tmp.dh == NULL)
 				{
 				al=SSL_AD_HANDSHAKE_FAILURE;
 				SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 9ce2684..4b7397f 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -241,9 +241,9 @@
 #define	SSL_TXT_NULL		"NULL"
 
 #define SSL_TXT_kRSA		"kRSA"
-#define SSL_TXT_kDHr		"kDHr" /* no such ciphersuites supported! */
-#define SSL_TXT_kDHd		"kDHd" /* no such ciphersuites supported! */
-#define SSL_TXT_kDH 		"kDH"  /* no such ciphersuites supported! */
+#define SSL_TXT_kDHr		"kDHr" 
+#define SSL_TXT_kDHd		"kDHd"
+#define SSL_TXT_kDH 		"kDH"
 #define SSL_TXT_kEDH		"kEDH"
 #define SSL_TXT_kKRB5     	"kKRB5"
 #define SSL_TXT_kECDHr		"kECDHr"
@@ -256,7 +256,7 @@
 
 #define	SSL_TXT_aRSA		"aRSA"
 #define	SSL_TXT_aDSS		"aDSS"
-#define	SSL_TXT_aDH		"aDH" /* no such ciphersuites supported! */
+#define	SSL_TXT_aDH		"aDH"
 #define	SSL_TXT_aECDH		"aECDH"
 #define SSL_TXT_aKRB5     	"aKRB5"
 #define SSL_TXT_aECDSA		"aECDSA"
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index ac643c9..c12a7a2 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -238,9 +238,9 @@
 	 * e.g. kEDH combines DHE_DSS and DHE_RSA) */
 	{0,SSL_TXT_kRSA,0,    SSL_kRSA,  0,0,0,0,0,0,0,0},
 
-	{0,SSL_TXT_kDHr,0,    SSL_kDHr,  0,0,0,0,0,0,0,0}, /* no such ciphersuites supported! */
-	{0,SSL_TXT_kDHd,0,    SSL_kDHd,  0,0,0,0,0,0,0,0}, /* no such ciphersuites supported! */
-	{0,SSL_TXT_kDH,0,     SSL_kDHr|SSL_kDHd,0,0,0,0,0,0,0,0}, /* no such ciphersuites supported! */
+	{0,SSL_TXT_kDHr,0,    SSL_kDHr,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kDHd,0,    SSL_kDHd,  0,0,0,0,0,0,0,0},
+	{0,SSL_TXT_kDH,0,     SSL_kDHr|SSL_kDHd,0,0,0,0,0,0,0,0},
 	{0,SSL_TXT_kEDH,0,    SSL_kEDH,  0,0,0,0,0,0,0,0},
 	{0,SSL_TXT_DH,0,      SSL_kDHr|SSL_kDHd|SSL_kEDH,0,0,0,0,0,0,0,0},
 
@@ -701,8 +701,6 @@
 #ifdef OPENSSL_NO_DSA
 	*auth |= SSL_aDSS;
 #endif
-	*mkey |= SSL_kDHr|SSL_kDHd; /* no such ciphersuites supported! */
-	*auth |= SSL_aDH;
 #ifdef OPENSSL_NO_DH
 	*mkey |= SSL_kDHr|SSL_kDHd|SSL_kEDH;
 	*auth |= SSL_aDH;
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 906fcd4..9f29f3e 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2110,6 +2110,9 @@
 	if (dh_dsa) mask_k|=SSL_kDHd;
 	if (dh_dsa_export) emask_k|=SSL_kDHd;
 
+	if (emask_k & (SSL_kDHr|SSL_kDHd))
+		mask_a |= SSL_aDH;
+
 	if (rsa_enc || rsa_sign)
 		{
 		mask_a|=SSL_aRSA;
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 315aaa8..8cbaaab 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -280,8 +280,8 @@
 
 /* Bits for algorithm_mkey (key exchange algorithm) */
 #define SSL_kRSA		0x00000001L /* RSA key exchange */
-#define SSL_kDHr		0x00000002L /* DH cert, RSA CA cert */ /* no such ciphersuites supported! */
-#define SSL_kDHd		0x00000004L /* DH cert, DSA CA cert */ /* no such ciphersuite supported! */
+#define SSL_kDHr		0x00000002L /* DH cert, RSA CA cert */
+#define SSL_kDHd		0x00000004L /* DH cert, DSA CA cert */
 #define SSL_kEDH		0x00000008L /* tmp DH key no DH cert */
 #define SSL_kKRB5		0x00000010L /* Kerberos5 key exchange */
 #define SSL_kECDHr		0x00000020L /* ECDH cert, RSA CA cert */
@@ -295,7 +295,7 @@
 #define SSL_aRSA		0x00000001L /* RSA auth */
 #define SSL_aDSS 		0x00000002L /* DSS auth */
 #define SSL_aNULL 		0x00000004L /* no auth (i.e. use ADH or AECDH) */
-#define SSL_aDH 		0x00000008L /* Fixed DH auth (kDHd or kDHr) */ /* no such ciphersuites supported! */
+#define SSL_aDH 		0x00000008L /* Fixed DH auth (kDHd or kDHr) */
 #define SSL_aECDH 		0x00000010L /* Fixed ECDH auth (kECDHe or kECDHr) */
 #define SSL_aKRB5               0x00000020L /* KRB5 auth */
 #define SSL_aECDSA              0x00000040L /* ECDSA auth*/
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index c0960b5..b7c1905 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -182,8 +182,23 @@
 static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey)
 	{
 	int i;
-
-	i=ssl_cert_type(NULL,pkey);
+	/* Special case for DH: check two DH certificate types for a match.
+	 * This means for DH certificates we must set the certificate first.
+	 */
+	if (pkey->type == EVP_PKEY_DH)
+		{
+		X509 *x;
+		i = -1;
+		x = c->pkeys[SSL_PKEY_DH_RSA].x509;
+		if (x && X509_check_private_key(x, pkey))
+				i = SSL_PKEY_DH_RSA;
+		x = c->pkeys[SSL_PKEY_DH_DSA].x509;
+		if (i == -1 && x && X509_check_private_key(x, pkey))
+				i = SSL_PKEY_DH_DSA;
+		ERR_clear_error();
+		}
+	else 
+		i=ssl_cert_type(NULL,pkey);
 	if (i < 0)
 		{
 		SSLerr(SSL_F_SSL_SET_PKEY,SSL_R_UNKNOWN_CERTIFICATE_TYPE);