メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#77363likely_accept

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

ステータス変更: active likely_accept

要約

AIによる要約であり、誤りを含む場合があります。

概要

crypto/tls パッケージの QUICConfigClientHelloInfoConn フィールドを追加し、QUICスタックがハンドシェイク中の ClientHelloInfo.Conn に使用する net.Conn を注入できるようにするproposalです。これにより、QUICスタックが tls.Config を不必要にクローンする必要がなくなります。

ステータス変更

activelikely_accept
2026年3月26日の週次Proposalレビューミーティングにおいて、@aclements がneildによる具体的なAPI提案(QUICConfig.ClientHelloInfoConn net.Conn)の追加を妥当と判断し、likely acceptへ移行しました。ローカル/リモートアドレスのみを個別フィールドとして追加する代替案も検討されましたが、net.Conn を直接渡す方式の方が、将来QUICレイヤーが偽のConnに追加メタデータを持たせたい場合にも対応できるという点で優れているとの判断がなされました。

技術的背景

現状の問題点

crypto/tls パッケージの GetCertificateGetConfigForClient コールバックは 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の直接的なトリガーとなった

関連リンク