awesome-everything RU
↑ Back to the climb

Networking & Protocols

TLS 1.3: trace and config reading

Crux Read real openssl s_client output, an Nginx ticket-key config, an Early-Data handler, and a key_share trace, then pick the diagnosis and highest-leverage fix.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min

TLS problems are diagnosed in handshake traces, server configs, and request headers — not in textbook diagrams. Read each artifact, predict the behaviour, and choose the fix a senior engineer would make first.

Goal

Practise the loop you run in every TLS incident: read the openssl output or config, locate which handshake invariant is violated, and reach for the highest-leverage fix.

Snippet 1 — openssl s_client chain verification

% openssl s_client -connect api.example.com:443 -tls1_3
depth=0 CN = api.example.com
verify error:num=20:unable to get local issuer certificate
verify error:num=21:unable to verify the first certificate
---
Certificate chain
 0 s:CN = api.example.com
   i:CN = R3 Issuing CA
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Verify return code: 21 (unable to verify the first certificate)
Quiz

The handshake completes and a cipher is negotiated, yet verify return code is 21. What is misconfigured?

Snippet 2 — Nginx session-ticket key config

server {
    listen 443 ssl;
    ssl_protocols TLSv1.3;
    ssl_session_ticket_key /etc/nginx/ticket.key;   # generated once at install
    ssl_early_data on;
    # ...
}
Quiz

This config has been running unchanged for a year. What is the most serious security defect, given ssl_early_data is on?

Snippet 3 — an Early-Data request handler

app.post("/transfer", (req, res) => {
  // money movement
  if (req.headers["early-data"] === "1") {
    // request arrived in TLS 0-RTT early data
  }
  doTransfer(req.body);
  res.send("ok");
});
Quiz

The Early-Data header is read but the handler still calls doTransfer regardless. What goes wrong under a replay, and what is the correct fix?

Snippet 4 — a client key_share trace

ClientHello key_share: x25519 (0x001d), X25519MLKEM768 (0x11ec)
ServerHello: HelloRetryRequest, selected_group = secp256r1 (0x0017)
Quiz

The client offered x25519 and the hybrid X25519MLKEM768, yet the server sent HelloRetryRequest asking for secp256r1. What happened and what is the cost?

Recap

Every TLS incident is read in artifacts: an openssl verify code 20/21 means an incomplete chain — send the intermediates; a static disk-stored ssl_session_ticket_key destroys resumption forward secrecy — rotate STEKs hourly in memory; an Early-Data handler that mutates without returning 425 Too Early is replayable — gate mutating routes on the Early-Data header; and a HelloRetryRequest naming a different group means your offered key_shares missed — offer x25519 plus P-256 up front to avoid the extra RTT. Read the artifact, find the violated invariant, fix the cause.

Continue the climb ↑TLS 1.3: build and break a hardened endpoint
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.