TLS 1.2 needed two round trips before you could send application data. TLS 1.3 gets it down to one, and the trick is that the client guesses.
The client guesses a key
In the ClientHello, the client doesn’t just say “here are the ciphers I support”. It also throws in a key share — an ephemeral (EC)DH public key for the group it bets the server will pick:
ClientHello
+ supported_versions: TLS 1.3
+ key_share: x25519 <client pubkey>
+ signature_algorithms, ...
If the bet is right (it usually is — almost everyone does x25519), the server replies with its own key share in the ServerHello, and both sides can derive the session keys immediately. Everything after the ServerHello — including the server’s certificate — is already encrypted.
ServerHello
+ key_share: x25519 <server pubkey>
{EncryptedExtensions}
{Certificate}
{CertificateVerify}
{Finished}
Why this matters beyond speed
Because the certificate is encrypted, a passive observer can’t see which cert the server presented. The one thing still in the clear is the SNI in the ClientHello — which is exactly what ECH (Encrypted Client Hello) is trying to close.
0-RTT, briefly
On resumption the client can send data in its very first flight using a pre-shared key. It’s fast and it’s dangerous: that early data is replayable, so it must be idempotent. I keep 0-RTT off for anything that mutates state.