How to discover TLS configurations
A guide to inventory your TLS cryptography with minimal code and tools.
By Jaime Gómez García, Head of Quantum at Santander and #SanExperts top contributor.
📆 After NIST’s publication of the new standards on Post-Quantum Cryptography (PQC), the “cryptoprocrastination” excuses to prepare for the transition to quantum-safe cryptography are over.
One good place to start understanding how to discover and take control of your organization’s cryptography may be monitoring the Transport Layer Security (TLS) sessions flowing through your network. There are three reasons for this:
1️⃣ TLS is, arguably, the most common way for applications to exchange information over a network. For instance, it supports all the HTTPS traffic.
2️⃣ Some web browsers already support some forms of PQC, and its use is gaining traction.
3️⃣ The US government CNSA2 has declared web browsing as an early target to transition to PQC.
In summary, all organizations use TLS extensively and the required software upgrades are going to happen soon, if not already.
In this quick guide we will review how you can gain some insights from the TLS traffic in your network that will help you identify what’s your starting point to prepare for the transition to PQC. For instance, PQC will only be supported in TLSv1.3, so all organizations have a dependency on a previous migration to TLSv1.3 before thinking of implementing PQ-TLS ciphersuites. It is likely that you will find in your organization that prior TLS versions have a larger footprint than expected. This will be a demonstration that you need to start your PQC transition project as soon as possible to ensure that all the pre-requisites to transition to PQC are achieved in time. In this case, you should start working on the transition to TLSv1.3 as a prework for the transition to PQC.
Index: What it’s in this guide
- Setting the objectives
- Scanning TLS services in your network
- Sniffing TLS services in your network
- Conclusion
Setting the objectives
🎯 Our goal is to identify two fundamental parameters of your TLS configuration in web services:
- TLS protocol versions, and
- Ciphersuites supported.
A modern TLS server should support TLSv1.3 and, possibly, TLSv1.2 for backward compatibility with older clients.
TLSv1.3 supports only a small number of ciphersuites and they are all considered secure. TLSv1.2 support several ciphersuites, many of which are now considered weak.
A good guideline to establish your TLS configuration is the Mozilla Security/Server Side TLS wiki page and its associated Mozilla SSL configuration Generator. Here you will see that the “Modern” configuration supports only TLSv1.3 with the ciphersuites defined in the standard (TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256). The “Intermediate configuration” is dedicated to general-purpose servers with a variety of clients, hence opting for better backwards compatibility. It supports TLSv1.2 and a small set of secure ciphersuites (ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305).
These parameters can be configured in different ways depending on what webserver you use. The examples I use here come from an Apache 2.4 webserver I have deployed on a virtual Ubuntu box. The certificates come from a test CA I have deployed on the same box using EJBCA.
Scanning TLS services in your network
🌐 TLS scanners, also known as SSL scanners as it seems we do not update our vocabulary, will scan your web server and provide lots of useful information.
I will assume that you know what TLS servers you have. If you don’t, you can discover them with mapping tools like nmap.
🔸 Tool 1: Qualys SSL Labs
Qualys SSL Labs (https://www.ssllabs.com/) provides useful tools and documentation to configure and test your servers. It is an online service available on the Internet, hence you will not be able to use it for a TLS service not reachable from Internet.
After a scan, the service provides you with a brief summary, including a benchmark:
And lots of information on the certificates presented by the server and TLS configuration, including resistance to some known attacks.
Putting the focus on the protocol version, this example from sourceforge.net shows it only supports TLSv1.3 and TLSv1.2:
Later it lists all the ciphersuites supported by the server, showing which are weak in orange:
The next section shows whether that TLS configuration would be compatible with different clients:
There is a trade-off between setting up a modern configuration and supporting older clients. This section helps you fine-tune your setup to the right spot for your needs.
Qualys SSL Labs also provides interesting stats on their SLL Pulse site. For instance, it shows that, despite TLSv1.3 being published in 2018, it is supported only in 70% of the surveyed sites and still needs improvement.
Qualys SSL Labs is a good tool and requires no infrastructure. It is just a web page you can use to test your server configuration if it is available on Internet. But, what if you want to test an internal server? Let’s see two more tools that will help you there.
🔸 Tool 2: testssl.sh
👁🗨 testssl.sh is a free command line tool which checks a server’s service on any port for the support of TLS/SSL ciphers, protocols as well as recent cryptographic flaws and more.
It is a shell script that can download and run on any Linux box. You can also run it as a docker container, hence minimizing your set up if you already have docker.
Running it from shell is simple:
$ ./testssl.sh hostname
The output is long and takes a while to run. It gives the same kind of information you get from Qualys SSL Labs, with a comprehensive view of things like certificates, resistance to known vulnerabilities and more. You can also concentrate on the protocol version, ciphersuites and client support. In my test setup I get:
$ testssl.sh -p -E -c --quiet test.my.pki
Start 2024-07-08 16:27:11 -->> 127.0.1.1:443 (test.my.pki) <<-- A record via: /etc/hosts
rDNS (127.0.1.1): pkitest. test.my.pki.
Service detected: HTTP
Testing protocols via sockets except NPN+ALPN SSLv2 not offered (OK)
SSLv3 not offered (OK)
TLS 1 not offered
TLS 1.1 not offered
TLS 1.2 offered (OK)
TLS 1.3 offered (OK): final
NPN/SPDY not offered
ALPN/HTTP2 http/1.1 (offered) Testing ciphers per protocol via OpenSSL plus sockets against the server, ordered by encryption strength Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits Cipher Suite Name (IANA/RFC)
-----------------------------------------------------------------------------------------------------------------------------
SSLv2
SSLv3
TLS 1
TLS 1.1
TLS 1.2
xc030 ECDHE-RSA-AES256-GCM-SHA384 ECDH 256 AESGCM 256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
x9f DHE-RSA-AES256-GCM-SHA384 DH 2048 AESGCM 256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
xcca8 ECDHE-RSA-CHACHA20-POLY1305 ECDH 253 ChaCha20 256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
xccaa DHE-RSA-CHACHA20-POLY1305 DH 2048 ChaCha20 256 TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
xc02f ECDHE-RSA-AES128-GCM-SHA256 ECDH 256 AESGCM 128 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
x9e DHE-RSA-AES128-GCM-SHA256 DH 2048 AESGCM 128 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS 1.3
x1302 TLS_AES_256_GCM_SHA384 ECDH 253 AESGCM 256 TLS_AES_256_GCM_SHA384
x1303 TLS_CHACHA20_POLY1305_SHA256 ECDH 253 ChaCha20 256 TLS_CHACHA20_POLY1305_SHA256
x1301 TLS_AES_128_GCM_SHA256 ECDH 253 AESGCM 128 TLS_AES_128_GCM_SHA256 Running client simulations (HTTP) via sockets Android 6.0 TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
Android 7.0 (native) TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
Android 8.1 (native) TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 253 bit ECDH (X25519)
Android 9.0 (native) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Android 10.0 (native) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Android 11 (native) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Android 12 (native) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Chrome 79 (Win 10) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Chrome 101 (Win 10) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Firefox 66 (Win 8.1/10) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Firefox 100 (Win 10) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
IE 6 XP No connection
IE 8 Win 7 No connection
IE 8 XP No connection
IE 11 Win 7 TLSv1.2 DHE-RSA-AES128-GCM-SHA256, 2048 bit DH
IE 11 Win 8.1 TLSv1.2 DHE-RSA-AES128-GCM-SHA256, 2048 bit DH
IE 11 Win Phone 8.1 No connection
IE 11 Win 10 TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
Edge 15 Win 10 TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 253 bit ECDH (X25519)
Edge 101 Win 10 21H2 TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Safari 12.1 (iOS 12.2) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Safari 13.0 (macOS 10.14.6) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Safari 15.4 (macOS 12.3.1) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Java 7u25 No connection
Java 8u161 TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
Java 11.0.2 (OpenJDK) TLSv1.3 TLS_AES_256_GCM_SHA384, 256 bit ECDH (P-256)
Java 17.0.3 (OpenJDK) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
go 1.17.8 TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
LibreSSL 2.8.3 (Apple) TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 253 bit ECDH (X25519)
OpenSSL 1.0.2e TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
OpenSSL 1.1.0l (Debian) TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 253 bit ECDH (X25519)
OpenSSL 1.1.1d (Debian) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
OpenSSL 3.0.3 (git) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Apple Mail (16.0) TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
Thunderbird (91.9) TLSv1.3 TLS_AES_256_GCM_SHA384, 253 bit ECDH (X25519)
Done 2024-07-08 16:27:16 [ 11s] -->> 127.0.1.1:443 (test.my.pki) <<--
We see that this configuration supports TLSv1.3 and v1.2 with a small set of secure ciphersuites.
My Apache 2.4 is configured with the following directives:
SSLCiphersuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
SSLProtocol +TLSv1.3 +TLSv1.2
Let’s see how testssl.sh catches some weak configurations. If I apply Mozilla’s SSL Configuration Generator “old ciphersuite” set in my webserver and just support TLSv1.2 (I discovered my setup does not support anything under TLSv1.2! Great!):
$ testssl.sh -p -c -E --quiet test.my.pki
Start 2024-07-10 14:49:29 -->> 127.0.1.1:443 (test.my.pki) <<-- A record via: /etc/hosts
rDNS (127.0.1.1): pkitest. test.my.pki.
Service detected: HTTP
Testing protocols via sockets except NPN+ALPN SSLv2 not offered (OK)
SSLv3 not offered (OK)
TLS 1 not offered
TLS 1.1 not offered
TLS 1.2 offered (OK)
TLS 1.3 not offered and downgraded to a weaker protocol
NPN/SPDY not offered
ALPN/HTTP2 http/1.1 (offered) Testing ciphers per protocol via OpenSSL plus sockets against the server, ordered by encryption strength Hexcode Cipher Suite Name (OpenSSL) KeyExch. Encryption Bits Cipher Suite Name (IANA/RFC)
-----------------------------------------------------------------------------------------------------------------------------
SSLv2
SSLv3
TLS 1
TLS 1.1
TLS 1.2
xc030 ECDHE-RSA-AES256-GCM-SHA384 ECDH 256 AESGCM 256 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
xc028 ECDHE-RSA-AES256-SHA384 ECDH 256 AES 256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
xc014 ECDHE-RSA-AES256-SHA ECDH 256 AES 256 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
x9f DHE-RSA-AES256-GCM-SHA384 DH 2048 AESGCM 256 TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
xcca8 ECDHE-RSA-CHACHA20-POLY1305 ECDH 253 ChaCha20 256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
xccaa DHE-RSA-CHACHA20-POLY1305 DH 2048 ChaCha20 256 TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
x6b DHE-RSA-AES256-SHA256 DH 2048 AES 256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
x39 DHE-RSA-AES256-SHA DH 2048 AES 256 TLS_DHE_RSA_WITH_AES_256_CBC_SHA
x9d AES256-GCM-SHA384 RSA AESGCM 256 TLS_RSA_WITH_AES_256_GCM_SHA384
x3d AES256-SHA256 RSA AES 256 TLS_RSA_WITH_AES_256_CBC_SHA256
x35 AES256-SHA RSA AES 256 TLS_RSA_WITH_AES_256_CBC_SHA
xc02f ECDHE-RSA-AES128-GCM-SHA256 ECDH 256 AESGCM 128 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
xc027 ECDHE-RSA-AES128-SHA256 ECDH 256 AES 128 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
xc013 ECDHE-RSA-AES128-SHA ECDH 256 AES 128 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
x9e DHE-RSA-AES128-GCM-SHA256 DH 2048 AESGCM 128 TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
x67 DHE-RSA-AES128-SHA256 DH 2048 AES 128 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
x33 DHE-RSA-AES128-SHA DH 2048 AES 128 TLS_DHE_RSA_WITH_AES_128_CBC_SHA
x9c AES128-GCM-SHA256 RSA AESGCM 128 TLS_RSA_WITH_AES_128_GCM_SHA256
x3c AES128-SHA256 RSA AES 128 TLS_RSA_WITH_AES_128_CBC_SHA256
x2f AES128-SHA RSA AES 128 TLS_RSA_WITH_AES_128_CBC_SHA
TLS 1.3 Running client simulations (HTTP) via sockets Android 6.0 TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256, 256 bit ECDH (P-256)
Android 7.0 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
Android 8.1 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Android 9.0 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Android 10.0 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Android 11 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Android 12 (native) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Chrome 79 (Win 10) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Chrome 101 (Win 10) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Firefox 66 (Win 8.1/10) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Firefox 100 (Win 10) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
IE 6 XP No connection
IE 8 Win 7 No connection
IE 8 XP No connection
IE 11 Win 7 TLSv1.2 DHE-RSA-AES256-GCM-SHA384, 2048 bit DH
IE 11 Win 8.1 TLSv1.2 DHE-RSA-AES256-GCM-SHA384, 2048 bit DH
IE 11 Win Phone 8.1 TLSv1.2 ECDHE-RSA-AES128-SHA256, 256 bit ECDH (P-256)
IE 11 Win 10 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
Edge 15 Win 10 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Edge 101 Win 10 21H2 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Safari 12.1 (iOS 12.2) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Safari 13.0 (macOS 10.14.6) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Safari 15.4 (macOS 12.3.1) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Java 7u25 No connection
Java 8u161 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
Java 11.0.2 (OpenJDK) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
Java 17.0.3 (OpenJDK) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
go 1.17.8 TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
LibreSSL 2.8.3 (Apple) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
OpenSSL 1.0.2e TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
OpenSSL 1.1.0l (Debian) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
OpenSSL 1.1.1d (Debian) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
OpenSSL 3.0.3 (git) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Apple Mail (16.0) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 256 bit ECDH (P-256)
Thunderbird (91.9) TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384, 253 bit ECDH (X25519)
Done 2024-07-10 14:49:58 [ 35s] -->> 127.0.1.1:443 (test.my.pki) <<--
A diff from both outputs shows that the only client that would lose connectivity with the server by using the stronger configuration is IE 11 Win Phone 8.1. It is unlikely that this will have a significant impact on your service availability, so there is no reason to choose the weak configuration.
I recommend that you run testssl.sh without flags to see all the information it gives. One of the interesting things is an analysis of the categories of ciphersuites offered:
Testing cipher categories
NULL ciphers (no encryption) not offered (OK)
Anonymous NULL Ciphers (no authentication) not offered (OK)
Export ciphers (w/o ADH+NULL) not offered (OK)
LOW: 64 Bit + DES, RC[2,4] (w/o export) not offered (OK)
Triple DES Ciphers / IDEA not offered
Obsolete CBC ciphers (AES, ARIA etc.) offered
Strong encryption (AEAD ciphers) offered (OK)
Here it is showing that the weak configuration supports CBC encryption mode, which is regarded weak.
🔸 Tool 3: SSLyze
🚄 SSLyze is a fast and powerful SSL/TLS scanning tool and Python library. We will use it in command line mode, only, but you can integrate it in your applications and pipelines.
Running it in command line mode is simple. Once installed, just run:
$ sslyze --mozilla_config={old, intermediate, modern} hostname
If you omit the mozilla_config flag it defaults to intermediate in the final compliance summary.
The output is really fast. Where testssl.sh needed tens of seconds, sslyze ends in less than one second.
A run against the weak configuration provides this output, where I have omitted information about the certificates and vulnerabilities:
$ sslyze --mozilla_config=old test.my.pki
CHECKING CONNECTIVITY TO SERVER(S)
---------------------------------- test.my.pki:443 => 127.0.1.1 SCAN RESULTS FOR TEST.MY.PKI:443 - 127.0.1.1
-------------------------------------------- * SSL 2.0 Cipher Suites:
Attempted to connect using 7 cipher suites; the server rejected all cipher suites. * SSL 3.0 Cipher Suites:
Attempted to connect using 80 cipher suites; the server rejected all cipher suites. * TLS 1.0 Cipher Suites:
Attempted to connect using 80 cipher suites; the server rejected all cipher suites. * TLS 1.1 Cipher Suites:
Attempted to connect using 80 cipher suites; the server rejected all cipher suites. * TLS 1.2 Cipher Suites:
Attempted to connect using 156 cipher suites. The server accepted the following 18 cipher suites:
TLS_RSA_WITH_AES_256_GCM_SHA384 256
TLS_RSA_WITH_AES_256_CBC_SHA256 256
TLS_RSA_WITH_AES_256_CBC_SHA 256
TLS_RSA_WITH_AES_128_GCM_SHA256 128
TLS_RSA_WITH_AES_128_CBC_SHA256 128
TLS_RSA_WITH_AES_128_CBC_SHA 128
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 256 ECDH: X25519 (253 bits)
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 256 ECDH: prime256v1 (256 bits)
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 256 ECDH: prime256v1 (256 bits)
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 256 ECDH: prime256v1 (256 bits)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 128 ECDH: prime256v1 (256 bits)
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 128 ECDH: prime256v1 (256 bits)
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 128 ECDH: prime256v1 (256 bits)
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 256 DH (2048 bits)
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 256 DH (2048 bits)
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 256 DH (2048 bits)
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 128 DH (2048 bits)
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 128 DH (2048 bits) The group of cipher suites supported by the server has the following properties:
Forward Secrecy OK - Supported
Legacy RC4 Algorithm OK - Not Supported
* TLS 1.3 Cipher Suites:
Attempted to connect using 5 cipher suites; the server rejected all cipher suites. * Elliptic Curve Key Exchange:
Supported curves: X25519, X448, prime256v1, secp384r1, secp521r1
Rejected curves: prime192v1, secp160k1, secp160r1, secp160r2, secp192k1, secp224k1, secp224r1, secp256k1, sect163k1, sect163r1, sect163r2, sect193r1, sect193r2, sect233k1, sect233r1, sect239k1, sect283k1, sect283r1, sect409k1, sect409r1, sect571k1, sect571r1 SCANS COMPLETED IN 0.463308 S
----------------------------- COMPLIANCE AGAINST MOZILLA TLS CONFIGURATION
-------------------------------------------- Checking results against Mozilla's "MozillaTlsConfigurationEnum.INTERMEDIATE" configuration. See https://ssl-config.mozilla.org/ for more details. test.my.pki:443: FAILED - Not compliant.
* certificate_path_validation: Certificate path validation failed for C=SE,O=Keyfactor Community,CN=test.my.pki.
* maximum_certificate_lifespan: Certificate life span is 365000 days, should be less than 366.
SSLyze finished with a useful compliance summary with respect to Mozilla’s configurations. In this case it fails because it does not recognize the certificate chain of my test pki. If my server had a valid certirficate the output would be:
test.my.pki:443: OK - Compliant.
If you run it to validate a stringer ciphersuite it shows which ones should not be accepted. For instance, trying to validate the Mozilla’s intermediate configuration it provides the following compliance summary:
COMPLIANCE AGAINST MOZILLA TLS CONFIGURATION
--------------------------------------------
test.my.pki:443: FAILED - Not compliant.
* ciphers: Cipher suites {'TLS_RSA_WITH_AES_256_CBC_SHA', 'TLS_RSA_WITH_AES_256_GCM_SHA384', 'TLS_RSA_WITH_AES_128_CBC_SHA', 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA', 'TLS_DHE_RSA_WITH_AES_128_CBC_SHA256', 'TLS_DHE_RSA_WITH_AES_256_CBC_SHA256', 'TLS_RSA_WITH_AES_128_GCM_SHA256', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', 'TLS_RSA_WITH_AES_256_CBC_SHA256', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA', 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384', 'TLS_RSA_WITH_AES_128_CBC_SHA256'} are supported, but should be rejected.
Here we see it is basically rejecting ciphersuites with RSA key exchanges or CBC encryption modes. However, it says nothing about the fact that TLSv1.3 is not supported by the server. This is a pity.
Testing the stronger configuration of my test setup against the “modern” Mozilla configuration provides the following output:
COMPLIANCE AGAINST MOZILLA TLS CONFIGURATION
--------------------------------------------
Checking results against Mozilla's "MozillaTlsConfigurationEnum.MODERN" configuration. See https://ssl-config.mozilla.org/ for more details. test.my.pki:443: FAILED - Not compliant.
* certificate_types: Deployed certificate types are {'rsa'}, should have at least one of {'ecdsa'}.
* certificate_signatures: Deployed certificate signatures are {'sha256WithRSAEncryption'}, should have at least one of {'ecdsa-with-SHA512', 'ecdsa-with-SHA384', 'ecdsa-with-SHA256'}.
* tls_versions: TLS versions {'TLSv1.2'} are supported, but should be rejected.
* ciphers: Cipher suites {'TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256', 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256', 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256', 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'} are supported, but should be rejected.
We see the Mozilla modern configuration rejects RSA certificates, supporting TLSv1.2 and its associated ciphersuites.
With some integration, SSLyze is a great candidate to integrate in your compliance or monitoring solution to validate your TLS services in a fast and simple manner. However, it does not provide information on client support. Qualys SSL Lab or testssl.sh can help there, so you may want to run scans with different tools.
📡 Sniffing TLS Services in your network
Scanners can show you one part of the picture: the server side. Sniffing into the network provides also very useful information from the client side. With tools like Wireshark you can take and view network traffic captures to see all the details of any TLS session.
But our interest lies in gaining insights from the protocols and ciphersuites available in our packet capture, rather than doing a detail inspection of a single packet. To achieve that goal we will use tshark to extract some TLS fields from each packet and save them in a csv file. Later we will work with that information on an Excel spreadsheet. You can achieve much more than this with tshark, but this is a poor man’s guide, not a hacker guide… Feel free to take a look at other options.
Let’s assume you have a packet capture (pcap) file named TLStest.pcap containing several TLS sessions. Let’s extract the information we need with tshark:
$ tshark -r TLStest.pcap -Y "(tls.handshake.version || tls.alert_message.desc)" -T fields -E header=y -E separator=, -E quote=d -e frame.number -e ip.src -e ip.dst -e tcp.stream -e tls.record.content_type -e tls.handshake.type -e tls.handshake.version -e tls.handshake.extensions.supported_version -e tls.handshake.ciphersuite -e tls.alert_message.desc -e tls.handshake.extensions_server_name > TLStest.csv
–r sets the input file
–Y sets the filter for the interesting packets. I’m getting the ones that contain the fields tls.handshake.version and tls.alert_message.dec to capture TLS Client Hellos, Server Hellos and handshake failures.
The remaining flags define the export format to csv (json is also possible), the csv format and the fields we want, each one indicated with –e. We are getting the frame number to look for individual packets in Wireshark if needed, IP addresses, TCP stream number to identify which of the packets take part of a single conversation, TLS handshake type, version information, ciphersuites and alerts. We also get the name of the requested website to understand what services are involved.
This will give us a csv file with one line per packet matching the input filter. A sample line might look like this:
frame.number,ip.src,ip.dst,tcp.stream,tls.record.content_type,tls.handshake.type,tls.handshake.version,tls.handshake.extensions.supported_version,tls.handshake.ciphersuite,tls.alert_message.desc,tls.handshake.extensions_server_name
44,"x.x.x.x","y.y.y.y","7","22","1","0x0303",,"0xc02f,0xc013,0xc027,0xc030,0xc014,0xc028,0x009c,0x002f,0x003c,0x009d,0x0035,0x003d,0x0041,0x0084,0xc02b,0xc009,0xc023,0xc02c,0xc00a,0xc024,0x009e,0x0033,0x0067,0x009f,0x0039,0x006b,0x0045,0x0088,0x00ff",,
We will open this csv file in Excel and play around with it to get some insights. Many of the fields contain codes that we will need to translate into something meaningful.
👋 Client Hellos and Server Hellos
Let’s take a look first to the tls.handshake.type field. A value of 1 means the packet is a “Client Hello”, the initial request of a client to start a TLS session. A value of 2 means the packet is a “Server Hello”, the request from a server to a “Client Hello”. The value 1 is typically alone, but some “Server Hello” packets may have additional handshake types as multiple handshake messages might be bundled together. Those additional values would be followed after the initial 2, indicating the “Server Hello”, separated by commas.
So, we can insert a new column after the tls.handshake.type column. The new column should be G, if you are following this instructions. We will call this column “TLS HANDSHAKE TYPE” and include the following formula in the first data row:
=IF(F2=1;"Client Hello";IF(F2=2;"Server Hello";IF(ISNUMBER(SEARCH("2,";F2));"Server Hello";"Other")))
When expanding this formula to all the rows in the Excel file we will get a direct reference to “Client Hello” and “Server Hello” packets in the spreadsheet.
🔎 TLS Versions
Identifying the TLS version is more tricky due to backward compatibility requirements. Take a look at RFC8446 Appendix D for more information.
We will need to combine the tls.handshake.version and the tls.handshake.extensions.supported_version columns to understand what TLS version is used in each packet.
These fields will identify TLS versions according to the following dictionary:
TLS version code TLS version
0x0304 TLSv1.3
0x0303 TLSv1.2
0x0302 TLSv1.1
0x0301 TLSv1.0
0x0300 SSLv3
0x0002 SSLv2
Starting with 0x7 Experimental
We will insert a new column after the tls.handshake.extensions.supported_version (it will be J if tou are following my instructions). It will identify the TLS version used in the packet in that row. We will call this column “TLS VERSION”.
TLSv1.3 packets will identify their supported versions in the tls.handshake.extensions.supported_version field, so looking if that field has contents is an indicator of a TLSv1.3 packet. However we can expect future protocol upgrades to use this field, so we can do something more than just checking if it has contents and we will verify the highest known protocol version specified in the field.
Older protocol versions will include the protocol version in the tls.handshake.version field.
So, the formula for row 2 of the “TLS VERSION” column will be:
=IF(I2<>"";IF(ISNUMBER(SEARCH("0x0304";I2));"TLSv1.3";IF(ISNUMBER(SEARCH("0x0303";I2));"TLSv1.2";IF(ISNUMBER(SEARCH("0x0302";I2));"TLSv1.1";IF(ISNUMBER(SEARCH("0x0301";I2));"TLSv1.0";IF(ISNUMBER(SEARCH("0x7";I2));"Experimental";"Unknown")))));IF(H2="0x0304";"TLSv1.3";IF(H2="0x0303";"TLSv1.2";IF(H2="0x0302";"TLSv1.1";IF(H2="0x0301";"TLSv1.0";IF(H2="0x0300";"SSLv3";IF(H2="0x0002";"SSLv2";IF(ISNUMBER(SEARCH("0x7";H2));"Experimental";"Unknown"))))))))
Where we first search for the highest known protocol version in column I if it is not empty, or translate the version code in column H if I is empty.
This column gives us the TLS version used in a specific packet, but “Client Hello” packets offer different versions for the server to pick one. A client may request TLSv1.3 and the server downgrade the session to TLSv1.2. We really want to know what TLS version is actually negotiated for the session. We will create two more columns to gain more insights.
We will create one column to understand what version was requested by the “Client Hello” in the same TLS session to which each row belongs to. Insert a new column after the “TLS VERSION” column (it will be K in my example) and name it “CLIENT TLS VERSION”. If the packet is a “Client Hello” we will just pick the value of the “TLS VERSION” column. Otherwise we will look for a “Client Hello” packet containing the same value in the tcp.stream field and return the value of the “TLS VERSION” column.
=IF(G2="Client Hello";J2;IF(VLOOKUP(D2;D:J;4;FALSE)="Client Hello";VLOOKUP(D2;D:J;7;FALSE);"No Client Hello found"))
We will also want to know how the server responded to the “Client Hello” requests, to identify when the server is downgrading the connections. We will insert a new column after “CLIENT TLS VERSION”. We will name it “SERVER NEGOTIATED TLS VERSION” it should be on column L. It will search for a packet in the next packets containing the same tcp.stream value, validate that it is a “Server Hello” and return the contents of “TLS VERSION”.
=IF(G2="Client Hello";IF(VLOOKUP(D2;D3:J3000;4;FALSE)="Server Hello";VLOOKUP(D2;D3:J3000;7;FALSE));"This is not a Client Hello")
This should give you a spreadsheet looking like this:
From here you can create a pivot table to understand what protocol versions your systems are negotiating. For instance, the following pivot table configuration will summarize the TLS versions requested and agreed indicating, where available, the sites name:
The “TLS HANDSHAKE TYPE” will filter Client Hellos as we want to see the perspective of what clients are requesting and what severs are accepting.
We will get in the rows a summary of CLIENT TLS VERSIONs, for each version we will get the SERVER NEGOTIATED TLS VERSIONS, and, if available, the tls.handshake.extensions_server_name.
The result in my test packet capture, from where I have hidden the server names, shows that there were 384 TLSv1.3 Client Hellos of which 290 were downgraded to TLSv1.2 by the Server Hello.
A graph can help us visualize the insights we are getting:
Here we see that approximately only half of the sites support TLSv1.2 and some of those sites have a good part of the traffic share. We also see that some clients are requesting TLSv1.0 and some servers seem to be accepting it. From the pivot table we can extract the relevant traffic to identify the IP addresses involved and launch updates on specific servers.
🤝 Ciphersuites
The tls.handshake.ciphersuite column contains the codes for the ciphersuites negotiated. Typically you will find a set of different, comma-separated, ciphersuites proposed in the Client Hellos and a single ciphersuite accepted in the Server Hello.
The tricky part is translating all the codes using the TLS parameters guide from IANA. You will need to download the csv file from IANA, clean it, and concatenate the first two values from to match the Wireshark format (for instance, IANA’s 0xab, 0xcd would be Wireshark’s 0xabcd). You can use that table to translate the tls.handshake.ciphersuite into a new column inserted afterwards and named “TLS CIPHERSUITE”. That is a little bit complex and requires using macros. A simpler way is copying the contents from tls.handshake.ciphersuite in TLS CIPHERSUITE and replace only the interesting codes, as there are not many interesting ones in the end as you will see.
One option is to create a pivot table filtering the Server Hellos and getting the list of negotiated TLS CIPHERSUITES, like this:
In my test packet capture only seven ciphersuites are negotiated, so replacing just their codes with names is simple. In my test packet capture we see several Server Hellos are accepting suites with 3DES, CBC encryption modes, and the obsolete SHA1 hash algorithm. You can get more details on the definition and security of each ciphersuite in ciphersuite.info. Take a look for instance at the most concerning ciphersuite in my test file, TLS_RSA_WITH_3DES_EDE_CBC_SHA. From this insights you can launch remediation activities to improve the configuration in your servers.
You can also use the tls.alert_message.desc to identify failing TLS sessions, possibly due to a mismatch between client requests and the configurations your server is willing to accept. This might be handy to monitor the impact of implementing modern configurations.
💡 Conclusion
We have seen how you can leverage different simple tools available publicly to gain insights about the TLS configuration in your IT estate. Network scanners give visibility over different parameters in your servers configurations, such as certificates information, TLS version and ciphersuite support. Sometimes your server might be behind a middle box, such as a Content Delivery Network or a proxy, hiding the real configuration of your server. Capturing traffic in your DMZ provides information about your real end server configuration and about your client’s behavior.
We saw that according to SSLLabs SSLPulse, only 70% of the sites surveyed support TLSv1.3. Probably, your infrastructure matches this profile and should improve its configuration. You may find that either your servers have not been updated for a long time or that their sysadmins are just adopting old configurations from previous servers.
You can use these tools to:
- Establish controls to understand what configurations you have,
- Create curated configurations with a well understood security and client compatibility profile, and
- Make those configurations a standard in your organization.
This will create the knowledge and processes for your organization to reach 100% support of TLS1.3, a prerequisite for PQC, with a known set of ciphersuites. So, you will be in control of the cryptography configuration in your servers and ready to adapt them as soon as PQC in TLS is mature.
Before you go:
Clap if you liked it 👏, comment and share this article to reach more community 🧞.
Would you like to be part of our technology project? Find our open vacancies worldwide here 👉 https://www.betechwithsantander.com/en/home