Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
••
Sichere ProgrammierungHow Hindsight Turned Deployment #1017 Into the Fix for #1057(29.09.2026 um 06:25 Uhr)
••
Sichere ProgrammierungSystems foundations should start below the framework(29.09.2026 um 06:30 Uhr)
••
Sichere ProgrammierungHow a game should say no: designing refusals people can act on(29.09.2026 um 06:30 Uhr)
••
Sichere ProgrammierungTuring Sim: Making the USD Schemas Inspector Readable(29.09.2026 um 06:31 Uhr)
••••
Sichere ProgrammierungHow Hindsight Turned Deployment #1017 Into the Fix for #1057(29.09.2026 um 06:25 Uhr)
••
Sichere ProgrammierungSystems foundations should start below the framework(29.09.2026 um 06:30 Uhr)
••
Sichere ProgrammierungHow a game should say no: designing refusals people can act on(29.09.2026 um 06:30 Uhr)
••
Sichere ProgrammierungTuring Sim: Making the USD Schemas Inspector Readable(29.09.2026 um 06:31 Uhr)
••
Intelligence View
⚡ tsecurity.de Intelligence

TLS 1.3 on the Wire: What an Eavesdropper Can Still See Before Encryption Kicks In

Originally published at https://blog.pathvector.dev/protocol-lab-tls-09/ — part of the free Protocol Lab series. This post is part of Protocol Lab, a free, hands-on series for learning networking protocols by building and breaking them i…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Originally published at https://blog.pathvector.dev/protocol-lab-tls-09/ — part of the free Protocol Lab series.




This post is part of Protocol Lab, a free, hands-on series for learning networking protocols by building and breaking them in a container lab. All the lab material — topologies, configs, and scripts — lives in the repo: github.com/pathvector-studio/protocol-lab.



TCP gave us a reliable byte stream. TLS runs on top of it to add encryption and server authentication. This lab opens one TLS 1.3 connection and asks a precise question: what can an on-path observer see before encryption takes over?




Reading guide: rfc-notes/tls-handshake-certificates.md



Prerequisite: TCP Lab 07: One Connection, From SYN to FIN




Expected time: 55–70 minutes.






The Goal



You will:




  • run an openssl s_server with a self-signed certificate and ALPN,

  • connect with openssl s_client using SNI (-servername),

  • read the negotiated protocol, cipher, certificate, and ALPN,

  • capture the handshake and see that ClientHello (with SNI and the ALPN offer) is in the clear, while in TLS 1.3 the certificate is encrypted.



By the end, you should be able to fill in this table:

































Handshake item Visible on the wire (TLS 1.3)? How you saw it
SNI (server_name) yes, in ClientHello capture / tshark
ALPN offer yes, in ClientHello capture / tshark
Chosen cipher / version yes, in ServerHello capture
Server certificate no (encrypted) only via s_client endpoint





What You Will Learn




  • Where TLS sits: on top of TCP, below the application (HTTP).

  • What ClientHello and ServerHello carry, and which parts are cleartext.

  • What SNI is and why the server needs it before choosing a certificate.

  • What ALPN negotiates (e.g. h2 vs http/1.1).

  • Why, in TLS 1.3, the certificate is sent encrypted (unlike TLS 1.2).



This lab does not cover:




  • A real CA-signed certificate chain or trust-store validation.

  • Client certificates / mutual TLS.

  • Encrypted Client Hello (ECH), which also hides SNI.

  • The cryptographic details of key exchange.






Where to Read in the RFCs
















































RFC Section What to focus on
RFC 8446 2 The overall TLS 1.3 handshake (1-RTT)
RFC 8446 4.1.2 What's inside ClientHello
RFC 8446 4.1.3 What's inside ServerHello
RFC 8446 4.4.2 The Certificate message (encrypted in 1.3)
RFC 6066 3 Server Name Indication (SNI)
RFC 7301 3 Application-Layer Protocol Negotiation (ALPN)
RFC 5737 3 Confirming the names/addresses used here are documentation-only





The Big Picture



Same two-node setup as Labs 07/08: the server runs a TLS listener, and the client connects over TLS.




client (10.0.0.1) ------ eth1/eth1 ------ server (10.0.0.2:4433)
openssl s_server
cert CN=www.example.lab
ALPN: h2, http/1.1






The client connects with SNI=www.example.lab and an ALPN offer of h2,http/1.1, and captures the handshake on its own side.




sequenceDiagram
participant C as client
participant S as server

Note over C,S: TCP already established (Lab 07)
C->>S: ClientHello (SNI=www.example.lab, ALPN=[h2,http/1.1], ciphers, key share)
Note right of C: cleartext — visible on the wire
S->>C: ServerHello (chosen cipher, key share)
Note left of S: cleartext — visible on the wire
Note over C,S: keys derived; rest is encrypted
S-->>C: {EncryptedExtensions (ALPN=h2)}
S-->>C: {Certificate CN=www.example.lab} (encrypted in TLS 1.3)
S-->>C: {CertificateVerify, Finished}
C-->>S: {Finished}
Note over C,S: application data (HTTP) flows encrypted






Both nodes run nicolaka/netshoot (which bundles openssl, tcpdump, and tshark). No additional images are required.




Note: The names and addresses used here are local/documentation-only, so nothing in this lab touches the real internet.







What You Need



Recommended environment:




  • Linux / WSL2 / a Linux VM

  • Docker

  • containerlab

  • tcpdump / tshark



Images used:




  • nicolaka/netshoot:latest






Running the Lab



The quick path, which deploys, generates the certificate, starts s_server, captures the handshake, runs s_client, checks SNI/ALPN/certificate, and tears down for you:




./scripts/labctl.sh run tls-09






Or step through it manually:






1. Move into the working directory






cd protocol-lab/examples/tls-09









2. Deploy and create the certificate






sudo containerlab deploy -t tls-09.clab.yml
docker exec clab-tls-09-server sh -c \
"openssl req -x509 -newkey rsa:2048 -nodes \
-keyout /tmp/server.key -out /tmp/server.crt
\
-subj '/CN=www.example.lab' -days 30 -addext 'subjectAltName=DNS:www.example.lab'"







This is a self-signed certificate for a closed lab — no public CA involved.






3. Start the TLS listener on the server






docker exec -d clab-tls-09-server sh -c \
"openssl s_server -accept 4433 -cert /tmp/server.crt -key /tmp/server.key -alpn h2,http/1.1 -www -quiet"






-alpn h2,http/1.1 declares which application protocols the server can speak.






4. Set up the capture on the client



In a separate shell, start the capture (use -s0 so you get the whole handshake):




docker exec -it clab-tls-09-client tcpdump -i eth1 -s0 -n "tcp port 4433"









5. Connect over TLS






docker exec -it clab-tls-09-client sh -c \
"echo Q | openssl s_client -connect 10.0.0.2:4433 -servername www.example.lab -alpn h2,http/1.1 -tls1_3"






What to look for in the s_client output:




subject=CN = www.example.lab
issuer=CN = www.example.lab
...
ALPN protocol: h2
...
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Verify return code: 18 (self signed certificate)








  • subject=CN = www.example.lab: the certificate the server presented.


  • ALPN protocol: h2: client and server agreed on h2 (HTTP/2).


  • Protocol : TLSv1.3.


  • Verify return code: 18: verification is treated as failed because the certificate is self-signed (not from a public CA). In this lab, that's expected.






6. Read the cleartext parts out of the capture



If you have tshark, you can extract the SNI and the ALPN offer from inside the ClientHello:




docker exec clab-tls-09-client sh -c \
"tshark -r /tmp/tls-09.pcap -Y 'tls.handshake.type==1' \
-T fields -e tls.handshake.extensions_server_name -e tls.handshake.extensions_alpn_str"







Expected:




www.example.lab   h2,http/1.1






In other words, the SNI and the ALPN offer sit in the ClientHello in cleartext. The certificate, on the other hand, is sent after encryption begins in TLS 1.3, so its contents cannot be read from the capture (s_client can decrypt and display it because it is an endpoint of the connection).






Expected Output





  • s_client: CN = www.example.lab, ALPN protocol: h2, TLSv1.3.


  • tshark (if available): the ClientHello's server_name = www.example.lab, alpn = h2,http/1.1.

  • The capture: ClientHello / ServerHello are readable, but the Certificate is encrypted and is not.






Why It Works



TLS is the layer that adds "encryption" and "verifying the peer is genuine" on top of TCP. A TLS connection first runs a handshake to agree on the cipher suite, the keys, and the application protocol.





  • Why SNI is cleartext. A server may host multiple sites on a single IP. To choose which certificate to present, it needs to know "which site is this for?" before any encryption keys exist. That's why SNI rides in the ClientHello in cleartext. (Hiding it is what ECH does — outside this lab's scope.)


  • What ALPN decides. It negotiates the upper-layer protocol — HTTP/2 (h2) vs HTTP/1.1 — inside the handshake, in a single round trip. No extra negotiation round trips are needed.


  • Why TLS 1.3 encrypts the certificate. Right after ClientHello / ServerHello exchange key material (key shares), the keys are derived, and everything from then on (EncryptedExtensions, Certificate, Finished) is encrypted. In TLS 1.2 the certificate went out in cleartext; in 1.3 it's hidden. So an on-path observer can't see which certificate was served (though the SNI still hints at the site).



The key insight: be able to point at the exact boundary where encryption begins, right there in the capture. Everything up to ClientHello/ServerHello is cleartext; everything after is encrypted.






Common Pitfalls





  • Confusing the SNI with the certificate's CN. SNI is the client's cleartext statement of "this is the site I want." CN/SAN is the name in the certificate the server sends back.


  • Treating Verify return code: 18 as a bug. It's self-signed, so verification is expected to fail. With a public CA it would be 0.


  • The TLS 1.2 vs 1.3 difference. In 1.2 the certificate is visible in cleartext. This lab forces 1.3, so it's encrypted. Switch to -tls1_2 and you can confirm the certificate becomes readable in the capture.


  • Empty ALPN. Forget -alpn on the server side and no negotiation happens.


  • Capture size. Without -s0, packets can be truncated and you may lose parts of the handshake.


  • ECH. A mechanism to hide SNI exists, but it's not on by default. In this lab, the SNI is visible.






Cleanup






sudo containerlab destroy -t tls-09.clab.yml --cleanup






If you used labctl.sh run tls-09, the script runs destroy for you at the end.






Check Your Understanding




  1. What layer does TLS sit on top of, and what layer sits above it?

  2. Who sends the SNI, and why? Why is it cleartext?

  3. What does ALPN decide? What was chosen in this lab?

  4. In TLS 1.3, up to which message can you read from a capture? Can you read the certificate? Why or why not?

  5. What does Verify return code: 18 mean? What would it be with a public CA?

  6. How does the visibility of the certificate differ between TLS 1.2 and 1.3?






References








Verified Run Log (2026-07-05)



This lab has been confirmed reproducible on real hardware.



Environment:




  • Ubuntu 26.04 LTS (kernel 7.0.0-27-generic, x86_64)

  • Docker 29.1.3

  • containerlab 0.77.0

  • client / server: nicolaka/netshoot:latest (bundles openssl / tshark)



Running PATH="/tmp/pl-shim:$PATH" ./scripts/labctl.sh run tls-09 performed deploy → verify → destroy, and verification.json returned "status": "verified". No image or topology fixes were needed.






The handshake result as seen from openssl s_client






$ echo Q | openssl s_client -connect 10.0.0.2:4433 -servername www.example.lab \
-alpn h2,http/1.1 -tls1_3

Server certificate
subject=CN=www.example.lab
issuer=CN=www.example.lab
Verification error: self-signed certificate
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
ALPN protocol: h2






How to read it:





  • The certificate selected via SNI: subject=CN=www.example.lab. The server presented the certificate for exactly the name the client requested with -servername www.example.lab (SNI).


  • Self-signed: issuer equals subject, and Verification error: self-signed certificate. The lab CA isn't trusted, so verification failing is the correct outcome here (in production, a CA chain would make it pass).


  • TLS 1.3: Protocol: TLSv1.3, cipher TLS_AES_256_GCM_SHA384.


  • ALPN: ALPN protocol: h2. The client offered h2,http/1.1 and the server chose h2.






Confirming the ClientHello on the wire (tshark)



Extracting the SNI and ALPN from the ClientHello (tls.handshake.type==1) in the capture:




$ tshark -r tls-09.pcap -Y "tls.handshake.type==1" \
-T fields -e tls.handshake.extensions_server_name -e tls.handshake.extensions_alpn_str

www.example.lab h2,http/1.1






Even in TLS 1.3, the ClientHello is cleartext, so the SNI (the hostname being connected to) and the offered ALPN list (h2,http/1.1) are visible from the network. The ALPN the server chose (h2) travels inside the encrypted EncryptedExtensions, which is why you check it in the s_client output above instead.






Cleanup






containerlab destroy -t tls-09.clab.yml --cleanup









That's the TLS 1.3 handshake on the wire: SNI and the ALPN offer in the clear, keys derived right after ServerHello, and everything from the certificate onward hidden from anyone watching the path.



Explore the full Protocol Lab series here: github.com/pathvector-studio/protocol-lab. If these labs are useful to you, please ⭐ star the repo on GitHub — it genuinely helps others find the project.



Next up, we'll keep climbing the stack and look at what the application layer does with the encrypted channel TLS just handed it.

2. Cyber Threat Intelligence & Forensik

CTI Threat Relationship Graph3 Knoten / 2 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten TLS 1.3 on the Wire: What an Eavesdropper Can Still See Before Encryption Kicks In

Thematisch verwandte Begriffe: Wire, What, Eavesdropper, Still · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-102367 | mall4j through 4.0 contains an insufficient session expiration vulnerab…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag