crypto/tls: allow QUIC to configure net.Conn used on ClientHelloInfo
要約
概要
crypto/tls パッケージの QUICConfig に ClientHelloInfoConn フィールドを追加し、QUICスタックがハンドシェイク中の ClientHelloInfo.Conn に使用する net.Conn を注入できるようにするproposalです。これにより、QUICスタックが tls.Config を不必要にクローンする必要がなくなります。
ステータス変更
active → likely_accept
2026年3月26日の週次Proposalレビューミーティングにおいて、@aclements がneildによる具体的なAPI提案(QUICConfig.ClientHelloInfoConn net.Conn)の追加を妥当と判断し、likely acceptへ移行しました。ローカル/リモートアドレスのみを個別フィールドとして追加する代替案も検討されましたが、net.Conn を直接渡す方式の方が、将来QUICレイヤーが偽のConnに追加メタデータを持たせたい場合にも対応できるという点で優れているとの判断がなされました。
技術的背景
現状の問題点
crypto/tls パッケージの GetCertificate や GetConfigForClient コールバックは tls.ClientHelloInfo を受け取り、その Conn フィールド(型: net.Conn)にはTCPコネクションが設定されます。しかしQUICはUDPを使用するため、TCPと同様の read/write/close 操作は意味をなしません。
従来、quic-go などのQUICスタックはこの問題を回避するために tls.Config をクローンし、アドレス情報だけを返す偽の net.Conn をコールバックに注入していました。ところがGo 1.25.6のセキュリティ修正(CVE-2025-68121、Issue #77113)で Config.Clone() が自動生成されたセッションチケットキーをコピーしなくなったため、このクローンによるワークアラウンドがセッション再開(Session Resumption)を破壊するようになりました。
// 現在のquic-goのワークアラウンド(問題のあるコード)
clonedConfig := tlsConfig.Clone() // セキュリティ修正後はセッションキーが引き継がれない
clonedConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
// 偽のnet.ConnをClientHelloInfo.Connに注入
info.Conn = &fakeConn{localAddr: localAddr, remoteAddr: remoteAddr}
return originalGetCertificate(info)
}
提案された解決策
tls.QUICConfig 構造体に ClientHelloInfoConn フィールドを追加します。
type QUICConfig struct {
TLSConfig *Config
EnableSessionEvents bool
ClientHelloInfoConn net.Conn // ハンドシェイク中のClientHelloInfo.Connに使用される
}
crypto/tls は、QUICコネクションのハンドシェイク中にコールバックを呼び出す際、このフィールドの値を ClientHelloInfo.Conn として渡します。
これによって何ができるようになるか
コード例
// Before: tls.Configのクローンと偽Connの手動注入が必要
quicConfig := &tls.QUICConfig{
TLSConfig: tlsConfig.Clone(), // Clone()が必要でセッションキーが壊れる
}
// After: QUICConfigに直接Connを設定するだけ
fakeConn := &net.UDPConn{} // LocalAddr/RemoteAddrのみ実装した偽conn
quicConfig := &tls.QUICConfig{
TLSConfig: tlsConfig, // クローン不要
ClientHelloInfoConn: fakeConn,
}
具体的なメリットは以下の通りです。
- QUICスタックが
tls.Configをクローンせずにアドレス情報をClientHelloInfo.Conn経由でコールバックに渡せる - セッション再開が正しく機能する(自動生成セッションチケットキーが保持される)
- HTTP/3サーバー実装において、HTTP/2と共通の
tls.Configを共有しやすくなる(別のproposal #77631と合わせて、クローンが完全不要になる)
議論のハイライト
neildが最初にフィールド名としてClientHelloInfoConnを提案し、フィールドの用途を明確にする名前として評価された- オプション1(
HandshakeConn net.Conn)とオプション2(LocalAddr/RemoteAddr net.Addrの個別フィールド)の2案が検討され、最終的にnet.Connを直接受け取るオプション1が採用。これにより「偽のConnが何を提供すべきか」という将来の質問を予防できるとneildが指摘 quic-goでの実装検証(CL 745720 + quic-go PR #5571)により、実用性が確認された- 本proposalは関連proposal #77631(QUIC使用時のMinVersion強制チェック廃止)と合わせることで、QUICスタックが
tls.Configをクローンする必要を完全に排除できる設計となっている - CVE-2025-68121(#77113)のセキュリティ修正が本proposalの直接的なトリガーとなった