The Runtime Theory
Networking

How TLS Actually Secures a Connection

From the ClientHello to the session ticket: what every message in a TLS handshake does, why certificates are the center of the trust model, and how TLS 1.3 changed the game.

The Runtime Theory Team3 min read#tls#encryption#certificates#protocols
On this page

"HTTPS encrypts the traffic" is true and useless. It's like saying a castle has walls — the questions worth asking are which walls, whose keys, and which messages can still leak. This article reconstructs TLS from its messages, because the messages are the explanation.

The problem TLS exists to solve

Before TLS, connecting to a server over TCP was like sending postcards through a postal system where every clerk could read them and, worse, rewrite the address:

  1. Eavesdropping — anyone on the path can read the bytes.
  2. Tampering — anyone on the path can modify them.
  3. Impersonation — anyone can pretend to be the server, if they can also control where your packets go (DNS or BGP hijacking), because nothing authenticates the far end.

TLS solves all three at once with three cryptographic mechanisms:

ThreatCountermeasure
Eavesdroppingsymmetric encryption of application data
Tamperingauthenticated encryption (AES-GCM / ChaCha20-Poly1305)
Impersonationpublic-key signatures validated by certificate chains

Notice what's not on that list: hiding the conversation metadata. TLS 1.2 leaks server names by design (SNI); TLS 1.3 encrypts them too. But what TLS has never promised is obscuring who talks to whom — that's what has always made "just use TLS" an incomplete privacy story.

A handshake you can actually follow

TLS 1.3 reduced the handshake to a single flight in each direction. Here it is as sent over the wire, simplified:

text
C -> S  ClientHello
        version, cipher suites, key_shares (ephemeral key), SNI
 
S -> C  ServerHello
        chosen cipher suite, key_shares (server's ephemeral key)
        EncryptedExtensions
        Certificate (leaf + intermediates)
        CertificateVerify  (signs the transcript with the leaf key)
        Finished (MAC over the whole transcript)
 
C -> S  Finished
        [application data can now flow in both directions]

Two properties make this safe:

Forward secrecy via ephemeral keys. The key_shares in ClientHello/ServerHello are ephemeral (ECDHE-generated on the spot). The session key is derived from them, never from the long-term certificate key. Even if an attacker later steals the server's certificate private key, they cannot decrypt past traffic. That is why "we have the keys on a HSM" is not a retroactive privacy guarantee — the ephemeral design means it never needs to be.

A significant transcript. CertificateVerify signs everything exchanged so far (ClientHello message by message, in order). Neither side can swap a cipher suite or inject a different certificate mid-handshake without the signature breaking. The signature chain is the whole answer to impersonation: the leaf certificate's key is trusted because it's signed by the intermediate, which is signed by the root — and the root is in your browser's trust store.

The certificate is the authority

The deepest TLS question is always: what makes the server's key legitimate? The answer is atoms of trust — root certificates — that you already hold:

text
your trust store (system roots)
        │ signs

intermediate CA                  (policy enforcement here)
        │ signs

leaf certificate for api.example.com
        │ binds

ECDSA/RSA public key  →  the key that signs CertificateVerify

Every browser ships with ~150 root certificates controlled by ~50 organizations. Raw mathematics authenticates the key; the certificate chain authenticates the binding between that key and a name. Which is why:

  • Certificate expiry breaks connections even though the cryptography is perfect — the binding is time-boxed.
  • A stolen leaf key only impersonates one name; a stolen intermediate key can mint any leaf the CA policy allows.
  • Self-signed certificates fail for clients because you are not in their trust store — not because the math is wrong.

Where TLS still lets you down

TLS secures the pipe between two ends. It cannot secure what happens at either end, and the practical failures are all about the ends:

  1. Client-side trust decisions. If your app trusts any CA (or disables validation for debugging — then ships), the entire protocol becomes a formality. Yes, that includes corporate MITM proxies: the proxy is genuinely in the pipe, and your client decides it's fine.

  2. Certificate vs. identity. TLS validates that the peer holds the key matching the name you asked for. It does not validate that the name is the service you think it is — phishing works inside TLS perfectly.

  3. The Let's Encrypt blind spot. 90-day certificates are a brilliant compromise: they shrink the window in which a compromised leaf key is usable, at the cost of requiring automation. Teams that hand-roll renewal "later" discover their own expiry billing.

What memory of this model is good for

  • One RTT matters: TLS 1.3 vs 1.2 is a full round trip on every cold connection.
  • CertificateVerify and forward secrecy are why "they have the private keys" is never a complete security story.
  • TLS is a trust decision your code makes silently at boot — validating it is a runtime behavior, and the runtime is where this platform lives.