go: crypto/tls: randomly generate ticket_age_add [freeze exception]
crypto/tls always sets newSessionTicketMsgTLS13.ageAdd
to 0, which makes it so that clients resuming a session can’t obfuscate the obfusacted_ticket_age
. This violates the TLS 1.3 spec (RFC 8446, section 4.6.1):
ticket_age_add: A securely generated, random 32-bit value that is used to obscure the age of the ticket that the client includes in the “pre_shared_key” extension. The client-side ticket age is added to this value modulo 2^32 to obtain the value that is transmitted by the client. The server MUST generate a fresh value for each ticket it sends.
See the sendSessionTickets() function.
How to reproduce
- Run a simple TLS server: https://go.dev/play/p/t2moO8mDTmb (notice I set
srv.SetKeepAlivesEnabled(false)
; we don’t want connection reuse) - open Wireshark, listen on loopback interface and filter on
tls.handshake
curl -k https://localhost:8443 https://localhost:8443
In Wireshark, open the second Client Hello message, look at the pre_shared_key
extension and you’ll see that obfuscated_ticket_age
is 0 (or very close to 0).
Proposed fix
Given that you don’t check the obfuscated_ticket_age, it’s enough to assign ageAdd
a random value each time.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 1
- Comments: 15 (8 by maintainers)
Commits related to this issue
- [release-branch.go1.18 crypto/tls: randomly generate ticket_age_add As required by RFC 8446, section 4.6.1, ticket_age_add now holds a random 32-bit value. Before this change, this value was always s... — committed to golang/go by deleted user 2 years ago
- [release-branch.go1.17] crypto/tls: randomly generate ticket_age_add As required by RFC 8446, section 4.6.1, ticket_age_add now holds a random 32-bit value. Before this change, this value was always ... — committed to golang/go by deleted user 2 years ago
- [release-branch.go1.17] crypto/tls: randomly generate ticket_age_add As required by RFC 8446, section 4.6.1, ticket_age_add now holds a random 32-bit value. Before this change, this value was always ... — committed to danbudris/go by deleted user 2 years ago
- [release-branch.go1.17] crypto/tls: randomly generate ticket_age_add As required by RFC 8446, section 4.6.1, ticket_age_add now holds a random 32-bit value. Before this change, this value was always ... — committed to danbudris/go by deleted user 2 years ago
- crypto/tls: randomly generate ticket_age_add # AWS EKS Backported To: go-1.15.15-eks Backported On: Thu, 22 Sept 2022 Backported By: budris@amazon.com Backported From: release-branch.go1.17 EKS Patch... — committed to rcrozean/go by deleted user 2 years ago
- crypto/tls: randomly generate ticket_age_add # AWS EKS Backported To: go-1.15.15-eks Backported On: Thu, 22 Sept 2022 Backported By: budris@amazon.com Backported From: release-branch.go1.17 EKS Patch... — committed to rcrozean/go by deleted user 2 years ago
- crypto/tls: randomly generate ticket_age_add # AWS EKS Backported To: go-1.16.15-eks Backported On: Tue, 04 Oct 2022 Backported By: budris@amazon.com Backported From: release-branch.go1.17 EKS Patch ... — committed to rcrozean/go by deleted user 2 years ago
cc @golang/security
If the fix is easy and we can get a CL in before the end of the week I think it’s fine. Up to the security team to decide about a CVE/backport.
Ah, yes, that’s an oversight, thank you.
I would argue this is worth a freeze exception, because the fix is very simple, we are early in the freeze, and it fixes a privacy issue (allowing network observers to correlate successive connections even if the client changed location). Maybe even worth a CVE and a backport? Not sure. /cc @golang/release
If we ever expose the session ticket structure (which might be something that happens as part of #25351 #46718 #19199 #6379), we might want to add the obfuscated_ticket_age to it (or start generating it from the key material?) in case other implementations want to use it, but for now we are the only consumers of the tickets and indeed don’t care about it.
(While at it, let’s also add a note about why ticket_nonce is always zero, which is simply that we only ever send one ticket. It’s a good comment to have in there in case that invariant ever changes.)