From b46421afd0ddbf027001ac1f334acee4e17d1f71 Mon Sep 17 00:00:00 2001 From: arian ahmidi Date: Tue, 13 Oct 2026 18:39:45 +0330 Subject: [PATCH] fix: apply the Chrome parrot spec in Start, after the transport parameters SetTransportParameters writes quic-go's transport parameters into the retained ClientHello spec, but the spec was applied in newUTLSQUICClient, before that call. That works with uTLS v1.8.2, whose ApplyPreset keeps the caller's extension objects. Newer uTLS (master since ff1b50fbbe9a) deep-copies the spec in ApplyPreset, so the parameters never reach the ClientHello and every handshake fails with "missing initial_source_connection_id". Applying the spec in Start works with both. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KqYot5fp6kvHireReN6Lu7 --- internal/handshake/tls_conn_utls.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/internal/handshake/tls_conn_utls.go b/internal/handshake/tls_conn_utls.go index 2e78953f8bf..9498009d1fb 100644 --- a/internal/handshake/tls_conn_utls.go +++ b/internal/handshake/tls_conn_utls.go @@ -38,9 +38,9 @@ func newUTLSQUICClient(tlsConf *tls.Config) (*utlsQUICConn, error) { spec := chromeQUICClientHelloSpec(tlsConf.NextProtos) conn := utls.UQUICClient(&utls.QUICConfig{TLSConfig: uConf}, utls.HelloCustom) - if err := conn.ApplyPreset(spec); err != nil { - return nil, fmt.Errorf("applying Chrome ClientHello spec: %w", err) - } + // The spec is applied in Start, after SetTransportParameters has written the + // transport parameters into it: newer uTLS versions deep-copy the spec in + // ApplyPreset, so changes made to it afterwards would never reach the ClientHello. return &utlsQUICConn{conn: conn, spec: spec}, nil } @@ -118,8 +118,13 @@ func signatureSchemesToStd(in []utls.SignatureScheme) []tls.SignatureScheme { return out } -func (c *utlsQUICConn) Start(ctx context.Context) error { return c.conn.Start(ctx) } -func (c *utlsQUICConn) Close() error { return c.conn.Close() } +func (c *utlsQUICConn) Start(ctx context.Context) error { + if err := c.conn.ApplyPreset(c.spec); err != nil { + return fmt.Errorf("applying Chrome ClientHello spec: %w", err) + } + return c.conn.Start(ctx) +} +func (c *utlsQUICConn) Close() error { return c.conn.Close() } func (c *utlsQUICConn) HandleData(level tls.QUICEncryptionLevel, data []byte) error { return c.conn.HandleData(utlsEncryptionLevel(level), data)