From 27532dc35c2db60715622dcd2ad0a762108cd3dd Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Sun, 12 Apr 2026 17:05:35 +0200 Subject: [PATCH] crypto/tls: deprecate Config.Rand We now use SetGlobalRandom in recorded tests. It was already partially ineffective: ML-KEM encapsulation, used as part of X25519MLKEM768, doesn't take a source of randomness, and instead always uses the global random source. Fixes #79367 Change-Id: I1cc07ebec21bee32ece685efde188c0d6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/765926 Auto-Submit: Filippo Valsorda LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Roland Shoemaker Reviewed-by: David Chase --- api/next/79367.txt | 1 + .../6-stdlib/99-minor/crypto/tls/79367.md | 2 ++ src/crypto/tls/common.go | 9 ++++-- src/crypto/tls/example_test.go | 24 ++++----------- src/crypto/tls/handshake_client_test.go | 30 ++++++++++--------- src/crypto/tls/handshake_test.go | 8 ----- 6 files changed, 31 insertions(+), 43 deletions(-) create mode 100644 api/next/79367.txt create mode 100644 doc/next/6-stdlib/99-minor/crypto/tls/79367.md diff --git a/api/next/79367.txt b/api/next/79367.txt new file mode 100644 index 0000000000..3213d15505 --- /dev/null +++ b/api/next/79367.txt @@ -0,0 +1 @@ +pkg crypto/tls, type Config struct, Rand //deprecated #79367 diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/79367.md b/doc/next/6-stdlib/99-minor/crypto/tls/79367.md new file mode 100644 index 0000000000..f5a37f8ee9 --- /dev/null +++ b/doc/next/6-stdlib/99-minor/crypto/tls/79367.md @@ -0,0 +1,2 @@ +[Config.Rand] is now deprecated. +For deterministic testing, use [testing/cryptotest.SetGlobalRandom]. diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index be4921effa..9d9b814a00 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -572,10 +572,13 @@ const ( // modified. A Config may be reused; the tls package will also not // modify it. type Config struct { - // Rand provides the source of entropy for nonces and RSA blinding. + // Rand provides the source of entropy for the connection. // If Rand is nil, TLS uses the cryptographic random reader in package - // crypto/rand. - // The Reader must be safe for use by multiple goroutines. + // crypto/rand. The Reader must be safe for use by multiple goroutines. + // + // Deprecated: this should be left nil in production. Not all TLS + // configurations are guaranteed to use Rand. Test code can use + // [testing/cryptotest.SetGlobalRandom] instead. Rand io.Reader // Time returns the current time as the number of seconds since the epoch. diff --git a/src/crypto/tls/example_test.go b/src/crypto/tls/example_test.go index 95e4953fb2..aa9419a595 100644 --- a/src/crypto/tls/example_test.go +++ b/src/crypto/tls/example_test.go @@ -14,14 +14,6 @@ import ( "time" ) -// zeroSource is an io.Reader that returns an unlimited number of zero bytes. -type zeroSource struct{} - -func (zeroSource) Read(b []byte) (n int, err error) { - clear(b) - return len(b), nil -} - func ExampleDial() { // Connecting with a custom root-certificate set. @@ -70,19 +62,17 @@ TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== func ExampleConfig_keyLogWriter() { // Debugging TLS applications by decrypting a network traffic capture. - // WARNING: Use of KeyLogWriter compromises security and should only be // used for debugging. - // Dummy test HTTP server for the example with insecure random so output is - // reproducible. - server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) - server.TLS = &tls.Config{ - Rand: zeroSource{}, // for example only; don't do this. - } + server := httptest.NewUnstartedServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) {})) server.StartTLS() defer server.Close() + pool := x509.NewCertPool() + pool.AddCert(server.Certificate()) + // Typically the log would go to an open file: // w, err := os.OpenFile("tls-secrets.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) w := os.Stdout @@ -91,9 +81,7 @@ func ExampleConfig_keyLogWriter() { Transport: &http.Transport{ TLSClientConfig: &tls.Config{ KeyLogWriter: w, - - Rand: zeroSource{}, // for reproducible output; don't do this. - InsecureSkipVerify: true, // test server certificate is not trusted. + RootCAs: pool, }, }, } diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 7cf40ee5bc..64a668eae9 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -1211,12 +1211,10 @@ func TestKeyLogTLS12(t *testing.T) { clientConfig := testConfigClient.Clone() clientConfig.KeyLogWriter = &clientBuf clientConfig.MaxVersion = VersionTLS12 - clientConfig.Rand = zeroSource{} serverConfig := testConfigServer.Clone() serverConfig.KeyLogWriter = &serverBuf serverConfig.MaxVersion = VersionTLS12 - serverConfig.Rand = zeroSource{} c, s := localPipe(t) done := make(chan bool) @@ -1242,17 +1240,23 @@ func TestKeyLogTLS12(t *testing.T) { if len(loggedLine) == 0 { t.Fatalf("%s: no keylog line was produced", side) } - const expectedLen = 13 /* "CLIENT_RANDOM" */ + - 1 /* space */ + - 32*2 /* hex client nonce */ + - 1 /* space */ + - 48*2 /* hex master secret */ + - 1 /* new line */ - if len(loggedLine) != expectedLen { - t.Fatalf("%s: keylog line has incorrect length (want %d, got %d): %q", side, expectedLen, len(loggedLine), loggedLine) + rest, ok := strings.CutSuffix(loggedLine, "\n") + if !ok { + t.Fatalf("%s: keylog line is missing trailing newline: %q", side, loggedLine) } - if !strings.HasPrefix(loggedLine, "CLIENT_RANDOM "+strings.Repeat("0", 64)+" ") { - t.Fatalf("%s: keylog line has incorrect structure or nonce: %q", side, loggedLine) + label, rest, ok := strings.Cut(rest, " ") + if !ok || label != "CLIENT_RANDOM" { + t.Fatalf("%s: keylog line has incorrect label: %q", side, loggedLine) + } + clientRandom, masterSecret, ok := strings.Cut(rest, " ") + if !ok { + t.Fatalf("%s: keylog line is missing master secret: %q", side, loggedLine) + } + if b, err := hex.DecodeString(clientRandom); err != nil || len(b) != 32 { + t.Fatalf("%s: keylog line has invalid client random: %q", side, loggedLine) + } + if b, err := hex.DecodeString(masterSecret); err != nil || len(b) != 48 { + t.Fatalf("%s: keylog line has invalid master secret: %q", side, loggedLine) } } @@ -1265,11 +1269,9 @@ func TestKeyLogTLS13(t *testing.T) { clientConfig := testConfigClient.Clone() clientConfig.KeyLogWriter = &clientBuf - clientConfig.Rand = zeroSource{} serverConfig := testConfigServer.Clone() serverConfig.KeyLogWriter = &serverBuf - serverConfig.Rand = zeroSource{} c, s := localPipe(t) done := make(chan bool) diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go index 9b72b1f9c7..3205dd97d6 100644 --- a/src/crypto/tls/handshake_test.go +++ b/src/crypto/tls/handshake_test.go @@ -394,14 +394,6 @@ Dialing: panic("unreachable") } -// zeroSource is an io.Reader that returns an unlimited number of zero bytes. -type zeroSource struct{} - -func (zeroSource) Read(b []byte) (n int, err error) { - clear(b) - return len(b), nil -} - func TestMain(m *testing.M) { flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args)