Skip to content

crypto/tls: allow QUIC to configure net.Conn used on ClientHelloInfo #77363

Description

@marten-seemann

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:

  1. 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
    }
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status
    Accepted

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions