Enable Elliptical Curve Diffie-Hellman (ECDHE) in Linux

encryptionWith all the recent publicity regarding Internet spying, there has been a renewed interest in security and encryption. One oft-neglected feature of SSL is the ability to use a cipher with Diffie-Hellman key exchange that enables so-called perfect forward secrecy. The advantage of PFS is that even if your private key is compromised, recorded past traffic cannot be decrypted.

The problem is that Diffie-Hellman algorithms are very slow.  This can be offset to a large degree by using Elliptical Curve Diffie-Hellman (ECDHE).  The problem for Red Hat / CentOS / Fedora / Amazon Linux users is that Red Hat intentionally disables ECDHE ciphers (among others) because they’re unsure of the patent issues surrounding them.

Fixing this requires a custom compilation of OpenSSL.  Luckily, it is readily accomplished using the Fedora source RPM and does not require rolling your own binaries from scratch.   In addition, you must recompile applications such as Apache’s mod_ssl after installing the new OpenSSL packages.

Here’s how we enable ECDHE ciphers in Apache on a Fedora or Amazon Linux server:

  1. Download and install the openssl and httpd source RPMs.
  2. Download the official openssl-1.0.1e.tar.gz source package into /root/rpmbuild/SOURCES.
  3. Apply the patch below to ./rpmbuild/SPECS/openssl.spec
  4. rpmbuild -bb openssl.spec
  5. Install the openssl-libs, and openssl-devel RPMs in ./rpmbuild/RPMS/arch
  6. rpmbuild -bb httpd.spec
  7. Install the mod_ssl RPM in ./rpmbuild/RPMS/arch
  8. Edit your Apache config to prefer ECDHE ciphers
  9. Restart Apache
  10. Test your Apache installation with Qualys’ SSL Labs to verify your settings.

 

Example Apache Cipher Config:

SSLHonorCipherOrder On
SSLCipherSuite "ECDH+aRSA+AES256 EDH+aRSA+AES256 ECDH+aRSA+AES128 EDH+aRSA+AES128 DES-CBC3-SHA"
OpenSSL Spec file patch:
@@ -26,8 +26,8 @@
 # We have to remove certain patented algorithms from the openssl source
 # tarball with the hobble-openssl script which is included below.
 # The original openssl upstream tarball cannot be shipped in the .src.rpm.
-Source: openssl-%{version}-usa.tar.xz
-Source1: hobble-openssl
+Source: openssl-%{version}.tar.gz
+#Source1: hobble-openssl
 Source2: Makefile.certificate
 Source6: make-dummy-cert
 Source7: renew-dummy-cert
@@ -54,19 +54,19 @@
 Patch36: openssl-1.0.0e-doc-noeof.patch
 Patch38: openssl-1.0.1-beta2-ssl-op-all.patch
 Patch39: openssl-1.0.1c-ipv6-apps.patch
-Patch40: openssl-1.0.1e-fips.patch
+#Patch40: openssl-1.0.1e-fips.patch
 Patch45: openssl-1.0.1e-env-zlib.patch
 Patch47: openssl-1.0.0-beta5-readme-warning.patch
 Patch49: openssl-1.0.1a-algo-doc.patch
 Patch50: openssl-1.0.1-beta2-dtls1-abi.patch
 Patch51: openssl-1.0.1-version.patch
-Patch56: openssl-1.0.0c-rsa-x931.patch
-Patch58: openssl-1.0.1-beta2-fips-md5-allow.patch
+#Patch56: openssl-1.0.0c-rsa-x931.patch
+#Patch58: openssl-1.0.1-beta2-fips-md5-allow.patch
 Patch60: openssl-1.0.0d-apps-dgst.patch
 Patch63: openssl-1.0.0d-xmpp-starttls.patch
 Patch65: openssl-1.0.0e-chil-fixes.patch
 Patch66: openssl-1.0.1-pkgconfig-krb5.patch
-Patch68: openssl-1.0.1e-secure-getenv.patch
+#Patch68: openssl-1.0.1e-secure-getenv.patch
 Patch69: openssl-1.0.1c-dh-1024.patch
 # Backported fixes including security fixes
 Patch81: openssl-1.0.1-beta2-padlock64.patch
@@ -139,7 +139,7 @@

 # The hobble_openssl is called here redundantly, just to be sure.
 # The tarball has already the sources removed.
-%{SOURCE1} > /dev/null
+#%{SOURCE1} > /dev/null
 %patch1 -p1 -b .rpmbuild
 %patch2 -p1 -b .defaults
 %patch4 -p1 -b .enginesdir %{?_rawbuild}
@@ -158,19 +158,19 @@
 %patch36 -p1 -b .doc-noeof
 %patch38 -p1 -b .op-all
 %patch39 -p1 -b .ipv6-apps
-%patch40 -p1 -b .fips
+#%patch40 -p1 -b .fips
 %patch45 -p1 -b .env-zlib
 %patch47 -p1 -b .warning
 %patch49 -p1 -b .algo-doc
 %patch50 -p1 -b .dtls1-abi
 %patch51 -p1 -b .version
-%patch56 -p1 -b .x931
-%patch58 -p1 -b .md5-allow
+#%patch56 -p1 -b .x931
+#%patch58 -p1 -b .md5-allow
 %patch60 -p1 -b .dgst
 %patch63 -p1 -b .starttls
 %patch65 -p1 -b .chil
 %patch66 -p1 -b .krb5
-%patch68 -p1 -b .secure-getenv
+#%patch68 -p1 -b .secure-getenv
 %patch69 -p1 -b .dh1024

 %patch81 -p1 -b .padlock64
@@ -227,9 +227,9 @@
 ./Configure \
 	--prefix=/usr --openssldir=%{_sysconfdir}/pki/tls ${sslflags} \
 	zlib enable-camellia enable-seed enable-tlsext enable-rfc3779 \
-	enable-cms enable-md2 no-mdc2 no-rc5 no-ec no-ec2m no-ecdh no-ecdsa no-srp \
+	enable-cms enable-md2 no-mdc2 no-rc5 \
 	--with-krb5-flavor=MIT --enginesdir=%{_libdir}/openssl/engines \
-	--with-krb5-dir=/usr shared  ${sslarch} %{?!nofips:fips}
+	--with-krb5-dir=/usr shared  ${sslarch}

 # Add -Wa,--noexecstack here so that libcrypto's assembler modules will be
 # marked as not requiring an executable stack.
@@ -269,11 +269,7 @@
 %define __spec_install_post \
     %{?__debug_package:%{__debug_install_post}} \
     %{__arch_install_post} \
-    %{__os_install_post} \
-    crypto/fips/fips_standalone_hmac $RPM_BUILD_ROOT%{_libdir}/libcrypto.so.%{version} >$RPM_BUILD_ROOT%{_libdir}/.libcrypto.so.%{version}.hmac \
-    ln -sf .libcrypto.so.%{version}.hmac $RPM_BUILD_ROOT%{_libdir}/.libcrypto.so.%{soversion}.hmac \
-    crypto/fips/fips_standalone_hmac $RPM_BUILD_ROOT%{_libdir}/libssl.so.%{version} >$RPM_BUILD_ROOT%{_libdir}/.libssl.so.%{version}.hmac \
-    ln -sf .libssl.so.%{version}.hmac $RPM_BUILD_ROOT%{_libdir}/.libssl.so.%{soversion}.hmac \
+    %{__os_install_post} 
 %{nil}

 %define __provides_exclude_from %{_libdir}/openssl
@@ -406,8 +402,6 @@
 %attr(0755,root,root) %{_libdir}/libcrypto.so.%{soversion}
 %attr(0755,root,root) %{_libdir}/libssl.so.%{version}
 %attr(0755,root,root) %{_libdir}/libssl.so.%{soversion}
-%attr(0644,root,root) %{_libdir}/.libcrypto.so.*.hmac
-%attr(0644,root,root) %{_libdir}/.libssl.so.*.hmac
 %attr(0755,root,root) %{_libdir}/openssl

 %files devel

For more details on PFS and EC, peruse this excellent article by Vincent Bernat.

Note that this technique might be practical on Red Hat / CentOS, but it’s not already using OpenSSL 1.0.1e and we haven’t attempted this yet.

Update Oct 20 2013: Fedora 18+ and Red Hat 6.5 beta have released OpenSSL packages supporting EC. Recompiled packages to take advantage of this are still missing in Fedora, but should arrive soon.

Update Feb 6 2014: See our article on obtaining the Best Practical SSL Configuration for commonly used packages.