Why does Wireshark show in the overview Protocol TLSv1.3 but in the details Version TLS 1.2?
Wireshark reports TLS 1.3 in the protocol column due to Server Hello containing a Supported Versions extension with TLS 1.3.
Recall that TLS sessions begin with a handshake to negotiate parameters such as the protocol version and ciphers. The client sends a Client Hello handshake message in a TLS record containing:
- TLS Record - Version: minimum supported TLS version (in TLS 1.2 and before). In TLS 1.3, this field is not really used and MUST be 0x0303 ("TLS 1.2") or 0x301 ("TLS 1.0") for compatibility purposes. Reference: RFC 8446 (page 79)
- Client Hello - Version: maximum supported TLS version (in TLS 1.2 and before). In TLS 1.3, this field is not used but MUST be set to 0x0303 ("TLS 1.2"). Reference: RFC 8446 (4.1.2. Client Hello)
- Client Hello - Supported Versions Extension: list of supported versions. This is the only value used by TLS 1.3 implementations (which may agree TLS 1.3, 1.2 or other versions). Reference: RFC 8446 (4.2.1. Supported Versions)
The server sends a Server Hello handshake message with:
- Server Hello - Version: negotiated version (for TLS 1.2 and before). If TLS 1.3 is negotiated, it MUST be set to 0x0303 ("TLS 1.2").
- Server Hello - Supported Versions: a single negotiated version (for TLS 1.3). Cannot be used to negotiate earlier versions.
So in TLS 1.2, the client sends a range of supported versions while a TLS 1.3 client sends a list of supported versions. The server will then pick a single version, but for compatibility purposes it will use a new field for selecting TLS 1.3 or newer.
(Even if a client advertises support for some version (e.g. via a TLS record version containing "TLS 1.0"), it could still fail the handshake though if the server agrees to this low version.)
Another thing to be aware of: Wireshark tries to interpret a packet immediately as it is received. At the time the Client Hello is received, it will not know the final version and therefore assume the TLS Record Version. When the Server Hello is received, it can adjust the version accordingly:
$ tshark -r test/captures/tls13-rfc8446.pcap
1 0.000000 10.9.0.1 → 10.9.0.2 TLSv1 304 Client Hello
2 0.002634 10.9.0.2 → 10.9.0.1 TLSv1.3 658 Server Hello, Change Cipher Spec, Application Data
3 0.005266 10.9.0.1 → 10.9.0.2 TLSv1.3 130 Change Cipher Spec, Application Data
4 0.005772 10.9.0.2 → 10.9.0.1 TLSv1.3 468 Application Data
...
In a two-pass dissection (which also includes the Wireshark GUI), the agreed version will be known when it prints the results of the second pass:
$ tshark -r test/captures/tls13-rfc8446.pcap -2
1 0.000000 10.9.0.1 → 10.9.0.2 TLSv1.3 304 Client Hello
2 0.002634 10.9.0.2 → 10.9.0.1 TLSv1.3 658 Server Hello, Change Cipher Spec, Application Data
3 0.005266 10.9.0.1 → 10.9.0.2 TLSv1.3 130 Change Cipher Spec, Application Data
4 0.005772 10.9.0.2 → 10.9.0.1 TLSv1.3 468 Application Data
...
Test capture used above: https://github.com/wireshark/wireshark/blob/master/test/captures/tls13-rfc8446.pcap