The crypto/tls package's GetCertificate and GetConfigForClient callbacks receive a tls.ClientHelloInfo with a Conn field (type net.Conn). For QUIC, a full net.Conn doesn't make sense, as QUIC uses UDP and doesn't support read/write/close in the same way. Even for TCP, calling those methods during the handshake was always error-prone and nonsensical. The only useful parts are LocalAddr and RemoteAddr.
Currently, quic-go works around this by cloning the tls.Config and wrapping the callbacks to inject a fake net.Conn that exposes just the addresses (with no-ops for other methods). This cloning now breaks session resumption since Go 1.25.6, where a security fix stopped copying auto-generated session ticket keys in Config.Clone() (see #77113).
Arguably, a QUIC stack shouldn’t need to do any cloning. I propose extending tls.QUICConfig to let QUIC stacks supply the connection addresses for the handshake.
This proposal doesn’t run into any problems with connection migration as defined in RFC 9000, as the five-tuple is fixed during the handshake (migration only happens post-handshake).
Two options:
-
Add a HandshakeConn net.Conn field. The QUIC stack provides a fake conn with LocalAddr and RemoteAddr; crypto/tls uses it directly in ClientHelloInfo.Conn.
type QUICConfig struct {
TLSConfig *Config
EnableSessionEvents bool
HandshakeConn net.Conn // Fake conn for ClientHelloInfo.Conn during handshake
}
-
Add LocalAddr and RemoteAddr fields (type net.Addr). The QUIC stack sets them; crypto/tls creates the fake conn internally.
type QUICConfig struct {
TLSConfig *Config
EnableSessionEvents bool
LocalAddr net.Addr // Local address for ClientHelloInfo.Conn during handshake
RemoteAddr net.Addr // Remote address for ClientHelloInfo.Conn during handshake
}
I don't have a strong preference, but a slight lean toward option 1, as it gives QUIC stacks more flexibility for additional metadata.
The
crypto/tlspackage'sGetCertificateandGetConfigForClientcallbacks receive atls.ClientHelloInfowith aConnfield (typenet.Conn). For QUIC, a fullnet.Conndoesn't make sense, as QUIC uses UDP and doesn't support read/write/close in the same way. Even for TCP, calling those methods during the handshake was always error-prone and nonsensical. The only useful parts areLocalAddrandRemoteAddr.Currently, quic-go works around this by cloning the
tls.Configand wrapping the callbacks to inject a fakenet.Connthat exposes just the addresses (with no-ops for other methods). This cloning now breaks session resumption since Go 1.25.6, where a security fix stopped copying auto-generated session ticket keys inConfig.Clone()(see #77113).Arguably, a QUIC stack shouldn’t need to do any cloning. I propose extending
tls.QUICConfigto let QUIC stacks supply the connection addresses for the handshake.This proposal doesn’t run into any problems with connection migration as defined in RFC 9000, as the five-tuple is fixed during the handshake (migration only happens post-handshake).
Two options:
Add a
HandshakeConn net.Connfield. The QUIC stack provides a fake conn withLocalAddrandRemoteAddr;crypto/tlsuses it directly inClientHelloInfo.Conn.Add
LocalAddrandRemoteAddrfields (typenet.Addr). The QUIC stack sets them;crypto/tlscreates the fake conn internally.I don't have a strong preference, but a slight lean toward option 1, as it gives QUIC stacks more flexibility for additional metadata.