Who does what
| Primitive | Solves | Phase |
|---|---|---|
| Asymmetric (ECDHE) | Negotiate a session key, prove server identity | Handshake |
| Symmetric (AES-GCM / ChaCha20) | Encrypt the actual traffic | Data transfer |
| Hashing (SHA-256) + MAC | Detect tampering | Throughout |
The handshake (TLS 1.3) in order
- Client sends ClientHello: supported versions, cipher suites, random value;
- Server replies with ServerHello and its certificate (containing the public key);
- The client validates the chain: trusted CA, matching hostname, valid dates;
- Both sides exchange ECDHE material and independently derive the same session key;
- All subsequent data is encrypted symmetrically and carries an authentication tag.
The whole exchange usually takes tens to just over a hundred milliseconds; TLS 1.3 resumption makes repeat visits nearly free.
Why hybrid, not all asymmetric
Asymmetric algorithms are orders of magnitude slower and RSA cannot encrypt more than its modulus length. It therefore only handles agreeing on a symmetric key securely, leaving bulk data to AES — hybrid encryption, the pattern behind every secure channel.
What a certificate chain is
Trust is chained: site certificate → intermediate CA → root CA (shipped with the OS or browser). A missing, expired or mismatched link makes the browser refuse the connection. Self-signed certificates are "untrusted" simply because their root is not in the trust store.
Practical debugging: three certificate/handshake issues
- "NET::ERR_CERT_DATE_INVALID": the certificate expired or the clock is wrong. Fix: check server time and automate renewal (ACME) instead of manual yearly signing.
- "Certificate name mismatch": the SAN does not cover that subdomain. Fix: include every needed name in the SAN, or use a wildcard certificate.
- "Missing intermediate breaks some clients": the server does not send the full chain — browsers may cope, CLI tools often fail. Fix: configure the full chain (fullchain).
Common questions
Does HTTPS hide the domain I visit? TLS 1.3 encrypts most handshake metadata, but DNS lookups can still reveal the hostname; stronger privacy needs DoH/DoT and ECH. Is HTTPS enough to be safe? It secures the transport against eavesdropping and tampering — it says nothing about the site's intentions; phishing sites get certificates too. What about expiry? Automate issuance and renewal with ACME (Let's Encrypt and similar).
Three diagnostic commands
# Show the chain, validity dates and issuer
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates -issuer
# Show the negotiated protocol and certificate verification result
curl -sS -o /dev/null -w '%{http_version} verify=%{ssl_verify_result}
' https://example.com/
# Diagnosis only (never for production decisions): skip verification
curl -kI https://example.com/
Common failures
- Incomplete chain: a missing intermediate makes some browsers report an untrusted certificate;
- Hostname mismatch: the certificate covers www but you visited the apex domain, or the reverse;
- Wrong local clock: produces bogus "not yet valid" or "expired" errors;
- SNI misconfiguration: with several hostnames on one IP, serving the wrong certificate breaks the handshake.
Try them: hashing, symmetric encryption
TLS 1.3 versus 1.2 handshakes
- Round trips: 1.3 completes in one RTT (1.2 needs two) and can reach 0-RTT on resumption;
- Key exchange: 1.3 removed RSA key exchange, leaving only (EC)DHE, which gives forward secrecy by default;
- More is encrypted: 1.3 encrypts the certificate too, so middleboxes see less and rely more on SNI for routing;
- Upgrade plan: enable 1.3 first, keep 1.2 for old clients, and explicitly disable 1.0/1.1.
The price of 0-RTT
0-RTT on resumption saves a round trip, but early data lacks forward secrecy and can be replayed. Use it only for idempotent read-only requests; writes and payment calls should wait until the handshake completes.
SNI and certificate selection
When several domains share one IP, the server picks a certificate from SNI. Clients too old to send SNI get the default certificate and see a mismatch. Ensure a usable default certificate, watch the share of requests without SNI, and handle that traffic separately if it matters.