TLS/SSL: Encryption and Certificates

K
Kai··5 min read

Article 8 said HTTPS is HTTP wrapped in TLS. This article opens the TLS box: how it encrypts, what a "certificate" is, and how the browser knows a website is trustworthy. This is the foundation of web security, and the source of the familiar "certificate expired / invalid" errors.

Naming: SSL is the old name (obsolete, no longer to be used); TLS is the modern replacement. People still casually say "SSL," but it's really TLS. The latest version is TLS 1.3 (RFC 8446) — faster and more secure.

TLS guarantees three things

To recap from Article 8, TLS provides three things:

  • Confidentiality — the content is encrypted; a man in the middle (Article 3) can't read it.
  • Integrity — data isn't modified in transit without detection.
  • Authentication — you're sure you're talking to the real example.com, not an impostor.

The first two are "encryption"; the third is "certificates" — and the third is the subtle part.

Two kinds of encryption, for two jobs

TLS uses both kinds of encryption, each for a purpose:

  • Asymmetric — each side has a public/private key pair. Encrypt with one key, decrypt with the other. Strong but slow. TLS uses it during the handshake so both sides can securely agree on a shared key.
  • Symmetric — the same key encrypts and decrypts. Fast. TLS uses it to encrypt the actual data after the handshake.

The idea: use asymmetric (slow but secure) only to exchange a symmetric key (called the session key), then use the symmetric key (fast) for all the data. You get the best of both.

The TLS handshake

After TCP has connected (Article 6), TLS handshakes to set up the encrypted channel (TLS 1.3, simplified):

   Client                                      Server
     │ ── ClientHello ─────────────────────────► │  "I support TLS 1.3, these ciphers..."
     │ ◄─ ServerHello + Certificate + key ──────── │  "picked cipher X; here's my certificate"
     │    (1) verify the certificate (chain of trust — section below)
     │    (2) both compute the same symmetric session key
     │ ══════════ encrypted channel ready ═══════ │
     │ ◄──────── encrypted HTTP data ───────────► │

TLS 1.3 merges steps, costing just one round trip (1-RTT) — much faster than older versions. Observe it live:

echo | openssl s_client -connect example.com:443 -servername example.com
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Verify return code: 0 (ok)

TLSv1.3 is the version, TLS_AES_256_GCM_SHA384 is the negotiated cipher suite (AES-256 for symmetric encryption), and Verify return code: 0 (ok) means the certificate is valid.

Certificates: proving "I really am example.com"

Encryption alone isn't enough — if you encrypt but you're talking to an impostor, it's meaningless. You need to authenticate the server. That's the job of the digital certificate.

A certificate is a file binding the server's public key to its identity, signed by a trusted third party (the CA — Certificate Authority). See a real certificate:

echo | openssl s_client -connect example.com:443 -servername example.com \
  | openssl x509 -noout -subject -issuer -dates
subject=CN = example.com                                   ← who it's issued to
issuer=O = "CLOUDFLARE, INC.", CN = Cloudflare TLS ... CA   ← who issued it (the CA)
notBefore=Apr  2 ... 2026 GMT                               ← valid from
notAfter=Jul  1 ... 2026 GMT                                ← expires

Note notAfter — a certificate has an expiry. Forgetting to renew is the classic "your connection is not private" error. (Services like Let's Encrypt issue certificates for free and renew them automatically to avoid this.)

The chain of trust: why the browser trusts it

How does the browser know example.com's certificate is genuine? It doesn't trust it directly — it trusts it via a chain (chain of trust) that traces back up to a Root CA it already trusts.

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | grep -E "s:|i:"
 0 s:CN = example.com                          ← the server certificate
   i:CN = Cloudflare TLS Issuing ECC CA 1       ← signed by this intermediate CA
 1 s:CN = Cloudflare TLS Issuing ECC CA 1        ← the intermediate CA
   i:CN = SSL.com TLS Transit ECC CA R2          ← signed by a higher CA
 2 s:CN = SSL.com TLS Transit ECC CA R2
   i:CN = SSL.com TLS ECC Root CA 2022           ← up to the ROOT CA

Read s: (subject — who it's issued to) and i: (issuer — who signed it):

   Root CA (SSL.com Root 2022)   ← lives in the OS/browser "trust store," trusted absolutely
        │ signs
        ▼
   Intermediate CA (SSL.com Transit → Cloudflare CA)
        │ signs
        ▼
   example.com certificate   ◄── what the server presents during the handshake

The browser follows the signature chain: the example.com certificate is signed by the Cloudflare CA, the Cloudflare CA is signed by SSL.com, and the SSL.com Root is in the list of Root CAs the OS/browser trusts by default. Tracing up to a trusted Root = valid (Verify return code: 0). If the chain is broken, the name is wrong, or it's expired → the browser warns.

This is why you can't sign your own certificate for google.com: a self-signed certificate doesn't trace up to any Root CA the browser trusts, so it gets flagged immediately.

DevOps in practice

  • Certificate expiry is a common production incident — set alerts, use auto-renewal (Let's Encrypt + certbot — this very blog series uses certbot, remember).
  • Self-signed certificates work fine internally/in dev, but you have to add your own CA to the trust store to avoid warnings.
  • TLS termination: usually the load balancer/reverse proxy (Article 11) handles TLS decryption, then speaks plain HTTP to the internal backend — called "TLS termination."

Wrap-up

TLS (the new name for SSL; current version TLS 1.3) gives HTTPS three guarantees: confidentiality, integrity, authentication. It uses asymmetric encryption during the handshake to agree on a symmetric key, then uses that key to encrypt the data (fast). A certificate binds the public key to the server's identity, signed by a CA; the browser trusts the server by tracing the chain of trust from the certificate up to a trusted Root CA. openssl s_client lets you inspect the version, cipher, and certificate chain. Remember: certificates expire — auto-renew so you don't go down.

We've now walked the whole journey of a request (DNS → TCP → TLS → HTTP). The next three articles shift to the operational angle: access control (firewall), scaling out (load balancer), and diagnosis. Article 10: firewalls and network security.