Reading a TLS handshake in a packet capture
The first thing to learn about TLS troubleshooting is that almost every interesting failure looks identical on the wire: a ClientHello goes out, something comes back, and the client gives up. The difference is in which bytes come back.
A useful habit is to dump the record header only:
tcpdump -i any -n -s 0 -X 'tcp port 443 and tcp[((tcp[12]&0xf0)>>2):1] = 0x16'
Record type 0x16 is a handshake, 0x17 is application data and
0x15 is an alert. If you see the handshake record followed immediately by alert
level fatal, the server rejected something in the hello — typically SNI, the
ALPN list, or a key share the server did not like. If you see application data before the
handshake completes, something in the middle is not what you think it is.
Two details that cost me the most time: TLS 1.3 encrypts almost the entire handshake after
ClientHello, so a ServerHello with a suspiciously short certificate payload is
usually a bad case of "you are talking to the wrong endpoint"; and a ClientHello split across
two TCP segments looks exactly like two separate records in a naive dissector.