toolhq.io

All posts
7 min readby Jameel Haider

TLS cipher suites explained: reading the names and picking a set

A cipher suite is the set of algorithms two parties agree to use for a connection. The names look like configuration noise, but they are structured, and once you can read one the whole topic becomes concrete.

Reading a TLS 1.2 name

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Four decisions, in order:

PartRole
ECDHEKey exchange: how the session key is agreed
RSAAuthentication: the key type in the server's certificate
AES_128_GCMBulk cipher: how the data is encrypted
SHA256Hash used for the key derivation function

So: agree a key with elliptic curve Diffie-Hellman, prove identity with an RSA certificate, encrypt with 128 bit AES in GCM mode, derive keys using SHA-256.

The authentication field is why an ECDSA certificate needs ECDSA suites enabled. Configure only ECDHE_RSA suites and deploy an ECDSA certificate, and no suite matches. The handshake fails with a message about no shared cipher, which sends people looking at protocol versions when the certificate key type is the real cause.

What TLS 1.3 changed

TLS 1.3 removed everything negotiable except the encryption itself. Key exchange and authentication are agreed separately, so the suite name shrinks:

TLS_AES_128_GCM_SHA256

There are exactly five suites in TLS 1.3, and three of them are all anyone uses:

  • TLS_AES_128_GCM_SHA256
  • TLS_AES_256_GCM_SHA384
  • TLS_CHACHA20_POLY1305_SHA256

All of them provide forward secrecy and all use AEAD. There is no weak option to accidentally leave enabled. This is the single biggest security improvement in TLS 1.3: the old protocol's flexibility was mostly the ability to be configured badly.

The practical consequence is that TLS 1.3 cipher configuration is not something you need to tune. Your TLS 1.2 configuration is where the decisions still live.

Forward secrecy

ECDHE and DHE generate a fresh key pair per connection and discard it afterwards. If your server's private key is stolen next year, traffic captured today stays unreadable, because that key was never used to encrypt the session.

The alternative, static RSA key transport, has the client encrypt the session key to the certificate's public key. Anyone who later obtains the private key can decrypt every session ever recorded. Suites without ECDHE or DHE in the name work this way, and they are the ones to remove first. TLS 1.3 dropped the mode entirely.

ECDHE is preferred over DHE on cost. Finite field Diffie-Hellman is considerably slower, and misconfigured DHE parameters have their own history of weakness.

AEAD versus the old construction

GCM, CCM and ChaCha20-Poly1305 are AEAD modes: they encrypt and authenticate in one operation. The older approach paired a cipher in CBC mode with a separate HMAC, and applied them in an order that turned out to be fragile.

That fragility produced a long list of attacks. BEAST exploited predictable initialisation vectors in CBC. Lucky13 used timing differences in padding checks. POODLE broke SSL 3.0's padding entirely. Each was patched, and the underlying design kept producing new variants until AEAD replaced it.

Prefer AEAD suites. In TLS 1.2 that means the GCM and CHACHA20_POLY1305 suites, not the CBC ones.

ChaCha20-Poly1305 is worth enabling alongside AES. Modern processors have AES instructions that make AES-GCM extremely fast, but hardware without them, which includes plenty of phones and embedded devices, runs ChaCha20 several times faster. Offering both lets each client pick what suits it.

What to disable

RemoveReason
Anything without ECDHE or DHENo forward secrecy
RC4Statistical biases, broken
3DES64 bit block size, vulnerable to Sweet32
NULL, EXPORT, anonNo encryption or no authentication
MD5Broken hash
CBC suitesPrefer AEAD; keep only if you need old clients
SSL 3.0, TLS 1.0, TLS 1.1Deprecated protocols, not suites, but disable them too

Sweet32 is the one that surprises people, because 3DES is not "broken" in the way RC4 is. The problem is its 64 bit block size: after enough data on one connection a collision becomes likely and leaks plaintext. On long lived connections that is reachable.

Do not hand write the list

The most useful advice here is to not compose a cipher string yourself. Mozilla publishes maintained configurations for common servers in three tiers:

  • Modern — TLS 1.3 only. Choose it if you control your clients.
  • Intermediate — TLS 1.2 and 1.3, forward secrecy throughout. The right default for a public site.
  • Old — includes legacy suites. Only for a documented requirement.

Take the intermediate configuration for your server version, and revisit it when you upgrade the server rather than editing it incrementally. Hand tuned cipher strings copied between projects are how a 3DES suite survives for a decade.

Ordering and preference

In TLS 1.2, client and server both have preferences, and the server decides whose ordering wins. Enabling server preference (ssl_prefer_server_ciphers on in nginx) means your order decides, which is usually what you want, since it stops a client choosing the weakest mutually supported option.

The exception is the AES and ChaCha20 tradeoff described above: a client without AES hardware knows better than you which is faster for it. Recent OpenSSL versions handle this with equal preference groups, and the Mozilla configurations account for it.

In TLS 1.3 the question largely disappears, because all the available suites are strong.

Verifying what you actually negotiate

Configuration and behaviour drift apart. A load balancer, CDN or reverse proxy may terminate TLS with its own settings, so the cipher list on your origin can be irrelevant to what users get.

Check the live endpoint rather than the config file. The SSL checker reports the negotiated protocol version and certificate details for a host as it is actually served. For a broader estate, the bulk SSL checker runs the same check across many hosts, which is how you find the one server still offering TLS 1.0 after a fleet wide change.

From a terminal, openssl s_client -connect example.com:443 prints the negotiated suite, and adding -tls1_2 or -cipher lets you confirm that a suite you believe is disabled genuinely is. Testing that a bad configuration is refused is worth as much as testing that a good one is accepted.

Related reading: the TLS handshake explained walks through the negotiation itself, TLS 1.2 vs TLS 1.3 covers what else changed, and ECDSA vs RSA certificates covers the authentication half of the suite name.