What is TLS and how does HTTPS work?
In one sentence: HTTPS is HTTP inside an encrypted tunnel (TLS). Public-key cryptography lets both ends agree on a secret key, and lets the server prove, with a certificate, that it is who it claims to be.
What you will learn
- Tell symmetric encryption apart from public- and private-key encryption, and explain what a signature is for.
- Understand what a certificate is, who signs it and what the browser checks.
- Follow the TLS 1.3 handshake and know what stays protected and what doesn't.
- Inspect a website's certificate with curl and openssl.
Before you start, read: 07-dns.md
The problem
Section titled “The problem”In lesson 4 you saw that an unencrypted HTTP message is like a postcard: every router along the way could read it. On a coffee shop’s Wi-Fi, anyone on the same network can try to see your traffic. And not just read it: change it too, for example to slip a script (code your browser runs) into the page you’re downloading.
There’s a third problem, one that’s harder to spot. In lesson 7 you saw that your computer asks a resolver for the IP address of yourbank.com and trusts the answer. If someone manages to give you a fake IP address, you connect to their server thinking it’s your bank’s.
So you need three things:
- Confidentiality: nobody along the way can read the data.
- Integrity: nobody can change it without it being noticed.
- Authenticity: you know you’re talking to the real server.
(term) TLSThe protocol that encrypts a connection and uses a certificate to prove the server is who it claims to be (Transport Layer Security). It sits between TCP and HTTP, and HTTP over TLS is HTTPS.Go to definition (Transport Layer Security) gives you all three. And HTTP inside a TLS connection is (term) HTTPSHTTP inside a TLS connection, usually on port 443. Nobody along the way can read or change the requests and responses, and the browser uses a certificate to check that the server really belongs to the domain.Go to definition.
The analogy
Section titled “The analogy”The analogy
Imagine handing out open padlocks with your name on them in the street. Anyone can take one, put a message in a box and lock it with your padlock. But only you have the key that opens them. The padlocks are your (term) Public keyThe half of a key pair you can show to anyone. It is used to encrypt messages that only the private key will decrypt, and to check the signatures the private key makes.Go to definition: it doesn’t matter that everyone has one. The key is your (term) Private keyThe half of a key pair that only its owner knows. It decrypts what was encrypted with its public key and signs messages anyone can check with the public key. If it leaks, it must be replaced.Go to definition, and you never give it to anyone.
Now the other way around: you have a unique wax seal, and everyone has a photo of what its mark looks like. If you seal a letter, anyone can check that the seal is yours and that nobody has changed the letter. The seal doesn’t hide the letter: anyone can read it. That’s a (term) Digital signatureA few bytes someone computes from a message with their private key. With the public key, anyone can check that the message hasn’t changed and that the owner of that key signed it.Go to definition.
That leaves one question: is the photo of the seal you’re shown really your bank’s? That’s what the (term) CertificateA document that binds a domain name to a public key, signed by a certificate authority and with an expiration date. The server sends it at the start of a TLS connection.Go to definition is for. It works like a passport, where an authority everyone trusts (the government; here, a ) states “this seal belongs to yourbank.com”.
Where the analogy breaks down
- A physical padlock can be forced open. Real keys can’t: at today’s key sizes, all the computers in existence working together would take longer than the age of the universe.
- In TLS 1.3, the server’s padlocks don’t encrypt anything. The shared secret key is agreed on with a different trick (the key exchange you’ll see below), and the server only uses its seal, to prove who it is.
- A wax seal looks the same on every letter. A digital signature is computed from the message: change one letter and it’s no longer valid.
- A passport lasts for years. A website certificate lasts a few months (example.com’s, three), and on every connection the browser checks that it’s still valid and that the name matches.
How it really works
Section titled “How it really works”One key: symmetric encryption
Section titled “One key: symmetric encryption”The oldest way to (term) EncryptionTransforming a message with a key so that only someone with the key to decrypt it can read it. If the same key encrypts and decrypts, it is symmetric; if there are two different keys, a public one and a private one, it is asymmetric.Go to definition uses a single key, the same one to encrypt and to decrypt. Today we use algorithms like AES or ChaCha20, which are very fast: your phone encrypts hundreds of megabytes per second without breaking a sweat.
The ciphers TLS uses (they’re called AEAD) also attach a tag to every chunk of data, computed with the key. If someone changes a single bit along the way, the tag doesn’t match and the other end cuts the connection: that’s where integrity comes from.
There’s one catch: both ends need the same key. If your browser and the server have never met, how do they agree on a secret key over a network where anyone can listen? If they send it, anyone can copy it.
Two keys: public-key cryptography
Section titled “Two keys: public-key cryptography”Public-key (or asymmetric) cryptography uses a pair of keys that go together: a public one and a private one. The two are mathematically related, but with today’s computers it’s infeasible to work out the private key from the public one. Depending on the algorithm, a key pair is used for one of these two things (that’s why the playground generates two pairs):
- To encrypt: anyone encrypts with your public key, and only your private key decrypts it.
- To sign: you sign with your private key, and anyone checks the signature with your public key. If a single letter of the message changes, the signature is no longer valid.
It’s much slower than symmetric encryption, and it can only encrypt small messages. That’s why TLS doesn’t use it for the data, but for what symmetric encryption can’t do on its own: agree on the key and prove who the server is.
How TLS combines them: the handshake
Section titled “How TLS combines them: the handshake”After the TCP (term) HandshakeThe exchange of messages two endpoints use to open a connection before sending data. In TCP there are three (SYN, SYN-ACK and ACK), and they cost one round trip.Go to definition from lesson 6, the browser and the server do another one: the TLS handshake. In TLS 1.3, the current version, it goes like this:
- Browser · ServerBoth compute the same secret key. From here on, everything is encrypted.
- The key exchange (Diffie-Hellman). Each end makes up a secret number and sends a “public part” computed from it. By combining its own secret with the other end’s public part, both arrive at the same result, without that result ever traveling over the network. Anyone listening sees both public parts and can’t compute it. That’s where the connection’s symmetric key comes from.
- Identity. The server sends its certificate and uses its private key to sign all the handshake messages, including both public parts of the exchange, which are new for every connection. The browser checks the signature with the public key in the certificate. Whoever copies the certificate can’t sign, a signature from another connection isn’t valid, and if someone in the middle changed the server’s public part, the signature would stop matching.
- Finished. Each side confirms it has seen the same thing; if someone had tampered with a handshake message, this is where it would show.
All of this costs one round trip, on top of TCP’s. That’s why, in DevTools (the Chrome tools you opened in lesson 4), Initial connection includes the SSL part (the old name for TLS).
Certificates and certificate authorities
Section titled “Certificates and certificate authorities”In essence, a certificate says “public key X belongs to example.com, from September 26 to December 25, 2026”, and it’s signed by a certificate authority (CA). Before issuing it, the CA checks that whoever requests it controls the domain, for example by asking them to publish a specific file on that website. Let’s Encrypt does this automatically and for free, and you’ll use it in Phase 8.
And why trust the CA? Because your operating system and your browser ship with a list of root authorities they trust, more than a hundred of them. Usually the root doesn’t sign certificates directly: it signs an intermediate CA’s certificate, which in turn signs the domain’s. That’s the certificate chain, and the browser follows it until it reaches a root on its list.
On every connection, the browser checks three things:
- The chain: each certificate is signed by the next one, up to a trusted root.
- The name: the domain you’re visiting is among the names in the certificate.
- The dates: the certificate is currently valid. It hasn’t expired, and its start date isn’t in the future.
If any of them fails, you’ll see an error screen instead of the website.
What HTTPS protects and what it doesn’t
Section titled “What HTTPS protects and what it doesn’t”With HTTPS, nobody along the way can read or change the URL path (/account/transactions), the headers, the cookies or the content. But some things are still visible:
- The domain. It almost always travels unencrypted in the ClientHello’s SNI (Server Name Indication), because the server needs it to choose which certificate to send. A newer extension, ECH, encrypts it, but it’s still rare. The domain also travels in the classic DNS query from lesson 7.
- The destination IP address, which routers need.
- How much and when you send and receive.
And the padlock only says that the connection to that domain is secure. It says nothing about whether the domain is honest: a phishing website can have HTTPS too.
Try it
Section titled “Try it”Start with the playground: it’s real cryptography, the kind built into your browser (the Web Crypto API). Generate a key pair, encrypt a message with the public key and decrypt it with the private key. Try decrypting it with another private key, too. And try pasting a long paragraph into the message. Then, in the signing part, sign the message, change “10” to “1000” in the received message and verify again.
playground · real cryptography
Encrypt: what the public key locks, only the private key opens
2048-bit RSA keys (RSA-OAEP), generated in your browser with the Web Crypto API. They never leave this page.
Sign: what the private key signs, anyone can check with the public key
ECDSA on the P-256 curve, the same kind of key as example.com’s certificate.
For encryption, the playground uses RSA, which is good enough to show the idea. TLS 1.3 no longer encrypts anything with RSA: it uses the key exchange above. It does still use signatures like the ones in the second part.
Now, a real website’s certificate:
1. The certificate for example.com
curl -sv -o /dev/null https://example.comWhat you will see:
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256 / [blank] / UNDEF* Server certificate:* subject: CN=example.com* start date: Sep 26 22:49:11 2026 GMT* expire date: Dec 25 22:56:35 2026 GMT* subjectAltName: host "example.com" matched cert's "example.com"* issuer: C=US; O=SSL Corporation; CN=Cloudflare TLS Issuing ECC CA 3* SSL certificate verify ok.These are the lines of curl -v that are about TLS (we’ve removed the rest):
TLSv1.3andAEAD-CHACHA20-POLY1305-SHA256: the TLS version and the symmetric cipher both sides agreed on, ChaCha20 with the Poly1305 integrity tag.subject: who the certificate belongs to.subjectAltName … matched: the name you’re visiting is in the certificate.start dateandexpire date: three months of validity.issuer: who signed it, a Cloudflare intermediate CA.SSL certificate verify ok: the chain leads to a trusted root.
Your dates will be different: the certificate is renewed every few months.
openssl s_client opens a TLS connection and shows you everything that happens in it. -servername sends the SNI, and </dev/null closes the connection as soon as the handshake is done:
2. The certificate chain
openssl s_client -connect example.com:443 -servername example.com </dev/nullWhat you will see:
depth=4 C = GB, ST = Greater Manchester, L = Salford, O = Comodo CA Limited, CN = AAA Certificate Servicesverify return:1…depth=0 CN = example.comverify return:1CONNECTED(00000005)---Certificate chain0 s:/CN=example.com i:/C=US/O=SSL Corporation/CN=Cloudflare TLS Issuing ECC CA 31 s:/C=US/O=SSL Corporation/CN=Cloudflare TLS Issuing ECC CA 3 i:/C=US/O=SSL Corporation/CN=SSL.com TLS Transit ECC CA R22 s:/C=US/O=SSL Corporation/CN=SSL.com TLS Transit ECC CA R2 i:/C=US/O=SSL Corporation/CN=SSL.com TLS ECC Root CA 20223 s:/C=US/O=SSL Corporation/CN=SSL.com TLS ECC Root CA 2022 i:/C=GB/ST=Greater Manchester/L=Salford/O=Comodo CA Limited/CN=AAA Certificate Services---…Server Temp Key: ECDH, X25519, 253 bits… Protocol : TLSv1.3 Cipher : AEAD-CHACHA20-POLY1305-SHA256… Verify return code: 0 (ok)Certificate chain: the chain the server sends. In each certificate,s:is who it belongs to andi:is who signed it, and eachi:is thes:of the next one. A Cloudflare CA signs example.com; an SSL.com intermediate signs that CA; and SSL.com’s root signs the intermediate. That root dates from 2022, so an old Comodo root (AAA Certificate Services) also signs it, which lets systems that don’t have the new root yet accept it. The server doesn’t send that last one: it’s already on your computer. That’s why thedepth=lines at the top, the same path checked from the root down, go up to 4.Server Temp Key: ECDH, X25519: the key exchange part. ECDH is Diffie-Hellman with elliptic curves, a kind of math that gives the same security with shorter keys, and X25519 is the specific curve. It’s temporary: it’s made up for this connection and thrown away at the end. That way, even if the server’s private key leaks one day, it can’t be used to decrypt conversations recorded earlier.Verify return code: 0 (ok): the chain is valid.
This output comes from the openssl that ships with macOS (LibreSSL). On Linux, or with OpenSSL from Homebrew, the format changes a little, and you might see X25519MLKEM768: a key exchange designed to withstand quantum computers. We’ve trimmed some parts (…), including the certificate in Base64.
Finally, what happens when something goes wrong. The badssl.com site has test pages with certificates that are broken on purpose:
3. Broken certificates
curl https://expired.badssl.com/curl https://wrong.host.badssl.com/curl https://self-signed.badssl.com/What you will see:
curl: (60) SSL certificate problem: certificate has expiredMore details here: https://curl.se/docs/sslcerts.htmlcurl: (60) SSL: no alternative certificate subject name matches target host name 'wrong.host.badssl.com'More details here: https://curl.se/docs/sslcerts.htmlcurl: (60) SSL certificate problem: self signed certificateMore details here: https://curl.se/docs/sslcerts.htmlThese are the three failures the browser checks for:
- Expired: today’s date is outside the certificate’s dates.
- Wrong name: the certificate is valid, but for another domain.
- Self-signed: its own owner signed it, not a trusted authority. Anyone can make one for any domain, and that’s why it doesn’t count.
In all three cases, curl refuses to continue and never sends the HTTP request. Open them in your browser too.
You have already seen it
Section titled “You have already seen it”- “Not secure” to the left of the URL on an
http://website: there’s no TLS, so everything travels like a postcard. - Chrome’s “Your connection is not private” warning shows a code underneath:
NET::ERR_CERT_DATE_INVALID,NET::ERR_CERT_COMMON_NAME_INVALIDorNET::ERR_CERT_AUTHORITY_INVALID. These are the three cases from exercise 3: expired, wrong name and signed by someone the browser doesn’t trust. - If your computer’s date is wrong, you’ll see
ERR_CERT_DATE_INVALIDon every website: as far as the browser is concerned, every certificate is out of date. - Hotel Wi-Fi can give you certificate errors until you accept its terms: it answers in place of the site you asked for, with a certificate that isn’t that site’s, and TLS catches it.
And if you code:
- Mixed content: an HTTPS page that loads a script over
http://. The browser blocks it, because that script would travel like a postcard and someone could change it. crypto.subtleisundefined. If you open your development server from your phone withhttp://192.168.1.133:5173, the Web Crypto API disappears, along with others likecrypto.randomUUIDor clipboard access: the browser only offers them in secure contexts, over HTTPS or onlocalhost. It’s the warning you’d see in the playground.
Common mistakes
Section titled “Common mistakes”- “The padlock means the website can be trusted.” It only means the connection is private and the server owns that domain. A phishing website with a domain that looks like your bank’s has a padlock too.
- “With HTTPS, nobody knows which websites I visit.” The domain is usually visible in the SNI and in the DNS query, and the IP address is always visible. What stays hidden is everything after that: the path, the headers and the content.
- “Encrypting and signing are the same thing.” Encrypting hides a message: you encrypt with the recipient’s public key. Signing proves who wrote a message and that it hasn’t changed: you sign with your own private key. TLS uses signatures for identity and a key exchange to agree on the secret key.
- “HTTPS makes websites slow.” The TLS 1.3 handshake adds one round trip, and connections get reused (and TLS can resume an earlier session). Symmetric encryption is so fast you won’t notice it. And browsers only use HTTP/2 and HTTP/3, faster versions you’ll see in Phase 2, over HTTPS.
Summary
Section titled “Summary”- TLS provides confidentiality, integrity and authenticity. HTTPS is HTTP inside TLS.
- Symmetric encryption is fast, but it needs a shared key. Public-key cryptography solves that, and it also makes signatures possible.
- In the handshake, both ends agree on a secret key with a Diffie-Hellman exchange, and the server proves its identity with its certificate and a signature.
- A certificate binds a domain to a public key, is signed by a certificate authority and expires. The browser checks the chain, the name and the dates.
- HTTPS hides the path, the headers and the content, but not the domain or the IP address. And it doesn’t tell you whether the website is honest.
Did you get it?
Section titled “Did you get it?”If anyone can have example.com's public key, why can't someone pretend to be example.com by sending its certificate?Show answer
Because in the handshake the server doesn’t just send the certificate: it also signs the handshake with the private key that goes with that public key. Whoever copies the certificate doesn’t have the private key, so they can’t produce a signature that checks out with the certificate’s public key, and the browser cuts the connection. Copying an old signature doesn’t work either: every handshake is different.
You connect to an airport's Wi-Fi, and someone on that network is watching your traffic while you go to https://yourbank.com/account. What can they find out?Show answer
That you’re connecting to yourbank.com (from the SNI and the DNS query), its IP address, and how much data you send and receive, and when. They can’t see the /account path, your cookies, your password or the content of the page, and they can’t change any of it without it being noticed.
Why doesn't TLS encrypt all the data with the server's public key?Show answer
Because public-key cryptography is slow and only encrypts small messages: you saw it in the playground, which won’t encrypt more than about 190 bytes. TLS only uses it at the start, to agree on a symmetric key and to prove the server’s identity. The data is encrypted with that symmetric key, which is very fast.
Further reading
Section titled “Further reading”- What is TLS? (Cloudflare Learning): TLS, its versions and the handshake.
- Web Crypto API (MDN): the cryptography the playground uses, in case you code and want to use it in your own projects.
- RFC 8446: the TLS 1.3 specification. Section 2 summarizes the handshake.