Enable Elliptical Curve Diffie-Hellman (ECDHE) in Linux
With 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:
- Download and install the openssl and httpd source RPMs.
- Download the official openssl-1.0.1e.tar.gz source package into /root/rpmbuild/SOURCES.
- Apply the patch below to ./rpmbuild/SPECS/openssl.spec
- rpmbuild -bb openssl.spec
- Install the openssl-libs, and openssl-devel RPMs in ./rpmbuild/RPMS/arch
- rpmbuild -bb httpd.spec
- Install the mod_ssl RPM in ./rpmbuild/RPMS/arch
- Edit your Apache config to prefer ECDHE ciphers
- Restart Apache
- 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.