TLS: what actually protects the connection
TLS gives an HTTPS connection three guarantees — confidentiality, integrity, and server identity — and this lesson walks through how the handshake, certificate chains, and modern configuration actually deliver them.
TLS (Transport Layer Security) is the protocol that turns a plaintext TCP connection into a private, tamper-evident channel between a client and a server. When you see https://, TLS is doing the work underneath. It provides three things at once: confidentiality (an eavesdropper on the wire sees only ciphertext), integrity (any modification of the bytes in flight is detected and the connection breaks), and server authentication (you get cryptographic proof you are talking to the host you dialed, not an impostor). Optionally it can also do client authentication, where the server verifies the client's certificate — the basis of mutual TLS (mTLS).
What the handshake establishes
Before any application data flows, client and server run a handshake to agree on parameters and derive keys. Conceptually it goes like this: the client sends a ClientHello listing its supported protocol versions, cipher suites, and a random value. The server replies with its choice plus its certificate, which carries the server's public key. The two sides then run a key exchange to agree on a shared secret without ever sending it in the clear.
Modern deployments use ephemeral Elliptic Curve Diffie-Hellman (ECDHE) for that exchange. Ephemeral means a fresh key pair is generated per session and thrown away afterward. This gives forward secrecy: even if the server's long-term private key is stolen later, past recorded sessions cannot be decrypted, because the secret that protected them no longer exists anywhere. The handshake output is a set of symmetric session keys — the asymmetric crypto is used only to bootstrap; the actual traffic is encrypted with fast symmetric ciphers like AES-GCM or ChaCha20-Poly1305.
TLS 1.3 streamlines all of this into a single round trip, drops every legacy key-exchange mode that lacked forward secrecy, and removes old ciphers entirely. If you can run TLS 1.3, the secure defaults are largely made for you.
Certificates and the chain of trust
A certificate presented by the server is not trusted on its own — it is trusted because it chains up to something you already trust. The chain has three tiers:
- Leaf certificate — issued for the specific hostname (e.g.
example.com), containing its public key and validity dates. This is what the server sends. - Intermediate certificate(s) — issued by the CA to sign leaf certificates; they insulate the root from day-to-day signing. The server should send these alongside the leaf.
- Root certificate — the trust anchor, pre-installed in your OS or browser trust store. Its private key signs intermediates and is kept offline.
The client validates the chain by verifying each signature up to a root it already holds, checking that the leaf's name matches the host you connected to, that the dates are current, and that nothing in the chain is revoked. What a Certificate Authority (CA) actually attests is narrow but important: that the party requesting the certificate demonstrated control of that domain at issuance time. It does not vouch for the site's honesty, safety, or business — only for the domain-to-key binding.
Where TLS breaks in the real world
Most production TLS failures are configuration and lifecycle problems, not broken cryptography:
- Expired certificate — validity lapsed because renewal was manual and someone forgot. Clients hard-fail.
- Name mismatch — the certificate is for
www.example.combut served onapi.example.com, or the SAN list is missing the host. The identity check fails. - Self-signed in production — a certificate not chained to any trusted root. Fine for local dev, but in prod it trains users to click through warnings, defeating authentication.
- Weak or deprecated protocol versions — SSLv3, TLS 1.0, and TLS 1.1 are deprecated and carry known weaknesses; they should be disabled in favor of TLS 1.2 and 1.3.
- Missing HSTS — without HTTP Strict Transport Security, a user's first request can be downgraded to plaintext and intercepted before the redirect to HTTPS.
- Mixed content — an HTTPS page that pulls scripts, images, or styles over
http://. The insecure sub-resources are exposed and can undermine the whole page.
When you probe or scan a TLS endpoint, only test hosts you own or are explicitly authorised to test. Connecting a scanner to third-party infrastructure without permission can be treated as unauthorised access regardless of your intent.
How to inspect a live endpoint
You can read exactly what a server negotiates. openssl s_client opens a raw TLS connection and prints the presented chain, the negotiated version, and the cipher:
# Connect, send SNI, and show the certificate chain
openssl s_client -connect example.com:443 -servername example.com </dev/null
# Pin a specific version to confirm old protocols are refused
openssl s_client -connect example.com:443 -tls1_1 </dev/null # should fail
# Inspect the leaf certificate's names and dates
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltNameFor a full audit, testssl.sh enumerates supported protocols, cipher suites, certificate details, and common vulnerabilities against one target, without installing anything beyond OpenSSL:
# Scan one host you control
./testssl.sh --protocols --server-defaults example.com:443Check the three things that matter together, not one at a time: the protocol (is TLS 1.0/1.1 still accepted?), the cipher (is it forward-secret and AEAD, like ECDHE-...-GCM?), and the chain (does the leaf name match and does it reach a trusted root?). A green padlock in a browser hides all three from you.
How to configure and defend it
- Restrict versions to TLS 1.2+, and prefer TLS 1.3. Disable SSLv3, TLS 1.0, and TLS 1.1 explicitly at the server.
- Offer only strong cipher suites — forward-secret ECDHE key exchange with AEAD ciphers (AES-GCM, ChaCha20-Poly1305). Drop RC4, 3DES, and CBC-mode legacy suites.
- Automate renewal with ACME / Let's Encrypt (e.g.
certbotoracme.sh). Short-lived certificates renewed by a robot never lapse the way annual manual ones do. - Enable HSTS so browsers refuse plaintext to your domain, and serve every sub-resource over HTTPS to eliminate mixed content.
- Monitor expiry independently of your renewal tooling — alert days ahead on the actual served certificate, so a broken renewal job surfaces before users hit an error.
# Send HSTS (only after you are confident all sub-resources are HTTPS)
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
# Cron-style expiry check against the live endpoint (warn 14 days before expiry)
cert_state=$(openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -checkend $((14*86400)) >/dev/null && echo ok || echo EXPIRING)
echo "$cert_state"The through-line: TLS's cryptography is rarely the weak point. The connection is protected when the version is modern, the cipher is forward-secret, the certificate is valid and correctly named, and renewal is automated so none of that silently decays. Inspect what your servers actually negotiate rather than trusting that the padlock means it is all fine.