Networks and the web
TCP/IP and Ports: How Services Listen on Your Machine
A port is a numbered door on your machine. Learn how TCP and UDP use ports, then start, find and test a local server on 127.0.0.1.
TLS 1.3 gives HTTPS confidentiality, integrity and server authentication. Learn the handshake, certificate chains and what the padlock does not prove.
TLS (Transport Layer Security) is a protocol that wraps a network connection in encryption. HTTPS is ordinary HTTP sent through a TLS connection. When your browser shows a padlock, it has done three things. It encrypted the data. It checked that nobody changed the data in transit. And it checked that the server proved it holds a certificate trusted for the name you typed.
The third point is the one people misread. HTTPS tells you which server you are talking to. It says nothing about whether that server is trustworthy, honest or well run.
In How HTTP works, requests and responses are text messages, and HTTP does nothing to hide them. Every device between you and the server can read them: your home router, the access point in a café, your internet provider and the networks in between.
A passive observer can read a login form sent over plain HTTP. An active attacker on the path can do more. It can change a page before it reaches you, insert a script, or replace a download with a modified file. TLS is designed to stop both threats. It also gives the client a way to check who is answering, which plain HTTP never does.
The current version is TLS 1.3, defined in RFC 8446. TLS 1.0 and 1.1 are deprecated, as RFC 8996 explains, and TLS 1.2 is still widely deployed. Version 1.3 removed many older options, so there are fewer ways to configure the handshake badly.
TLS 1.3 gives you three properties.
Application data is encrypted with session keys that only the two endpoints hold. An observer sees ciphertext. The size and timing of the traffic stay visible, but the content does not.
A full TLS 1.3 handshake uses an ephemeral key exchange. Both sides create temporary key values for the session and discard them afterward. This gives forward secrecy: if the server's certificate private key leaks years later, recorded old sessions should still be unreadable. A leaked key still lets an attacker impersonate the server from that point on, so forward secrecy protects the past, not the future.
Each record carries an authentication tag from an AEAD cipher, such as AES-GCM or ChaCha20-Poly1305. TLS 1.3 allows only this kind of cipher. If an attacker flips a bit in transit, the tag check fails and the record is rejected.
The server proves that it holds the private key matching its certificate. The certificate binds that public key to a name such as example.com. The client checks the certificate and the chain of trust behind it, then checks the name. Most of the rest of this article is about that part.
The handshake agrees on keys and proves identity before any HTTP data moves. In TLS 1.3 the usual handshake takes one round trip. The steps below follow RFC 8446 at a high level.
Your client sends a ClientHello. It lists the TLS versions and cipher suites it supports, and it includes a key share, the client's temporary public value for the key exchange. It also carries the server name indication (SNI), the host name you asked for, in plain text. Servers that host many sites need that name to pick the right certificate.
The server selects a version and cipher suite and sends its own key share. Each side combines its private value with the other side's public value and derives the same shared secret. An observer who saw both public values cannot compute that secret. From here on, the handshake is encrypted.
The server sends its certificate. In TLS 1.2 the certificate was visible on the wire. In TLS 1.3 it travels inside the encrypted part of the handshake.
The server then sends a CertificateVerify message, a signature over the handshake transcript made with the certificate's private key. This proves the server holds the key during this handshake. A copied certificate alone is useless to an attacker. A Finished message, a MAC over the transcript, closes the server's part.
Your client checks the certificate chain, the validity dates, the name in the certificate against the host you requested, and the CertificateVerify signature. If every check passes, the client sends its own Finished message, and application data can flow.
If a check fails, the client stops. A browser shows a certificate warning, and curl exits with an error. Those messages are the most useful part of TLS for a beginner, because they name the check that failed.
A certificate is an X.509 structure, and RFC 5280 defines the profile used on the internet. The fields that matter most here are these.
| Field | What it says |
|---|---|
| Subject | The entity the certificate names. For web certificates it often repeats the host name. |
| Subject Alternative Name (SAN) | The names the certificate covers, such as example.com or *.example.com. Clients match the requested host against this list. |
| Issuer | The certificate authority (CA) that signed this certificate. |
| Validity | The notBefore and notAfter dates. Outside this window the certificate is not valid. |
| Basic Constraints | Whether this certificate may sign other certificates. CA certificates are marked this way. |
Modern clients ignore the Common Name (CN) in the subject for host-name checks and use the SAN list instead. A reader who looks only at the CN can misjudge a certificate.
A server rarely presents a certificate that the client can verify directly. Usually the leaf certificate, which covers the host name, is signed by an intermediate CA, and the intermediate is signed by a root CA. The client trusts a set of roots that comes with the operating system or the browser.
The client builds a path from the leaf to a trusted root. At each link it verifies the signature, checks the validity dates, and confirms that the issuer is allowed to sign certificates. Then it checks the host name. Both checks must pass.
Any trusted root can, in principle, issue a certificate for any name. Trust therefore depends on the practices of the authorities in the store. That is why vendors remove authorities that misissue certificates.
A certificate can be revoked before it expires, for example after its key is compromised. Clients can check revocation through certificate revocation lists (CRLs) or OCSP, but these checks behave unevenly. A clean connection does not prove that a certificate was never revoked.
TLS authenticates the server's identity. It does not evaluate the server's behavior. A phishing site can obtain a valid certificate for a look-alike domain it controls. The padlock then shows that the connection reaches the holder of that domain's key, not that the domain belongs to your bank. Read the host name in the address bar before you trust the page. A correctly certified server can still be hacked or badly run.
TLS hides content, not every fact about the connection. Anyone on the path can still see the IP addresses at each end, the port, the approximate size and timing of traffic, and the server name in the ClientHello, because SNI is sent in plain text. Encrypted Client Hello is an IETF effort to hide SNI, but check how widely it is deployed before you assume a site uses it. DNS lookups are a separate protocol and reveal the names you resolve unless you use encrypted DNS.
TLS protects data while it moves between two endpoints. It does not protect the endpoints. Malware on your computer can read decrypted data, and a browser extension can read every page you open. A company can also install its own trusted root on your machine and decrypt your HTTPS traffic through an inspection proxy. The client then works exactly as configured, and the trust decision belongs to whoever controls the root store.
example.com is one of the names IANA reserves for documentation and examples. Every command below connects only to example.com. The lab changes nothing on the server and needs no account. You need a terminal with curl and openssl. The openssl commands were run with OpenSSL 3.2.4.
Your output will differ from the output shown here. IP addresses change, certificates get renewed, and dates move forward.
curl -vI https://example.comThe -v flag prints connection details, and -I sends a HEAD request, which asks for headers only. On the machine used for this article (Windows 11 with Git Bash, curl 8.12.1, run on November 8, 2026), the relevant lines looked like this:
* Host example.com:443 was resolved.
* IPv4: 172.66.147.243, 104.20.23.154
* Connected to example.com (172.66.147.243) port 443
* using HTTP/1.x
> HEAD / HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OKThis curl build uses Schannel, the Windows TLS library, and its verbose output differs from curl built with OpenSSL. Here curl did not print the TLS version, cipher or certificate lines this lab asks for. On an OpenSSL-based curl, look for the line naming the TLS version and cipher, and the certificate block with subject, issuer and expiry date. The next steps get the same facts from openssl.
The 200 OK means the server answered inside the TLS connection. The headers travel encrypted, and curl decrypts them locally.
openssl s_client -connect example.com:443 -servername example.com -brief </dev/nullOutput:
Connecting to 172.66.147.243
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=example.com
Hash used: SHA256
Signature type: ECDSA
Verification: OK
Server Temp Key: X25519, 253 bits
DONERead it line by line:
The -servername flag sets SNI. Without it, a server hosting several sites may return a default certificate that does not match the name you wanted. The </dev/null redirect closes standard input so the command exits.
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -datesOutput:
subject=CN=example.com
issuer=C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
notBefore=Sep 26 22:49:11 2026 GMT
notAfter=Dec 25 22:56:35 2026 GMTThe subject holds only a CN. The issuer is an intermediate CA, not a root. The validity window was open on the day of the lab and closes on December 25, 2026. Compare notAfter with the date on your own system, because an expired certificate fails even when its chain is sound.
The subject does not list the covered names, so ask for the SAN list:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -ext subjectAltNameOutput:
X509v3 Subject Alternative Name:
DNS:example.com, DNS:*.example.comThe wildcard covers names such as www.example.com. The client compares this list with the host in your URL.
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -E '^ *[0-9] s:|^ *i:'Output:
0 s:CN=example.com
i:C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
1 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 R2
2 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 2022
3 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 ServicesEach s: line is a subject and each i: line is its issuer. Entry 0 is the leaf, and each entry is issued by the one after it. Certificates can be cross-signed, so a chain may reach a root by more than one path. The client needs one valid path that ends at a root in its own store.
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | grep 'Verify return code'Output:
Verify return code: 0 (ok)Zero means this openssl build's trust store accepted the chain. Other values name a specific failure, such as an expired certificate.
openssl s_client -connect example.com:443 -servername example.com -verify_hostname example.org -brief </dev/nullOutput, trimmed:
depth=0 CN=example.com
verify error:num=62:hostname mismatch
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=example.com
Verification error: hostname mismatchThe command still connects only to example.com. The -verify_hostname flag asks openssl to check the certificate against example.org, which the certificate does not cover. A browser shows the same kind of failure. This check is what stops a server with a valid certificate for one domain from passing as another.
The connection negotiated TLS 1.3, and the client accepted a chain for example.com while rejecting the same certificate for example.org. Neither result says whether the company behind example.com is trustworthy. The lab shows that your client reached the holder of the key for example.com, and nothing more.
-k or --insecure to curl to make an error disappear. That turns off the checks you just read. Use it only against a throwaway test server, never with real credentials.verify=False in a Python HTTP client. The data is still encrypted, but to whoever answered.Read the overview and handshake sections of RFC 8446, then skim RFC 5280 for the certificate fields. Read the Mozilla server-side TLS guide and run a configuration check against a server you operate.
The next article in this series covers public and private keys, the math behind the certificate. If the name lookup step is new, read What is DNS? first, because its result decides which address the handshake reaches.
Networks and the web
A port is a numbered door on your machine. Learn how TCP and UDP use ports, then start, find and test a local server on 127.0.0.1.
Networks and the web
Read a real HTTP exchange line by line: methods, URLs, headers, status code classes and cookies, tested with curl against a local server.
Networks and the web
How DNS turns names into addresses: resolvers, authoritative servers, TTL caching, the A, AAAA, CNAME, MX and TXT records, and a safe lookup.