crypto/tls: add QUICConfig.ClientHelloInfoConn

Fixes #77363.

Change-Id: I28ec5cdd16e96bae13f495a904006845dfbf3a2e
Reviewed-on: https://go-review.googlesource.com/c/go/+/745720
Reviewed-by: Damien Neil <dneil@google.com>
Auto-Submit: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Daniel McCarney <daniel@binaryparadox.net>
This commit is contained in:
Marten Seemann 2026-02-15 18:14:36 +08:00 committed by Gopher Robot
parent fee42ee058
commit 1456da550a
5 changed files with 46 additions and 1 deletions

1
api/next/77363.txt Normal file
View file

@ -0,0 +1 @@
pkg crypto/tls, type QUICConfig struct, ClientHelloInfoConn net.Conn #77363

View file

@ -0,0 +1,2 @@
The new [QUICConfig.ClientHelloInfoConn] field specifies the [net.Conn] to use
for the [ClientHelloInfo.Conn] field during QUIC server handshakes.

View file

@ -1024,6 +1024,10 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg)
supportedVersions = supportedVersionsFromMax(clientHello.vers)
}
conn := c.conn
if c.quic != nil {
conn = c.quic.clientHelloInfoConn
}
return &ClientHelloInfo{
CipherSuites: clientHello.cipherSuites,
ServerName: clientHello.serverName,
@ -1033,7 +1037,7 @@ func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg)
SupportedProtos: clientHello.alpnProtocols,
SupportedVersions: supportedVersions,
Extensions: clientHello.extensions,
Conn: c.conn,
Conn: conn,
HelloRetryRequest: c.didHRR,
config: c.config,
ctx: ctx,

View file

@ -8,6 +8,7 @@ import (
"context"
"errors"
"fmt"
"net"
)
// QUICEncryptionLevel represents a QUIC encryption level used to transmit
@ -56,6 +57,9 @@ type QUICConfig struct {
// stored in the client session cache.
// The application should use [QUICConn.StoreSession] to store sessions.
EnableSessionEvents bool
// ClientHelloInfoConn is the net.Conn to use for the ClientHelloInfo.Conn field.
ClientHelloInfoConn net.Conn
}
// A QUICEventKind is a type of operation on a QUIC connection.
@ -176,6 +180,7 @@ type quicState struct {
transportParams []byte // to send to the peer
enableSessionEvents bool
clientHelloInfoConn net.Conn
}
// QUICClient returns a new TLS client side connection using QUICTransport as the
@ -199,6 +204,7 @@ func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn {
signalc: make(chan struct{}),
blockedc: make(chan struct{}),
enableSessionEvents: config.EnableSessionEvents,
clientHelloInfoConn: config.ClientHelloInfoConn,
}
conn.quic.events = conn.quic.eventArr[:0]
return &QUICConn{

View file

@ -9,6 +9,7 @@ import (
"context"
"errors"
"fmt"
"net"
"reflect"
"strings"
"sync"
@ -481,6 +482,37 @@ func TestQUICStartContextPropagation(t *testing.T) {
}
}
func TestQUICClientHelloInfoConn(t *testing.T) {
clientHelloInfoConn, peerConn := net.Pipe()
t.Cleanup(func() {
clientHelloInfoConn.Close()
peerConn.Close()
})
config := &QUICConfig{
TLSConfig: testConfig.Clone(),
ClientHelloInfoConn: clientHelloInfoConn,
}
config.TLSConfig.MinVersion = VersionTLS13
var called bool
config.TLSConfig.GetConfigForClient = func(info *ClientHelloInfo) (*Config, error) {
called = true
if info.Conn != clientHelloInfoConn {
t.Errorf("ClientHelloInfo.Conn = %v, want %v", info.Conn, clientHelloInfoConn)
}
return nil, nil
}
cli := newTestQUICClient(t, config)
cli.conn.SetTransportParameters(nil)
srv := newTestQUICServer(t, config)
srv.conn.SetTransportParameters(nil)
if err := runTestQUICConnection(context.Background(), cli, srv, nil); err != nil {
t.Fatalf("error during connection handshake: %v", err)
}
if !called {
t.Fatal("GetConfigForClient was not called")
}
}
func TestQUICContextCancelation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
config := &QUICConfig{TLSConfig: testConfig.Clone()}