8735de0
Patch by Robert Scheck <robert@fedoraproject.org> for Zarafa >= 7.1.13 which implements DHE aka EDH
8735de0
(diffie-hellman key exchange) support. https://en.wikipedia.org/wiki/Diffie-Hellman_key_exchange is
8735de0
providing more information about Perfect Forward Secrecy (PFS). This implementation might need some
8735de0
more resources compared to ECDHE, however not all servers and/or clients are supporting it through;
8735de0
e.g. Red Hat Enterprise Linux 5 (and derivates). The prime length of 1024, 2048, 3072, 4096, 6144
8735de0
and 8192 bits are based on the private key size to avoid any static DH parameters. Please be aware
8735de0
that this patch may cause issues with some older SSL/TLS clients, mostly Java 7 or earlier, that do
8735de0
not support primes larger than 1024 bits.
8735de0
8735de0
Suggestions for testing; run the following openssl(1) commands before and after applying this patch:
8735de0
8735de0
1. echo QUIT | openssl s_client -cipher 'kEDH:ALL' -connect <host>:110 -starttls pop3 2>&1 | grep Cipher
8735de0
2. echo QUIT | openssl s_client -cipher 'kEDH:ALL' -connect <host>:143 -starttls imap 2>&1 | grep Cipher
8735de0
3. echo QUIT | openssl s_client -cipher 'kEDH:ALL' -connect <host>:237 2>&1 | grep Cipher
8735de0
4. echo QUIT | openssl s_client -cipher 'kEDH:ALL' -connect <host>:993 2>&1 | grep Cipher
8735de0
5. echo QUIT | openssl s_client -cipher 'kEDH:ALL' -connect <host>:995 2>&1 | grep Cipher
8735de0
6. echo QUIT | openssl s_client -cipher 'kEDH:ALL' -connect <host>:8443 2>&1 | grep Cipher
8735de0
8735de0
After applying this patch the output should contain e.g. "DHE-RSA-AES256-GCM-SHA384" on a Red Hat
8735de0
Enterprise Linux 6 (and derivates). Without this patch the result is e.g. "AES256-GCM-SHA384". Note
8735de0
that ZCP-12237 is maybe having influence on the result depending on the exact test case.
8735de0
8735de0
Important: As https://www.mail-archive.com/haproxy@formilux.org/msg13274.html is the origin for this
8735de0
patch (a HAProxy patch suggestion, which itself bases on mod_ssl of Apache httpd), the licensing is
8735de0
likely a combination out of the Apache License, Version 2.0, the GNU General Public License, version
8735de0
2 (or later) and the GNU Affero General Public License, version 3 (and thus excludes dual-licensing
8735de0
situations such as at the upstream of Zarafa).
8735de0
8735de0
This patch should be only applied after ZCP-12237 and its dependencies.
8735de0
8735de0
--- zarafa-7.1.13/common/ECChannel.cpp					2015-07-30 01:01:07.212313822 +0200
8735de0
+++ zarafa-7.1.13/common/ECChannel.cpp.ssl_dhe				2015-07-30 02:05:36.045747555 +0200
8735de0
@@ -85,6 +85,119 @@
8735de0
 // because of statics
8735de0
 SSL_CTX* ECChannel::lpCTX = NULL;
8735de0
 
8735de0
+#if !defined(OPENSSL_NO_DH)
8735de0
+static DH *ssl_get_dh_1024(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc2409_prime_1024(NULL);
8735de0
+		// See RFC 2409, Section 6 "Oakley Groups" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_2048(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_2048(NULL);
8735de0
+		// See RFC 3526, Section 3 "2048-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_3072(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_3072(NULL);
8735de0
+		// See RFC 3526, Section 4 "3072-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_4096(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_4096(NULL);
8735de0
+		// See RFC 3526, Section 5 "4096-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_6144(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_6144(NULL);
8735de0
+		// See RFC 3526, Section 6 "6144-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_8192(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_8192(NULL);
8735de0
+		// See RFC 3526, Section 7 "8192-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+// Returns Diffie-Hellman parameters matching the private key length
8735de0
+static DH *ssl_get_tmp_dh(SSL *ssl, int exporting, int keylen) {
8735de0
+	DH *dh = NULL;
8735de0
+	EVP_PKEY *pkey = SSL_get_privatekey(ssl);
8735de0
+	int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE;
8735de0
+
8735de0
+	if (type == EVP_PKEY_RSA || type == EVP_PKEY_DSA) {
8735de0
+		keylen = EVP_PKEY_bits(pkey);
8735de0
+	}
8735de0
+
8735de0
+	if (keylen >= 8192) {
8735de0
+		dh = ssl_get_dh_8192();
8735de0
+	} else if (keylen >= 6144) {
8735de0
+		dh = ssl_get_dh_6144();
8735de0
+	} else if (keylen >= 4096) {
8735de0
+		dh = ssl_get_dh_4096();
8735de0
+	} else if (keylen >= 3072) {
8735de0
+		dh = ssl_get_dh_3072();
8735de0
+	} else if (keylen >= 2048) {
8735de0
+		dh = ssl_get_dh_2048();
8735de0
+	} else {
8735de0
+		dh = ssl_get_dh_1024();
8735de0
+	}
8735de0
+
8735de0
+	return dh;
8735de0
+}
8735de0
+#endif
8735de0
+
8735de0
 HRESULT ECChannel::HrSetCtx(ECConfig *lpConfig, ECLogger *lpLogger) {
8735de0
 	HRESULT hr = hrSuccess;
8735de0
 	char *szFile = NULL;
8735de0
@@ -116,6 +229,11 @@
8735de0
 
8735de0
 	SSL_CTX_set_options(lpCTX, SSL_OP_ALL);			 // enable quirk and bug workarounds
8735de0
 
8735de0
+#if !defined(OPENSSL_NO_DH)
8735de0
+	SSL_CTX_set_options(lpCTX, SSL_OP_SINGLE_DH_USE);
8735de0
+	SSL_CTX_set_tmp_dh_callback(lpCTX, ssl_get_tmp_dh);
8735de0
+#endif
8735de0
+
8735de0
 #if !defined(OPENSSL_NO_ECDH) && defined(NID_X9_62_prime256v1)
8735de0
 	ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
8735de0
 
8735de0
--- zarafa-7.1.13/provider/server/ECSoapServerConnection.cpp		2015-07-30 01:01:07.212313822 +0200
8735de0
+++ zarafa-7.1.13/provider/server/ECSoapServerConnection.cpp.ssl_dhe	2015-07-30 02:05:54.658626465 +0200
8735de0
@@ -165,6 +165,119 @@
8735de0
 	return nRet;
8735de0
 }
8735de0
 
8735de0
+#if !defined(OPENSSL_NO_DH)
8735de0
+static DH *ssl_get_dh_1024(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc2409_prime_1024(NULL);
8735de0
+		// See RFC 2409, Section 6 "Oakley Groups" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_2048(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_2048(NULL);
8735de0
+		// See RFC 3526, Section 3 "2048-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_3072(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_3072(NULL);
8735de0
+		// See RFC 3526, Section 4 "3072-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_4096(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_4096(NULL);
8735de0
+		// See RFC 3526, Section 5 "4096-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_6144(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_6144(NULL);
8735de0
+		// See RFC 3526, Section 6 "6144-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+static DH *ssl_get_dh_8192(void) {
8735de0
+	DH *dh = DH_new();
8735de0
+	if (dh) {
8735de0
+		dh->p = get_rfc3526_prime_8192(NULL);
8735de0
+		// See RFC 3526, Section 7 "8192-bit MODP Group" for the reason why we use 2 as a generator
8735de0
+		BN_dec2bn(&dh->g, "2");
8735de0
+		if (!dh->p || !dh->g) {
8735de0
+			DH_free(dh);
8735de0
+			dh = NULL;
8735de0
+		}
8735de0
+	}
8735de0
+	return dh;
8735de0
+}
8735de0
+
8735de0
+// Returns Diffie-Hellman parameters matching the private key length
8735de0
+static DH *ssl_get_tmp_dh(SSL *ssl, int exporting, int keylen) {
8735de0
+	DH *dh = NULL;
8735de0
+	EVP_PKEY *pkey = SSL_get_privatekey(ssl);
8735de0
+	int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE;
8735de0
+
8735de0
+	if (type == EVP_PKEY_RSA || type == EVP_PKEY_DSA) {
8735de0
+		keylen = EVP_PKEY_bits(pkey);
8735de0
+	}
8735de0
+
8735de0
+	if (keylen >= 8192) {
8735de0
+		dh = ssl_get_dh_8192();
8735de0
+	} else if (keylen >= 6144) {
8735de0
+		dh = ssl_get_dh_6144();
8735de0
+	} else if (keylen >= 4096) {
8735de0
+		dh = ssl_get_dh_4096();
8735de0
+	} else if (keylen >= 3072) {
8735de0
+		dh = ssl_get_dh_3072();
8735de0
+	} else if (keylen >= 2048) {
8735de0
+		dh = ssl_get_dh_2048();
8735de0
+	} else {
8735de0
+		dh = ssl_get_dh_1024();
8735de0
+	}
8735de0
+
8735de0
+	return dh;
8735de0
+}
8735de0
+#endif
8735de0
+
8735de0
 ECSoapServerConnection::ECSoapServerConnection(ECConfig* lpConfig, ECLogger* lpLogger)
8735de0
 {
8735de0
 	m_lpConfig = lpConfig;
8735de0
@@ -271,6 +384,11 @@
8735de0
 
8735de0
 	SSL_CTX_set_options(lpsSoap->ctx, SSL_OP_ALL);
8735de0
 
8735de0
+#if !defined(OPENSSL_NO_DH)
8735de0
+	SSL_CTX_set_options(lpsSoap->ctx, SSL_OP_SINGLE_DH_USE);
8735de0
+	SSL_CTX_set_tmp_dh_callback(lpsSoap->ctx, ssl_get_tmp_dh);
8735de0
+#endif
8735de0
+
8735de0
 #if !defined(OPENSSL_NO_ECDH) && defined(NID_X9_62_prime256v1)
8735de0
 	ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
8735de0