SecurityBeginner

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 text

Without this

Every byte is readable by anyone on the path: your password, your session cookie, the whole page.

1 / 4

Four steps. Each one exists because the previous one leaves a specific hole.

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 . This is what happens on a modern TLS 1.3 connection.

Sequence

Your browserclient
The serverwikipedia.org
ClientHello
ServerHello
Certificate + CertificateVerify
Verify
Finished
GET / HTTP/1.1

1 / 6

One round trip. The server proves who it is, and the traffic is already encrypted by the time the certificate arrives.

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 . 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.

Five fields carry the whole argument. Nothing in here says whether the operator is honest.

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 . 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 climbs until it lands on something it already trusts. Run out of links first and the chain fails.

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

  1. Until Mar 2026

    The old ceiling

    398 days

    A little over a year. An annual calendar reminder was survivable, if unwise.

  2. 15 Mar 2026today

    In force today

    200 days

    Roughly two renewals a year for anyone still doing it by hand.

  3. 15 Mar 2027

    Next step down

    100 days
  4. 15 Mar 2029

    The destination

    47 days

    About eight renewals a year. There is no version of this that a human does reliably.

Under ballot SC-081v3, the window shrinks by roughly eight times in three years. Renewal has to be something a machine does.

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 . 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

~2 min

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.