Old-School Networking / 2026 ・ No.08

Old-School Networking

Part 8: Layers 5 and 6, and TLS — putting a lock on the submission

Published

The Wireshark window. The list shows the TCP handshake, packet 4 Client Hello (SNI=expenses.example), Server Hello and Application Data, ending with FIN and RST. Packet 4 is selected with Transport Layer Security expanded, and Server Name: expenses.example under Extension: server_name is selected; in the bytes pane the text expenses.example is highlighted
A submission sent over HTTPS. Open packet 4, the Client Hello, and the name of the server being contacted (SNI), expenses.example, is still readable, because it comes before encryption starts (Recorded on 25 October 2026 on a practice network the author built in the cloud and opened in Wireshark 4.2.2. The bar across the top of the window and the headings were added for the illustration.)

So far every submission has travelled in a form anyone along the way could read. This part is about TLS, which sits between TCP and the application and locks the submission up. It's the S in HTTPS.
We make a practice CA (the role that issues certificates), give the server a certificate, and switch to HTTPS: what disappears from view, what's still visible, and how much slower is it? We also cause the four verification failures you're most likely to meet, on purpose.

1

Presentation and session

AraiStop 8 on the route map says “layers 5 and 6”. Why do they share a part?

FuruiOn the real internet, layers 5 and 6 barely exist on their own. They're folded into TLS and applications. So we deal with them together.

The 12-part route map (you are here: part 8)

1 Big picture 2 Physical 3 Data link 4 IP addresses 5 Routers 6 TCP 7 UDP, sockets 8 TLS 9 DNS 10 HTTP 11 Dev networks 12 Troubleshoot You are here Overview Layer 1 Layer 2 Layer 3 Layer 4 Layers 5-6 Layer 7 Practice
  • Layers 5 and 6 — presentation (character encoding, JSON, compression, encryption) and session
  • Switching to HTTPS — what disappears and how much slower it is (measured)
  • Keys and certificates — sharing a key, certificate chains, four ways verification fails (measured)
  • Still visible — the name (SNI) and ECH, which hides it; certificate lifetimes getting shorter

Layers 5 and 6 sit between the application and TCP

7 7 Application HTTP, the expenses API 6 6 Presentation UTF-8, JSON, gzip, encryption 5 5 Session start, end, resume 4 4 Transport TCP, UDP TLS spans both On the real internet, layers 5 and 6 aren't separate layers; they're folded into TLS, applications and libraries

Layer 6 is presentation. The same word is unreadable unless both sides lay it out by the same rules. Today's rules: UTF-8 for text, JSON for data, gzip for compression.

# 交通費 (“travel”) is 9 bytes in UTF-8 (also visible in the bytes pane of part 7's cover)
    交通費 → e4 ba a4 e9 80 9a e8 b2 bb
# gzip on the 2 MB CSV (the same line repeated, so it shrinks absurdly)
    2,097,152 bytes → 6,179 bytes

Layer 5 is session: starting and ending a conversation and resuming it after a break. In practice it's spread across TCP connections, HTTP cookies, TLS session resumption and so on. Encryption is a form of presentation too, so TLS does work that spans both layers.

2

A submission in plain view

At the end of part 7 we noticed the submission's JSON was readable in Wireshark. Let's search the capture files for the submission's text.

# Searching the capture files for the submission's text
    HTTP   '"amount":1280'       found
    HTTP   'POST /api/expenses'  found
    HTTPS  '"amount":1280'       not found
    HTTPS  'POST /api/expenses'  not found
    HTTPS  'expenses.example'    found  ← Client Hello SNI
Two Wireshark detail and byte panes stacked. Top: the HTTP submission, where the right side of the bytes pane reads POST /api/expenses, Host, Content-Type, and the JSON date and amount 1280. Bottom: the HTTPS submission, shown only as Transport Layer Security, with meaningless symbols on the right of the bytes pane
The same submission over HTTP and over HTTPS. With HTTPS, neither the URL nor the JSON can be read along the way (Recorded on 25 October 2026 on a practice network the author built in the cloud and opened in Wireshark 4.2.2. The bar across the top of the window and the headings were added for the illustration.)

The HTTP capture contains the URL and the amount as is. Past every router along the way, anyone on the same Wi-Fi, every machine at the provider, it travelled readable. And what can be read can be altered and passed on. In the HTTPS capture, neither the URL nor the amount could be found, with one exception: the name expenses.example (section 7).

TLS's three promises

Can't be read encryption to anyone en route it's meaningless bytes Changes noticed integrity change a single bit and it's rejected It's really them certificate check name, dates, signature, then talk All three are needed. Encryption is pointless if the other end is a fake TLS protects only the wire, not the PC or server at either end
3

Switching to HTTPS

We gave the server a certificate for the name expenses.example and ran the expenses API over Node.js https on port 3443 (.example is a name reserved for documentation). The certificate was issued by a practice CA the author created, “Kiji Practice Root CA”, and the PC's curl was told about that CA with --cacert.

ConnectedTLS doneFirst byte of replyRound trips
HTTP0.041 s—0.083 s2
HTTPS (TLS 1.3)0.041 s0.085 s0.127 s3
HTTPS (TLS 1.2)0.041 s0.126 s0.168 s4

With a 0.041 s round trip, HTTP took 2 round trips to the reply. HTTPS with TLS 1.3 added one round trip for the TLS greeting, making 3, and the older TLS 1.2 added two, making 4. The cryptography itself took only a few milliseconds. The slowness is round trips, not computation.

# TLS 1.3 (20 ms each way): after TCP's greeting, TLS's takes one round trip; the request (no. 9) is encrypted
   1  0.000  pc  → srv  TCP      [SYN]
   2  0.041  srv → pc   TCP      [SYN, ACK]
   3  0.041  pc  → srv  TCP      [ACK]
   4  0.043  pc  → srv  TLSv1    Client Hello (SNI=expenses.example)
   5  0.083  srv → pc   TCP      [ACK]
   6  0.084  srv → pc   TLSv1.3  Server Hello, Change Cipher Spec, Application Data, Application Data, Application Data, Application Data
   7  0.084  pc  → srv  TCP      [ACK]
   8  0.085  pc  → srv  TLSv1.3  Change Cipher Spec, Application Data
   9  0.086  pc  → srv  TLSv1.3  Application Data
  10  0.126  srv → pc   TLSv1.3  Application Data, Application Data
  11  0.130  srv → pc   TLSv1.3  Application Data
# TLS 1.2: two round trips of TLS greeting before the request (no. 10)
   1  0.000  pc  → srv  TCP      [SYN]
   2  0.041  srv → pc   TCP      [SYN, ACK]
   3  0.041  pc  → srv  TCP      [ACK]
   4  0.042  pc  → srv  TLSv1    Client Hello (SNI=expenses.example)
   5  0.083  srv → pc   TCP      [ACK]
   6  0.083  srv → pc   TLSv1.2  Server Hello, Certificate, Server Key Exchange, Server Hello Done
   7  0.083  pc  → srv  TCP      [ACK]
   8  0.085  pc  → srv  TLSv1.2  Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
   9  0.128  srv → pc   TLSv1.2  Change Cipher Spec, Encrypted Handshake Message
  10  0.128  pc  → srv  TLSv1.2  Application Data
  11  0.170  srv → pc   TLSv1.2  Application Data

The TLS 1.3 handshake (measured times)

PC Server SYN 0 SYN+ACK ACK, Client Hello 43 ms Server Hello … Finished, POST 86 ms 201 TCP greeting 1 round trip TLS greeting 1 RTT (1.2 needs 2) Request, reply 1 round trip Everything after Server Hello is encrypted, certificate included
Two Wireshark packet lists stacked. Top, TLS 1.2: Client Hello; Server Hello, Certificate, Server Key Exchange, Server Hello Done; Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message; Change Cipher Spec, Encrypted Handshake Message; then Application Data as packet 10 at 0.128 s. Bottom, TLS 1.3: Client Hello; Server Hello, Change Cipher Spec, Application Data; then Application Data as packet 9 at 0.086 s
TLS 1.2 and 1.3 handshakes compared. 1.3 saves a round trip, so the request starts 0.042 s sooner (Recorded on 25 October 2026 on a practice network the author built in the cloud and opened in Wireshark 4.2.2. The bar across the top of the window and the headings were added for the illustration.)

In TLS 1.3 the PC sends its key material up front in the first Client Hello, so encryption is ready as soon as the server's reply (Server Hello) arrives. Everything after Server Hello, the certificate included, is already encrypted. TLS 1.2 needed another round trip to exchange that material. TLS 1.0 and 1.1 were formally deprecated in 2021.

POINT

More round trips make part 6's “reuse the connection” matter even more. Over HTTPS, every fresh connection costs two round trips for TCP and TLS. Keep-alive and connection pools are a must (part 10).

4

Agreeing on a key

AraiHow do you hand the other side the encryption key? If you send it down the wire, it gets read on the way.

FuruiYou never send the key. Each side computes the same key on its own.

Don't send the key; compute the same one on both sides

PC secret a never sent public A same key Server secret b never sent public B same key swapped in Client/Server Hello On the wire: only A and B not enough to compute the key a + B b + A Both sides end up with the same key X25519 here; fresh keys per connection protect past sessions

The PC and the server each make a secret number and exchange only a “public” number computed from it, in the Client Hello and Server Hello. Combining your own secret with the other side's public number gives both sides the same key. Seeing the public numbers along the way isn't enough to compute it. The secrets are made fresh for each connection and thrown away, so even if the server's long-term key leaks later, old recordings can't be unlocked (forward secrecy).

# openssl s_client shows what was agreed
pc$ openssl s_client -connect 203.0.113.20:3443 -servername expenses.example -CAfile ca.pem -brief
    Protocol version: TLSv1.3
    Ciphersuite: TLS_AES_256_GCM_SHA384
    Peer certificate: CN = expenses.example
    Hash used: SHA256
    Signature type: ECDSA
    Verification: OK
    Server Temp Key: X25519, 253 bits
# The chain (0 is the server; i: is who signed it)
    0 s:CN = expenses.example
    i:CN = Kiji Practice Root CA
    Verify return code: 0 (ok)
# The server's certificate
    subject=CN = expenses.example
    issuer=CN = Kiji Practice Root CA
    notBefore=Oct 24 23:40:01 2026 GMT
    notAfter=Jan 22 23:40:01 2027 GMT
    DNS:expenses.example

openssl s_client shows this connection used TLS 1.3, X25519 to share the key and TLS_AES_256_GCM_SHA384 for the contents. AES-256-GCM encrypts and adds a “not tampered with” check at the same time, covering two of the three promises. The third, whether the other side is genuine, is the certificate's job.

5

Is it really them? Certificates

However safely you share a key, if the server is a fake you're just talking safely to a fake. So the server shows a certificate saying “I am expenses.example”. It holds a name, validity dates and a public key, and is signed by a trusted CA.

Do the signatures lead back to a trusted root?

Root CA trusted by OS and browser Intermediate CA (skipped in this practice) signs Server certificate expenses.example signs Trusted CA list built into OS and browser What the PC checks ✓ name (expenses.example) ✓ dates (to 2027-01-22) ✓ signatures reach a root The practice CA isn't in the PC's list, so curl was told with --cacert Real sites get certificates from CAs such as Let's Encrypt

A real site's certificate is signed via an intermediate CA by a “root CA” that the OS or browser trusts out of the box. The PC checks three things: the name matches, it's within its dates, and the signatures lead to a root. This part's practice CA isn't in the PC's list, so we told curl to trust it.

6

Four ways verification fails

Here are the errors every developer meets sooner or later, caused on purpose. The wrong-name, expired and self-signed certificates were all made for the exercise.

# Connect without telling curl about the practice CA
    curl: (60) SSL certificate problem: unable to get local issuer certificate
# Connect by address (IP); the certificate's name is expenses.example
    curl: (60) SSL: no alternative certificate subject name matches target host name '203.0.113.20'
# An expired certificate (valid until 2026-09-29)
    curl: (60) SSL certificate problem: certificate has expired
# A certificate signed by itself
    curl: (60) SSL certificate problem: self-signed certificate
# Practice CA given, connecting by name → verification succeeds
    HTTP 404 (GET /api/expenses)
ErrorWhich check failedThe right fix
unable to get local issuer certificatethe signatures don't lead to a rootconfigure the intermediate certificate on the server too; for an internal CA, add it to the trusted list
no alternative certificate subject name matchesname mismatchconnect by the name on the certificate; put the names you need into it
certificate has expiredexpiredrenew, and automate renewal (section 8)
self-signed certificateno trusted signatureget it issued by a CA; for development, run a local development CA
POINT

Don't make the error go away by switching verification off (curl's -k, Node.js's NODE_TLS_REJECT_UNAUTHORIZED=0, Python requests' verify=False and the like). The traffic is still encrypted, but you no longer know who's on the other end, and one of the three promises is gone. Settings added “just for now” during development and left in production have caused accidents for as long as TLS has existed.

7

What's still visible

As the cover photo shows, the Client Hello's SNI carries the name of the server being contacted, expenses.example, in the clear. When one server hosts sites under many names, it has to know which certificate to present before encryption starts. Beyond that, the server's IP address, how much is sent and when are all visible along the way even with TLS.

To hide the name, ECH (Encrypted Client Hello), which encrypts the Client Hello itself, became a standard as RFC 9849 in March 2026. The name also leaks through DNS lookups (part 9), though, so both need covering before it's truly hidden.

8

Certificate lifetimes and automation

Maximum validity of public website certificates (CA/Browser Forum)

to 2026-03-14 398 days from 2026-03-15 200 days from 2027-03-15 100 days from 2029-03-15 47 days Shorter lives limit the damage from stolen keys or wrong certificates Manual renewal stops being practical; automatic renewal (ACME) is assumed

The CA/Browser Forum, the industry body of browsers and CAs, has decided to shorten public certificate lifetimes in stages: at most 200 days from 15 March 2026, and 47 days from 15 March 2029. Renewing by hand several times a year isn't realistic, so issuing and renewing automatically with the ACME protocol becomes the norm. Let's Encrypt, the free CA, hands out its certificates over ACME.

For developers, the job is to prevent “the site went down because the certificate expired” with monitoring and automatic renewal. You can check the dates with openssl x509 -noout -dates or through the browser's padlock.

9

Checking your own PC

To seeHow
TLS version and cipheropenssl s_client -connect example.com:443 -servername example.com -brief
Handshake steps and certificatecurl -v https://example.com/ -o /dev/null
Handshake timecurl -o /dev/null -s -w '%{time_connect} %{time_appconnect}\n' URL
Certificate datesopenssl x509 -in cert.pem -noout -dates
Trusted CAsMac: Keychain Access; Windows: certmgr.msc; Linux: /etc/ssl/certs

Click the icon to the left of the browser's address bar to see a site's certificate. Have a look at the issuing CA, the name and the dates.

§ — On one page, and next time

  1. Layer 6 is presentation (UTF-8, JSON, gzip, encryption); layer 5 is session. In practice both are folded into TLS and applications.
  2. The HTTP capture showed the URL and the amount; in the HTTPS capture they weren't there.
  3. TLS makes three promises: can't be read, changes are noticed, it's really them.
  4. HTTPS with TLS 1.3 costs one more round trip than HTTP; TLS 1.2 costs two. Slowness comes from round trips, not computation.
  5. The key is never sent: public numbers are swapped and each side computes it (X25519), fresh for every connection.
  6. Certificates are checked for name, dates and the signature chain. If a check fails, never switch checking off.
  7. The SNI name, IP, volume and timing remain visible; ECH (RFC 9849) hides the name. Certificate lifetimes fall to 47 days in 2029.

AraiCome to think of it, curl always had --resolve saying “expenses.example is 203.0.113.20”. Isn't that cheating?

FuruiIt is. There's a real system for looking up an address from a name. Next time: DNS, the internet's phone book.

References

The recordings were made on 25 October 2026 on a practice network the author built with network namespaces on Linux (Ubuntu 24.04, kernel 6.18) in the cloud, with part 6's mischief wire (20 ms each way) between the PC and the server. The certificates were issued by a practice CA the author made with OpenSSL 3.0.13 (the expired one was created with Python's cryptography library, setting its dates explicitly); the server is Node.js 22 (OpenSSL 3.5) and the client curl 8.5.0. Every number in the text is a real value read from those recordings and the commands' output. The certificate lifetime rules are taken from DigiCert's and DNSimple's announcements of CA/Browser Forum ballot SC-081. The characters are fictional.

Old-School Networking, part 8 — Layers 5 and 6, and TLS / 2026.10

← Back to all posts