Repository navigation
Conversation
clientHandshake copies the private handshake state into UConn.HandshakeState once the handshake is done, so callers can read what was negotiated. The copy included State13.KeyShareKeys, the private keys behind the ClientHello's key shares, which nothing reads after the shared secret is derived. With X25519MLKEM768 the ML-KEM decapsulation key is 7.8 KiB, so every idle connection kept about 8 KiB of spent private key material for its lifetime: 27.4 KiB of live heap per idle Chrome-spec connection against 7.0 KiB for a crypto/tls client. Clear the keys right after the public state is refreshed and say so on the field. The rest of the handshake state stays readable. Per idle connection this saves 8.4 KiB with the Go hello and 8.4 KiB with the Chrome 155 spec.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After the handshake,
clientHandshakecopies the whole private handshake state intoUConn.HandshakeStateso callers can read what was negotiated. That copy includesState13.KeyShareKeys, the private keys behind the ClientHello's key shares, which nothing reads once the shared secret is derived: no code path consults them after the handshake, HelloRetryRequest is handled before the copy, and resumption and key updates use theConn's own secrets. With X25519MLKEM768 the ML-KEM decapsulation key is 7.8 KiB (the FIPS implementation keeps the expanded matrix), so every idle connection holds about 8 KiB of spent private key material for its whole lifetime.Measured on this branch's base, live heap per idle client connection after a TLS 1.3 handshake, servers closed and collected (300 connections,
runtime.MemStats):crypto/tlsClientUClientwithHelloGolangUClientwithHelloChrome_155This change clears
State13.KeyShareKeysright after the public state is refreshed, and documents on the field that it is set before the handshake and nil after it. The rest of the handshake state stays readable, soHandshakeState.Hello,ServerHello,MasterSecretandState13.UsingPSK, which the examples and downstream code read after the handshake, are unchanged. The remaining difference tocrypto/tlsis the public copies of both hellos and the applied extensions, which is the state uTLS documents as readable.The test builds the handshake state with both hello builders, checks the keys are present before the handshake, and checks they are gone after it while the rest of the state remains.
Verified with Go 1.27.3:
go test ./...,go test -raceon the handshake tests,go vet,gofmt -s,go fix -diff, staticcheck and golangci-lint report nothing.