If the first article is the short version, this is the version for when you want to know what each part of the handshake is actually doing.
The easiest mistake to make with TLS is to treat it like one blob called "encryption." It is not one blob. It is a staged negotiation with a few very specific goals:
- agree on protocol parameters
- derive fresh traffic secrets
- prove the server's identity
- verify that the transcript was not altered
- get to application data with as little latency as possible
TLS 1.3 matters because it does all of that with less baggage than the older versions most engineers still carry around in their heads.
If you have not read the primer yet, start with SSL vs TLS vs HTTPS: The Mental Model Behind Every Secure Website.
Start with the real constraints
Before a browser can send a single meaningful HTTP request, the handshake has to answer a handful of questions:
- Which version of TLS are we using?
- Which algorithms and parameters will protect this connection?
- How do both sides derive the same shared secrets without sending them directly?
- How does the client know this server is the real one?
- How do both sides know nobody changed the negotiation in flight?
TLS 1.3 answers all of that in one full round trip for a fresh connection.
That is not trivia. It is latency. Every extra round trip becomes user-visible time.
ClientHello: the client shows its hand early
The first meaningful TLS message is ClientHello.
This message does much more work than the friendly name suggests. It is not just "hello." It is the client's capability advertisement and connection context.
At a high level, ClientHello carries:
- supported TLS versions
- supported cipher suites
- supported groups for key agreement, such as
x25519orP-256 - a
key_sharevalue for the client's ephemeral key exchange - the requested hostname via
SNI - the preferred application protocol via
ALPN, such ash2orhttp/1.1 - supported signature algorithms
- sometimes resumption information if this is not the first connection
The key design move in TLS 1.3 is that the client sends key agreement material immediately.
Older handshakes needed more back-and-forth before both sides could get to useful secret material. TLS 1.3 moves that work earlier so the rest of the connection can happen faster.
Why ClientHello is still plaintext
The client cannot encrypt the first message because the shared keys do not exist yet.
That means the early connection still leaks metadata. Observers can usually see:
- that a TLS handshake is happening
- the source and destination IP addresses
- the port
- timing and packet sizes
- much of the
ClientHello - often the requested hostname via
SNI, unlessECHis in play
This is one of the most useful truths to keep in mind: TLS hides the contents of the conversation, not the fact that the conversation exists.
ServerHello: this is the turning point
The server reads ClientHello and chooses the connection parameters.
At a high level, ServerHello says:
- this is the TLS version we are actually using
- this is the cipher suite we selected
- this is the server's key share
Once the client has the server's key share, both sides have enough information to derive shared secret material locally.
That is the turning point in the handshake. From here on, the connection is no longer just negotiating. It is building real cryptographic state.
A detail that looks strange unless you know the history
TLS 1.3 still carries some legacy compatibility behavior because the internet is full of old middleware.
That is why packet captures and fields can sometimes look slightly odd or more backward-looking than the modern design would suggest. The protocol had to evolve on top of a messy deployed world, not in a vacuum.
That tension between clean design and real-world compatibility explains a lot of TLS.
The shared secret is derived, not sent
This is the point where a lot of explanations get hand-wavy, even though it is one of the most important ideas in the protocol.
The browser and the server do not send the final connection secret back and forth.
Instead, each side combines:
- its own private key agreement material
- the other side's public key agreement material
Both arrive at the same shared secret independently.
That is why the handshake can happen on an untrusted network without anyone simply reading "the session key" out of the packets.
It also explains why modern TLS gets forward secrecy from ephemeral key exchange. Each connection gets its own short-lived key agreement state rather than relying on one long-term server secret to protect every session.
The key schedule is more important than it sounds
Once the shared secret exists, TLS 1.3 does not just say "great, that is the key now."
Instead, it feeds that material into a key schedule that derives different secrets for different phases and directions of the connection.
Conceptually, the handshake moves through stages:
- derive handshake secrets
- protect the rest of the handshake
- derive application traffic secrets
- protect HTTP or other application data
That separation matters because TLS is not a one-key protocol. It is a protocol that deliberately derives:
- different secrets for different phases
- different secrets for client and server directions
- later secrets that depend on the validated transcript
That is one reason TLS 1.3 feels cleaner than older designs. The structure makes the security story easier to follow.
This is where many explanations go wrong
Many people imagine TLS like this:
- public handshake
- handshake finishes
- encryption begins
That is not how TLS 1.3 works.
After ServerHello, the handshake already starts moving under encryption. The later messages are protected before application data begins.
That means there are really two different transitions to keep straight:
- the transition from plaintext negotiation to encrypted handshake traffic
- the transition from encrypted handshake traffic to encrypted application data
If you blur those together, the whole protocol feels fuzzier than it actually is.
The server is not trusted just because it sent a certificate
Once the encrypted part of the handshake starts, the server sends the information that lets the client authenticate it.
The important messages here are:
EncryptedExtensionsCertificateCertificateVerifyFinished
They are easy to treat as one block, but each serves a different purpose.
EncryptedExtensions
Think of this as the server sending the rest of the negotiated connection details now that handshake encryption is available.
It is less famous than the certificate messages, but it is part of the protocol becoming fully concrete rather than just tentatively negotiated.
Certificate
This is the server's certificate chain.
The certificate answers an identity question. It says that, according to a trust chain the client may accept, this public key is associated with this name.
What it does not say is "you can stop thinking now, the connection is trusted." The certificate alone is not enough.
CertificateVerify
This is the proof-of-possession step.
Without CertificateVerify, a server could send a certificate chain and never prove it actually controls the private key behind that chain.
This message signs the handshake transcript. That proves the server holds the corresponding private key inside this specific handshake, not just in theory.
This is a good example of why TLS is worth understanding at the message level. The protocol is solving precise problems, not just waving certificates around.
Finished
Finished is the transcript integrity check.
It proves that the sender derived the expected handshake secrets and saw the same conversation up to that point.
If negotiation details had been tampered with earlier in the exchange, this is one of the places where the connection would fail to verify.
In plain English, Finished means:
"We agree on what just happened, and the cryptographic state we derived from it matches."
The client still has real verification work to do
When the browser receives the encrypted server messages, it still has to decide whether the connection deserves trust.
That means checking things like:
- does the hostname match the certificate?
- does the certificate chain lead to a trusted root?
- is the certificate currently valid?
- did the server's proof verify correctly?
- does the transcript integrity check pass?
Only after those validations succeed does the client send its own Finished.
This is an important moment in the mental model. Before this point, the client can compute keys, but it should not yet treat the server as authenticated.
When can HTTP actually start?
Only after the authentication and transcript checks are in place do both sides move fully into application traffic.
For the web, that means the browser can finally send a normal HTTP request over the TLS-protected connection.
This ordering matters:
- negotiate parameters
- derive handshake secrets
- authenticate the server
- confirm transcript integrity
- derive application traffic state
- send application data
So when someone says "encryption starts after the handshake," the accurate answer is: not exactly.
The later handshake is already encrypted before the handshake is complete. Application data starts only after the trust checks are in place.
Why TLS 1.3 feels simpler than TLS 1.2
TLS 1.3 is not just TLS 1.2 with a few new options. It is a cleanup pass on years of accumulated protocol history.
Important simplifications include:
- forward secrecy by default through ephemeral key exchange
- removal of RSA key exchange
- removal of CBC-based cipher suites
- removal of TLS-level compression
- less room for downgrade and fallback complexity
- a smaller and easier-to-reason-about negotiation surface
That matters because complexity becomes implementation risk. Every legacy branch is another place for bugs, misconfiguration, surprising interoperability problems, or security mistakes.
TLS 1.3 got better partly by becoming less willing to carry the past forever.
The operational fields engineers actually care about
Some handshake details matter far more in real systems than in simplified diagrams.
SNI
SNI tells the server which hostname the client wants.
That matters because one IP address often serves many domains. Without SNI, the server may not know which certificate to present.
This is why SNI misconfiguration can surface as the wrong certificate being served even when the rest of the stack looks healthy.
ALPN
ALPN is how both sides agree on the application protocol that comes after TLS.
For web traffic, that often means choosing between http/1.1 and h2.
This matters operationally because application behavior, performance characteristics, and sometimes entire debugging paths change depending on what ALPN negotiated.
Termination points
Most systems do not run one end-to-end TLS hop from browser to origin process with no intermediaries.
Instead, TLS is often terminated at a CDN, load balancer, ingress proxy, or service mesh sidecar. That means the trust boundary depends on where TLS ends, not just whether "TLS is enabled."
This is one of the most common places engineers oversimplify the story.
Session resumption and 0-RTT
A returning client may not need to pay the full handshake cost again.
Resumption lets client and server reuse trusted state from an earlier connection, which can reduce latency. TLS 1.3 also supports optional 0-RTT early data.
That sounds great until you remember the tradeoff: early data can be replayed.
So 0-RTT is not a universal performance win. It is a performance feature with application-level consequences.
mTLS
In ordinary web browsing, the server proves its identity and the client typically does not.
In mutual TLS, the client also presents a certificate. That matters in service-to-service systems, private APIs, and zero-trust environments where the server wants a cryptographic identity for the caller, not just a bearer token.
What still leaks on the wire
Even with TLS 1.3, observers can still learn useful metadata.
Usually visible:
- source and destination IPs
- ports
- timing and duration
- traffic shape and packet sizes
- the fact that TLS was used
- the early handshake
- often the requested hostname
Usually hidden once the encrypted part of the handshake begins:
- the later handshake details
- the certificate chain in TLS 1.3
- HTTP headers and bodies
- cookies, tokens, and API payloads
This matters in real architecture discussions because people often hear "encrypted" and mentally jump to "opaque." TLS is powerful, but it is not invisibility.
Where TLS breaks in production
The ugly production incidents around TLS are usually not "the math failed." They are almost always trust, configuration, or environment issues.
Common examples:
- expired certificates
- hostname mismatch
- incomplete certificate chains
- wrong certificate served because of
SNImisconfiguration - unsupported protocol versions or cipher overlap problems
- client and server disagreeing on
ALPN - clock skew making a certificate appear not-yet-valid or expired
- TLS terminated at the edge while downstream hops are assumed secure without being audited
This is why a useful TLS mental model is not just the happy path. It includes where things fail when real infrastructure gets involved.
The durable version to keep in your head
If you want the shortest engineer-friendly summary, keep this:
ClientHellois the capability advertisement and connection contextServerHellois the moment both sides can derive shared secret material- the next phase is about protected configuration, identity proof, and transcript verification
- certificates establish identity; key agreement establishes fresh secrecy
- TLS 1.3 is better mostly because it is faster, simpler, and harder to misuse
- application data is encrypted, but important metadata is still visible
That is the TLS 1.3 handshake as an engineer should think about it: not as magic, and not as "just encryption," but as a carefully staged negotiation that turns an untrusted network path into a channel with confidentiality, integrity, and authenticated identity.