How SSL actually works
SSL is now TLS, and encryption is the smaller half of the job. What the handshake really does, what a certificate proves, and how teams break it in production.
Assumes you know
- What an HTTP request is
- That DNS turns a domain name into an IP address
Type your password into a page served over plain http://, and every device
between you and that server can read it. Not decode it, not crack it. Read it, the
way you are reading this sentence. The same is true of the session cookie that comes
back, which is the thing an attacker actually wants, because it lets them be you
without ever knowing your password.
That is the hole https:// closes. Everything else in this article is about how it
closes it, and why the answer needs so many moving parts.
Why any of this exists
Start with two machines and nothing else, and add one piece at a time.
Build it up
you --------------------> server
plain textWithout this
Every byte is readable by anyone on the path: your password, your session cookie, the whole page.
you ====================> server
unreadable in transitWithout this
You now have a private conversation with someone you have not identified. An attacker in the middle will happily encrypt with you instead.
This part was solved decades ago. Two machines that have never met can agree a shared secret over a public wire in one round trip.
you ====================> server
+ cert
"I own example.com"Without this
Anyone can generate a document claiming any domain. A claim nobody vouches for is worth nothing.
you ====================> server
+ cert
|
signed by CA
(already trusted
by your device)Without this
Nothing. This is the piece that closes the loop, and it is why the rest of TLS looks complicated.
Encryption solves reading. The certificate makes a claim. The authority makes the claim checkable. Everything else in this article is detail on those three.
1 / 4
Encrypting to an attacker sitting between you and your bank achieves nothing except making the eavesdropping tidier. Identity is also where the day-to-day trouble is: almost every TLS problem you hit in production is a certificate problem, not a cryptography problem.
A note on the name
SSL stands for Secure Sockets Layer, built by Netscape in the mid-1990s. Every version of it is broken: SSL 2.0 was prohibited by RFC 6176, and SSL 3.0 followed after the POODLE attack. The replacement is TLS, Transport Layer Security, whose 1.0 and 1.1 versions were themselves deprecated by RFC 8996 in 2021. You are almost certainly running TLS 1.2 or TLS 1.3.
The old word survives because it is welded into config keys (ssl_certificate in
nginx), library names (OpenSSL) and a decade of marketing. When someone says “SSL
cert” they mean a TLS certificate, and you do not need to correct them. This article
uses the two words for the same thing, and names a version where it matters.
The handshake, step by step
Before any HTTP request is sent, the two sides run a The opening exchange of a TLS connection, where both sides agree which version and algorithms to use, establish a shared key, and the server proves its identity.. This is what happens on a modern TLS 1.3 connection.
Sequence
1 / 6
TLS 1.2 needed two round trips here, which is a large part of why 1.3 exists. TLS 1.3 also cut the cipher suite list to five (RFC 8446, appendix B.4) and removed every mode that had turned out to be a foot-gun, including static RSA key exchange and renegotiation.
The key that encrypts your traffic is generated fresh for this connection and thrown away afterwards, so recording the traffic today and stealing the server’s private key next year does not decrypt it. That property is called Past sessions stay unreadable even if the server’s long-term private key is later compromised, because each session used its own ephemeral key.. The certificate’s key only ever signs. It never touches your data.
Check yourself
An attacker steals a server's private key today. What can they do with traffic they recorded from that server six months ago?
What is actually inside a certificate
A certificate is a small, boring, structured file. Click through the parts that matter, taken from the certificate Wikipedia was actually serving when this article was written:
Anatomy
TLS certificate, leaf
SubjectThe primary name, kept for historical reasons. Browsers stopped trusting this field on its own years ago, so on its own it proves nothing.
Subject Alternative NameThe authoritative list of hostnames this certificate covers. This is what the browser actually checks. A name missing here fails validation no matter how the DNS is set up.
Public keyThe key used to verify the handshake signature. It proves identity and never encrypts your traffic, which is why stealing it later does not decrypt old sessions.
ValidityNot-before and not-after. There is no grace period: at the not-after timestamp every client starts refusing the connection. A 90-day window here, the Let's Encrypt default.
IssuerWho signed this certificate, and therefore the next link up the chain. The client uses this to work out what to look for next.
SignatureThe issuer's signature over every field above. Change one byte of the certificate and this stops matching, which is what makes the whole chain tamper-evident.
Nothing in there says whether the operator is honest, solvent or competent. A public certificate is issued once the applicant proves they control the domain, usually by serving a specific file or publishing a specific DNS record. That is the whole test.
The chain of trust, and why your laptop believes anyone
Your device ships with a The set of certificate authority certificates your operating system or browser trusts by default. It is a list of a few hundred organisations, curated by Apple, Microsoft, Mozilla and Google.. That list is the foundation of the whole system, and you did not choose it.
Roots do not sign your certificate directly. Their private keys live offline in hardware, brought out rarely. Instead a root signs an intermediate, the intermediate signs your certificate, and your server presents the resulting chain. Press the button and watch the client walk it:
Stack
The client stops here. It never verified this certificate against anything; it already trusts it, because your operating system or browser vendor put it there.
Signed by the root above. Roots stay offline in hardware, so intermediates do the day-to-day signing and can be replaced if compromised.
This is the link your server has to send and most often forgets. Without it the client cannot connect the leaf to anything it trusts.
The certificate for the actual site. Verification starts here and climbs.
The client walks upwards, checking each signature, until it lands on something in its root store. If it lands there, the chain is trusted. If it runs out of links first, it is not.
Your server must send the intermediates. It must not send the root. The root is already on the client, and sending it wastes bytes on every handshake. This one sentence is the source of an enormous share of TLS support tickets.
Check yourself
Your API works in the browser but Java clients report 'unable to find valid certification path'. What is the most likely cause?
The traps
Wildcards cover one level, the way a key opens one floor rather than the building.
A certificate for *.example.com matches api.example.com and www.example.com. It
does not match a.b.example.com, and it does not match example.com itself unless
that name is listed separately. Most issuers add the bare domain for you, which
is why this only bites when you generate certificates yourself.
Expiry is an outage, not a warning. An expired certificate is a passport at a border, not a library card: there is no talking your way past the date. At the not-after timestamp every client starts refusing the connection, with no grace period. The window is shrinking fast:
Timeline
- Until Mar 2026
The old ceiling
398 daysA little over a year. An annual calendar reminder was survivable, if unwise.
- 15 Mar 2026today
In force today
200 daysRoughly two renewals a year for anyone still doing it by hand.
- 15 Mar 2027
Next step down
100 days - 15 Mar 2029
The destination
47 daysAbout eight renewals a year. There is no version of this that a human does reliably.
Manual renewal has stopped being a viable strategy.
The hostname you connect to is what gets checked, not the IP. Modern servers host
many sites on one address, so the client announces which one it wants via
Server Name Indication, a field in the first handshake message
naming the hostname the client wants. It lets one IP address serve certificates for
many different sites.. Connect by IP address and you will get whichever
certificate is the default, and validation will fail. That is why openssl s_client
has a separate -servername flag.
TLS usually stops at your edge. In most deployments the load balancer or CDN terminates TLS and opens a second connection to your application. Whether that second hop is encrypted is a decision somebody made, possibly by accident. The padlock in the user’s browser says nothing about it.
Mixed content quietly downgrades your page. An HTTPS page that pulls a script over plain HTTP is as compromised as if the whole page were HTTP, because an attacker who can rewrite that script owns the page. Browsers block this outright for scripts and stylesheets now, so the usual symptom is a feature that silently does not work.
Check yourself
A phishing site at paypa1-secure.com shows a padlock and a valid certificate. What went wrong?
What TLS will not do for you
It does not make your application secure. TLS protects data while it is moving between two points. SQL injection, a leaky API, a public S3 bucket and a weak password policy are all completely untouched by it.
It does not hide who you are talking to. Your DNS lookup, the destination IP, and the SNI hostname in the ClientHello are all visible to anyone on the path. What is hidden is the URL path, the headers, the cookies and the body. Encrypted Client Hello (RFC 9849, published March 2026) fixes the SNI leak and is supported by several large CDNs, but it needs matching DNS records and client support, so cleartext SNI is still the norm.
It does not verify the client. By default only the server proves anything. Mutual TLS, where the client presents a certificate too, exists and works well, but it is a deliberate extra step and it brings its own certificate lifecycle to manage.
It is not free. You pay a round trip on every new connection, some CPU on every handshake, and a permanent operational cost in renewals and expiry monitoring. Worth paying almost every time, but pretending it is free is how the renewal job ends up nobody’s job.
Checking it yourself
One command shows you the whole picture:
echo | openssl s_client -connect wikipedia.org:443 -servername wikipedia.org
The -servername flag sets SNI, and without it you may get the wrong certificate
entirely. The parts that matter:
Certificate chain
0 s:CN = *.wikipedia.org
i:C = US, O = Let's Encrypt, CN = YE2
v:NotBefore: Aug 5 19:15:41 2026 GMT; NotAfter: Nov 3 19:15:40 2026 GMT
1 s:C = US, O = Let's Encrypt, CN = YE2
i:C = US, O = ISRG, CN = Root YE
...
Verification: OK
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Verify return code: 0 (ok)
Read it upwards. s: is the subject, i: is the issuer, and each entry’s issuer is
the next entry’s subject. That is the chain. Verification: OK means it reached a
trusted root; anything else names the specific link that failed. The NotAfter date on
entry 0 is your renewal deadline, and here it is 90 days after issuance, which is the
Let’s Encrypt default.
Try it yourself
Find a certificate that covers more names than you expect
Pull the list of hostnames out of a live certificate:
echo | openssl s_client -connect wikipedia.org:443 -servername wikipedia.org \
2>/dev/null \
| openssl x509 -noout -text \
| grep -A3 "Subject Alternative Name"Then try one that will fail, and read the error rather than the page:
curl -sSI https://expired.badssl.com/What you should see
The first command prints a long comma-separated list of DNS names, including entries for every Wikimedia project and their mobile subdomains. One certificate, one key, many names. That list is the definitive answer to “which hostnames will this certificate work for”, and a name missing from it is a name that will fail no matter how the DNS is configured.
The second command fails before a single byte of HTTP moves, with a message like
certificate has expired. Note that curl never sends the request. The handshake is
what failed, which is why an expired certificate takes a site down completely rather
than degrading it.
Where to go next
Three directions, depending on what you are trying to do.
If you run servers: learn ACME properly, so certificate renewal becomes something you configure once. Then read up on HSTS, the header that tells browsers never to try plain HTTP for your domain again.
If you are debugging: get comfortable with openssl s_client, then look at
Certificate Transparency logs (searchable at crt.sh), which record every public
certificate ever issued for a domain. They are how you find out that somebody issued a
certificate for your domain without telling you.
If you want the mechanism underneath: read about Diffie-Hellman key exchange, which is the trick that lets two strangers agree on a secret over a wire everyone can read. It is the one piece of mathematics in this article that genuinely feels like magic, and it is more approachable than its reputation suggests.
If you remember nothing else
- SSL is a dead protocol name. Every version of SSL is broken and switched off; what you are actually running is TLS, almost always 1.2 or 1.3.
- Encryption is the solved half of the problem. The hard part is identity, and the entire certificate authority system exists to answer one question: does this server really control this domain name?
- A certificate is a public key plus a list of domain names, signed by someone your device already trusts. It is a statement about a name, not about honesty.
- The padlock proves you are talking to the domain in the address bar, and nothing more. A phishing site can hold a perfectly valid certificate.
- Most TLS failures in production are not cryptography failures. They are a missing intermediate certificate, a renewal nobody automated, or a hostname the certificate does not cover.
Quick answers
- Is SSL the same thing as TLS?
- They are the same idea under two names. SSL was the original protocol from Netscape, and every version of it (2.0 and 3.0) is now broken and disabled everywhere. TLS is the successor, and the versions in real use today are TLS 1.2 and TLS 1.3. The word SSL survives in product names, config file keys and library names, so you will keep typing it for years, but the bytes on the wire are TLS.
- What does the padlock icon actually prove?
- It proves two things: the connection is encrypted, and the server presented a certificate for the exact domain shown in the address bar, signed by an authority your device trusts. It proves nothing about whether the site is honest, safe or well run. Phishing sites routinely have valid certificates, because getting one only requires proving you control the domain.
- Why does my site work in the browser but fail with curl or Java?
- Almost always a missing intermediate certificate. Your server is meant to send the leaf certificate plus every intermediate above it, stopping short of the root. Browsers paper over a missing intermediate by caching one from an earlier visit or fetching it on the fly, while curl, Java, Python and Go generally do not. Fix it by serving the full chain file rather than the leaf alone.
- Does HTTPS hide which website I am visiting?
- Not by itself. Your DNS lookup and the destination IP address are visible, and the hostname is sent in cleartext inside the first handshake message, in a field called SNI. HTTPS hides the URL path, the headers, the cookies and the body. Encrypted Client Hello (RFC 9849, published March 2026) closes the SNI gap, but it needs support at both ends and is not widely deployed yet.
- How long do SSL certificates last now?
- Public certificates are getting steadily shorter. The CA/Browser Forum ballot SC-081v3 caps them at 200 days from 15 March 2026, 100 days from 15 March 2027, and 47 days from 15 March 2029. Let's Encrypt still issues 90 days by default and offers an opt-in 6-day profile. The practical consequence is that manual renewal has stopped being viable.