h3. The Problem
Securing network services with SSL is, in general, a good idea, if you can spare the CPU cycles. Especially personal data should always be protected while in transit via the network. But it may not be enough to simply enable SSL in the service (be it Apache, Lighttpd, Cyrus IMAPD or something else) to get a reasonably secure connection.
SSL is a cover phrase for a wide collection of protocols and crypto algorithms. There are at least three protocol suites in use (SSLv2, SSLv3 and TLSv1), which between them support tens of different crypto algorithms with different strengths. Not all of those are still suitable for serious use today.
A list of the ciphers supported by the popular "OpenSSL library":http://openssl.org, which is used by many projects to handle SSL, can be obtained with the following command:
$ openssl ciphers -v 'ALL:COMPLEMENTOFALL'
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
...
$
On my notebook (running Fedora 11) this produces a list of 62 ciphers. The number of ciphers supported changes with the version of OpenSSL, so other
systems may display a different list.
During an SSL handshake between a client and a server the cipher to use is negotiated between the two machines. In practical terms this means that the client send list of ciphers it is able and willing to use to the server, the server compares this list with it's own list of supported ciphers and, if a cipher supported by both sides is found returns it's choice to the client.
h3. Defaults
Unless something else is configured, a server using OpenSSL uses the "DEFAULT" group of ciphers. The content of this group can also change between versions of OpenSSL. The value for the installed version can be queried:
$ openssl ciphers -v 'DEFAULT'
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
...
$
This list is shorter than the list of all ciphers above, containing 44 ciphers on my notebook. This list is not entirely nonsensical. It does not contain ciphers without encryption (yes, that is a valid mode of operation for SSL), it does not contain ciphers without authentication (which would allow for Man-in-the-middle attacks). It does, however, contain ciphers whose strength in this day and age must be questioned. These include the so called "export" ciphers.
These ciphers stem from a time when it was illegal to export software from the United States which supported strong encryption. So software supporting encryption (for example web browsers, like the venerable Netscape Nagivator) destined for export only supported watered down versions of the strong encryption variants, mostly by supporting shorter keys. Fortunately it is no longer illegal to export strong crypto from the United States, and hasn't been for years, but for compatibility reasons OpenSSL is still willing to negotiate these weak ciphers with a client.
Another weak candidate is the "DES algorithm":http://en.wikipedia.org/wiki/DataEncryptionStandard. It was made a standard in 1976 (which is an eternity ago in IT terms). Although it was never cryptographically broken, it's key length of 56 bits made it increasingly more vulnerable to brute force attacks as faster CPUs became available. Since the "Electronic Frontier Foundation":http://www.eff.org demonstrated a custom-built DES cracker in 1998, built for $250.000 and able to brute-force a DES key in under two days, DES has been effectively dead. But, for compatibility reasons, OpenSSL is, by default, willing to negotiate DES as a cipher.
OpenSSL can be told which ciphers to offer in an SSL negotiation, and thankfully most programs using OpenSSL offer configuration statements so the admin can change the default settings.
h3. Selections
Which ciphers should be used then? Let's start with all the ciphers supported by the SSLv3/TLSv1 cipher suite (which every program offering SSL should support, the use of SSLv2 is strongly discouraged due to vulnerabilities). And we only want ciphers which offer high security (which in OpenSSL terms means more than 128 bits key length, plus some ciphers with 128 bit keys). To be on the safe side we also explicitly disable SSLv2 ciphers, so they cannot be reintroduced later:
$ openssl ciphers -v 'TLSv1+HIGH:!SSLv2'
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
...
$
25 ciphers match this list, but it also contains ciphers without authentication. These have to go, along with all ciphers without encryption (there should not be any, but better save than sorry):
$ openssl ciphers -v 'TLSv1+HIGH:!SSLv2:!aNULL:!eNULL'
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
...
$
20 remain. It's my personal preference to disable ciphers based on triple-DES (3DES), so these are removed, too. There is no technical reason for this, 3DES is still considered secure.
Finally, the remaining ciphers are sorted by strength, the most secure first, which will make OpenSSL prefer those.
$ openssl ciphers -v 'TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH'
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
...
On my notebook 14 ciphers remain. For comparison, on my web server (running CentOS 5) this selection only produces 6 ciphers, due to an older version of OpenSSL.
There is, however, two problem with this list. First, it does no longer contain the export or simple DES ciphers (which was kind of the point). This means that SSL services secured with this selection are no longer available to SSL client which only support export grade ciphers. This is a good thing, as these clients are insecure and need to be replaced with something more recent. Depending on the details of the service this option may not be available, though. Please check if these old ciphers must be supprted further before turning them off.
The second problem is Windows. In detail, Windows versions before and including Windows XP. The crypto libraries shipped with these versions do not support newer crypto algorithms (like AES), so there is no overlap between the set of algorithms supported by the server and those supported by the client. These crypto libraries are primarily used by Internet Explorer, Outlook and Outlook Express, so these programs on Windows XP and earlier will not be able to negotiate an SSL connection to a web or mail server. Other web browsers and mail clients (like Firefox and Thunderbird) usually ship with their own crypto libraries which do support modern algorithms, and are not
affected. The system crypto libraries in Windows Vista and Windows 7 are also not affected.
If support for older Windows versions cannot be dropped (likely), the cipher list needs to be extended by some RC4 ciphers (which Windows does support):
$ openssl ciphers -v 'TLSv1+HIGH:!SSLv2:RC4+MEDIUM:!aNULL:!eNULL:!3DES:@STRENGTH'
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
...
$
This brings the number of ciphers up to 19, the new RC4 ciphers are added at the end of the sorted list.
h3. Configuration
Now that the cipher list is complete the various services that use SSL need to be configured to use it. Instructions how to do this can be found in the documentation, examples for some services are below.
h4. Exim
Add the following line to the global (first) configuration section and restart Exim:
tls_require_ciphers = TLSv1+HIGH : !SSLv2 : RC4+MEDIUM : !aNULL : !eNULL : !3DES : @STRENGTH
h4. Lighttpd
Add the following line to the configuration section containing ssl.engine = "enable"
and restart Lighttpd:
ssl.cipher-list = "TLSv1+HIGH !SSLv2 RC4+MEDIUM !aNULL !eNULL !3DES @STRENGTH"
h4. Cyrus IMAPD
Add the following line in imapd.conf
and restart Cyrus:
tls_cipher_list: TLSv1+HIGH:!SSLv2:RC4+MEDIUM:!aNULL:!eNULL:!3DES:@STRENGTH
h3. Testing
In order to test the new settings, a connection attempt using an excluded cipher can be made (which should fail, of course):
$ openssl s_client -host www.skytale.net -port 443 -cipher 3DES
CONNECTED(00000003)
140209911707464:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:672:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 58 bytes
---
New, (NONE), Cipher is (NONE)
Compression: NONE
Expansion: NONE
---
A successful attempt (letting openssl select the best cipher) negotiates AES with a 256 bit key:
$ openssl s_client -host www.skytale.net -port 443
CONNECTED(00000003)
...
---
SSL handshake has read 1281 bytes and written 309 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 1024 bit
Compression: zlib compression
Expansion: zlib compression
SSL-Session:
Protocol : TLSv1
Cipher : AES256-SHA
Session-ID: --removed--
Session-ID-ctx:
Master-Key: --removed--
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Compression: 1 (zlib compression)
Start Time: 1252852959
Timeout : 300 (sec)
Verify return code: 21 (unable to verify the first certificate)
---
Tracked: Dec 24, 19:40
Tracked: Dec 28, 12:15
Tracked: Jul 26, 08:38