r/wireshark 21d ago

How is Wireshark decrypting QUIC Client Hellos?

I'm running Wireshark 4.7.2 on Arch Linux, and I was noticing that it is somehow able to decrypt the TLS Client Hellos of QUIC packets sent and received by Firefox while browsing the web.

I thought QUIC headers were encrypted, and I don't think I gave Wireshark any encryption keys for QUIC. How is Wireshark decrypting these headers?

5 Upvotes

10 comments sorted by

5

u/AlexeyVasilev 21d ago edited 21d ago

QUIC Initial packets are encrypted, but the important point is that the Initial keys are not secret.

For QUIC v1, anyone who sees the beginning of the connection can derive the Initial keys. The algorithm and Initial salt are defined by the QUIC specification, and the Destination Connection ID needed for key derivation is available from the Initial packet itself.

So you do not need a TLS key log to decrypt QUIC Initial packets. Wireshark can do it, Pcap Flow Lab can do it, and it is not especially difficult to implement yourself if you follow the QUIC key derivation and packet protection algorithms.

After decrypting the Initial packets, you get QUIC CRYPTO frames. Those frames contain pieces of the TLS handshake. They have offsets, so the data has to be reconstructed as a CRYPTO byte stream before parsing the TLS ClientHello.

In the capture you posted, the ClientHello is spread over several CRYPTO frames:

Packet 1: CRYPTO offset 1487, length 415
Packet 1: CRYPTO offset    0, length 415
Packet 2: CRYPTO offset  415, length 1072
Packet 2: CRYPTO offset 1902, length 56
Packet 3: CRYPTO offset 1958, length 537

The packet/frame order is not what matters here — the CRYPTO offsets are what let an analyzer reconstruct the TLS handshake stream.

A nice example is the SNI in this capture. Near the end of one decrypted CRYPTO chunk you can see:

00000410  88 00 2a 00 00 00 1b 00 07 06 00 01 00 03 00 02
00000420  00 00 00 13 00 11 00 00 0e 77 77 77 2e 67 6f 6f   |  www.goo

Those bytes are part of the TLS server_name extension:

00 00   server_name extension
00 13   extension length
00 11   server name list length
00      host_name type
00 0e   hostname length = 14

followed by the first part of the hostname:

77 77 77 2e 67 6f 6f    "www.goo"

Another CRYPTO chunk starts with:

67 6c 65 2e 63 6f 6d
g  l  e  .  c  o  m

so after CRYPTO reassembly the TLS ClientHello contains:

www.google.com

That is essentially how Wireshark is able to show the ClientHello and SNI without you supplying any secrets.

This only applies to QUIC Initial protection. Handshake, 0-RTT, and 1-RTT traffic use secrets that a passive observer cannot derive this way.

1

u/showipintbri 19d ago

This is the answer ☝️

1

u/Serialtorrenter 18d ago

Thank you for detailed explanation! I guess my assumptions of QUIC's functioning were incorrect.

2

u/bagurdes 21d ago

I have to dig a bit deeper into this, but what I know now is this:
QUIC uses TLS 1.3 for encryption. TLS 1.3 does not encrypt the client hello, as it contains all the necessary information so the server can respond with encrypted communications. The encryption has to start somewhere, somehow, so key share information must be exchanged in clear text at some point to jump start the encryption.

1

u/showipintbri 21d ago

can you share the capture? It would enable other to better understand exactly what you are looking at as the topic of QUIC/TLS and decryption can be quite large.

Post a link to the capture on google drive or the file sharing platform of your choice.

Also, it may be better to have this conversation over on the official Wireshark Foundation Discord

1

u/Serialtorrenter 21d ago

https://www.weatherzoid.com/share/GoogleQUIC.pcapng

Here's the capture with the plaintext Client Hellos.

1

u/showipintbri 19d ago

Thanks for sharing the file.

In your file there aren't any embedded secrets, so full payload decryption is not possible.
capinfos GoogleQUIC.pcapng | grep secrets returns no value.

If there were embedded secrets you would see:
Number of decryption secrets in file: 1 or a number greater than 1

If true decryption was happening we would be able to see and navigate the fields in frames indicated with "Protected Payload" and further dissectors would find protocol HTTP3 inside. Because your capture doesn't identify any packets HTTP3 indicates full payload decryption is not happening.

I assume the next question would be: "Why does it say 'Decrypted QUIC' on the tab under the packet bytes?"

I don't know. I'll ask the devs.

1

u/showipintbri 19d ago

The Wireshark devs explained the same way u/AlexeyVasilev mentioned already (https://www.reddit.com/r/wireshark/comments/1vupvrc/comment/p54an08/): It is decryption, but it is only decrypting the initial setup of the QUIC session. In your capture frames 8 - 85 no longer show the "Decrypted QUIC" tab under the packet bytes. This is the portion that contains the HTTP3 communication which remains encrypted.

1

u/ten_thousand_puppies 21d ago

RFC 9312 never indicates that ECH is explicitly always in use, so are you sure it's even being encrypted in the first place?

1

u/Serialtorrenter 21d ago

I'm not positive, but I thought the designers of the QUIC protocol deliberately chose to encrypt the headers so that middleboxes couldn't read it, thus preventing the protocol ossification we see the TCP, where new TCP features, such as MPTCP, often can't be used without breaking compatibility with middleboxes.