# Updating SSL Ciphers

3rd June 2019

I enjoy the warm fuzzy feeling from some security hardening, and nothing brings that on more than knowing that people can view my publicly-available content securely.

Updating my ciphers was quite an adventure, partially because LetsEncrypt was overriding my configuration, as found by Shanebe and Pavel on StackOverflow.

## Pre-Update SSLScan and NMap

> sslscan ranaldo.co.uk [ . . . ] snip [ . . . ] Preferred TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 Accepted TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 2048 bits Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 2048 bits Accepted TLSv1.0 128 bits AES128-SHA Accepted TLSv1.0 256 bits AES256-SHA [ . . . snip . . . ]

> sslscan ranaldo.co.uk Version: 1.11.13-static OpenSSL 1.0.2-chacha (1.0.2g-dev) Connected to 46.101.63.222 Testing SSL server ranaldo.co.uk on port 443 using SNI name ranaldo.co.uk TLS Fallback SCSV: Server supports TLS Fallback SCSV TLS renegotiation: Secure session renegotiation supported TLS Compression: Compression disabled Heartbleed: TLS 1.2 not vulnerable to heartbleed TLS 1.1 not vulnerable to heartbleed TLS 1.0 not vulnerable to heartbleed Supported Server Cipher(s): Preferred TLSv1.2 128 bits ECDHE-RSA-AES128-GCM-SHA256 Curve P-256 DHE 256 Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-GCM-SHA384 Curve P-256 DHE 256 Accepted TLSv1.2 128 bits DHE-RSA-AES128-GCM-SHA256 DHE 2048 bits Accepted TLSv1.2 256 bits DHE-RSA-AES256-GCM-SHA384 DHE 2048 bits Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA256 Curve P-256 DHE 256 Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA384 Curve P-256 DHE 256 Accepted TLSv1.2 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 Accepted TLSv1.2 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA256 DHE 2048 bits Accepted TLSv1.2 128 bits DHE-RSA-AES128-SHA DHE 2048 bits Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA256 DHE 2048 bits Accepted TLSv1.2 256 bits DHE-RSA-AES256-SHA DHE 2048 bits Accepted TLSv1.2 128 bits AES128-GCM-SHA256 Accepted TLSv1.2 256 bits AES256-GCM-SHA384 Accepted TLSv1.2 128 bits AES128-SHA256 Accepted TLSv1.2 256 bits AES256-SHA256 Accepted TLSv1.2 128 bits AES128-SHA Accepted TLSv1.2 256 bits AES256-SHA Preferred TLSv1.1 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 Accepted TLSv1.1 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.1 128 bits DHE-RSA-AES128-SHA DHE 2048 bits Accepted TLSv1.1 256 bits DHE-RSA-AES256-SHA DHE 2048 bits Accepted TLSv1.1 128 bits AES128-SHA Accepted TLSv1.1 256 bits AES256-SHA Preferred TLSv1.0 128 bits ECDHE-RSA-AES128-SHA Curve P-256 DHE 256 Accepted TLSv1.0 256 bits ECDHE-RSA-AES256-SHA Curve P-256 DHE 256 Accepted TLSv1.0 128 bits DHE-RSA-AES128-SHA DHE 2048 bits Accepted TLSv1.0 256 bits DHE-RSA-AES256-SHA DHE 2048 bits Accepted TLSv1.0 128 bits AES128-SHA Accepted TLSv1.0 256 bits AES256-SHA SSL Certificate: Signature Algorithm: sha256WithRSAEncryption RSA Key Strength: 2048 Subject: ranaldo.co.uk Altnames: DNS:ranaldo.co.uk, DNS:www.ranaldo.co.uk Issuer: Let's Encrypt Authority X3

> nmap --script ssl-enum-ciphers -p 443 ranaldo.co.uk [ . . . snip . . . ] | TLSv1.0: | ciphers: | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(ecdh_x25519) - A | TLS_DHE_RSA_WITH_AES_128_CBC_SHA(dh 2048) - A | TLS_DHE_RSA_WITH_AES_256_CBC_SHA(dh 2048) - A | TLS_RSA_WITH_AES_128_CBC_SHA(rsa 2048) - A | TLS_RSA_WITH_AES_256_CBC_SHA(rsa 2048) - A [ . . . snip . . . ]

> nmap --script ssl-enum-ciphers -p 443 ranaldo.co.uk Starting Nmap 7.70 ( https://nmap.org ) at 2019-06-03 14:16 BST Nmap scan report for ranaldo.co.uk (46.101.63.222) Host is up (0.019s latency). PORT STATE SERVICE 443/tcp open https | ssl-enum-ciphers: | TLSv1.0: | ciphers: | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (ecdh_x25519) - A | TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A | TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A | TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A | TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A | compressors: | NULL | cipher preference: server | TLSv1.1: | ciphers: | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (ecdh_x25519) - A | TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A | TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A | TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A | TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A | compressors: | NULL | cipher preference: server | TLSv1.2: | ciphers: | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (ecdh_x25519) - A | TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048) - A | TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048) - A | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (ecdh_x25519) - A | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (ecdh_x25519) - A | TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 2048) - A | TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A | TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048) - A | TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A | TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A | TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A | TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A | TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A | TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A | TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A | compressors: | NULL | cipher preference: server |_ least strength: A Nmap done: 1 IP address (1 host up) scanned in 3.41 seconds

First things first was to decide what I wanted to purge. Going through the ciphers, Cipher Block Chaining seemed like something I wouldn't like to have hang around, as well as TLSv1.0. After a bit of research into the various options, including running through SSLLabs, it appeared that disabling all CBC cipher suites and removing TLSv1.0 support would only deprive Windows 8.1 Mobile users, so that seemed like an acceptable loss.

I already had a mostly complete configuration within my Apache configuration, but going to Mozilla's Cipher Generating Page was pretty helpful. Configuring a "modern" setting was good, although I did end up modifying sections after some passes through SSLLabs.

## Mozilla SSL Configuration Generator Output

# modern configuration, tweak to your needs SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 SSLHonorCipherOrder on SSLCompression off SSLSessionTickets off

This all initially seemed in order, although since I update the site reasonably often I opted for "SSL Protocol TLSv1.2 TLSv1.3" over the suggested method of allowing all then purging the weak, as I would likely catch anything if there were to be an issue.

However, after applying this then refresing an inordinate amount of times I realised that, as linked above, sites-enabled is overwritten by the Let's Encrypt configuration. With a short visit to /etc/letsencrypt/options-ssl-apache.conf the correct configuration now loaded. Which appeared to work until I revisited SSL Labs. The issue here is that what Apache calls "ECDHE-RSA-AES-256-SHA384" is a CBC cipher suite. Put simply, it comes up in orange as an issue. The toss up is that while using only the non-GCM and CHACHA cipher suites is the most secure, it also stops half of the assessed browsers on anything below Windows 10 from being able to get an SSL connection. Since I'm not getting rid of my HSTS header any time soon, which mandates that all connections *must* be secured, this effectively locks out older browsers.

So, the dilemma - do I weaken everything by removing a header, or do I potentially weaken some by re-adding cipher suites?

### Final configuration

The simplest solution I found was to further prune my offered ciphersuites to:

SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384 SSLProtocol +TLSv1.3 +TLSv1.2 SSLHonorCipherOrder on SSLCompression off SSLSessionTickets off

With these settings in place, while I still support CBC, it is the last cipher suite selected. The only losses from these settings are users on Windows Phone 8.1 using Internet Explorer 11. Sorry about that. Not that you can see this. As you can also see, in place of the default "all -SSLv3 etc...", I've gone the opt-in route, just to ensure the most secure option is selected. I mean as far as I know it doesn't make a difference, but you've got to flex that "experimental TLSv1.3 support".