[インデックス 18632] ファイルの概要
このコミットは、Go言語のcrypto/tls
パッケージにおいて、TLS接続の確立後にその接続が使用しているTLSプロトコルバージョン(例: TLS 1.0, TLS 1.1, TLS 1.2)をConnectionState
構造体を通じて報告するように変更を加えるものです。これにより、アプリケーションは確立されたTLS接続のバージョン情報をプログラム的に取得できるようになります。
コミット
commit c7612f3426977332b471acb8f1928a1cd027f896
Author: Adam Langley <agl@golang.org>
Date: Mon Feb 24 18:01:28 2014 -0500
crypto/tls: report TLS version in ConnectionState.
Fixes #7231.
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/68250043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c7612f3426977332b471acb8f1928a1cd027f896
元コミット内容
crypto/tls: report TLS version in ConnectionState.
Fixes #7231.
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/68250043
変更の背景
この変更の背景には、Goのcrypto/tls
パッケージが提供するTLS接続の状態情報が不完全であったという問題があります。具体的には、TLSハンドシェイクが完了した後、確立された接続がどのTLSプロトコルバージョン(例: TLS 1.0, TLS 1.1, TLS 1.2)を使用しているかをプログラムから直接取得する方法がありませんでした。
GitHub Issue #7231("crypto/tls: ConnectionState should report TLS version")がこの問題提起の根拠となっています。このIssueでは、ユーザーがTLS接続のバージョン情報を取得したいという要望を表明しており、特にデバッグやセキュリティ監査の目的でこの情報が必要とされていました。例えば、特定のTLSバージョン(例: TLS 1.0やTLS 1.1)の使用を非推奨とするポリシーを持つシステムにおいて、実際にどのバージョンが使われているかを確認するためには、この情報が不可欠です。
このコミットは、この欠落していた機能を追加することで、crypto/tls
パッケージの使いやすさと情報提供の充実を図るものです。これにより、開発者はより詳細なTLS接続の状態を把握し、アプリケーションの挙動を制御したり、セキュリティ要件を満たしているかを確認したりすることが可能になります。
前提知識の解説
TLS (Transport Layer Security)
TLSは、インターネット上で安全な通信を行うための暗号化プロトコルです。ウェブブラウザとウェブサーバー間のHTTPS通信などで広く利用されています。TLSは、通信相手の認証、データの機密性(暗号化)、データの完全性(改ざん防止)を提供します。
TLSプロトコルには複数のバージョンが存在し、それぞれセキュリティ機能や性能が異なります。主なバージョンは以下の通りです。
- SSL 3.0: TLSの前身。現在ではセキュリティ上の脆弱性があるため非推奨。
- TLS 1.0: SSL 3.0の後継。現在では多くの環境で非推奨またはサポート終了。
- TLS 1.1: TLS 1.0の改良版。現在では多くの環境で非推奨またはサポート終了。
- TLS 1.2: 広く利用されているバージョン。より強力な暗号スイートをサポート。
- TLS 1.3: 最新のバージョン。ハンドシェイクの高速化、セキュリティの強化が図られている。
各バージョンは、ハンドシェイクのプロセス、サポートする暗号スイート、メッセージ認証コード(MAC)のアルゴリズムなどに違いがあります。新しいバージョンほど、既知の脆弱性に対する対策が施され、より安全な通信が可能です。
Go言語のcrypto/tls
パッケージ
Go言語の標準ライブラリに含まれるcrypto/tls
パッケージは、TLSプロトコルを実装し、Goアプリケーションで安全なネットワーク通信を可能にします。このパッケージは、クライアントとサーバーの両方の役割をサポートし、証明書の管理、ハンドシェイクの処理、データの暗号化・復号化など、TLS通信に必要な機能を提供します。
ConnectionState
構造体
crypto/tls
パッケージにおいて、ConnectionState
構造体は、確立されたTLS接続に関する詳細な情報を提供するものです。この構造体は、TLSハンドシェイクが完了した後に、その接続の特性(使用された暗号スイート、証明書情報、ハンドシェイクが再開されたかどうかなど)をプログラムから取得するために使用されます。
このコミット以前は、ConnectionState
にはTLSプロトコルのバージョン情報が含まれていませんでした。
技術的詳細
このコミットの技術的な変更は、主に以下の3つのファイルにわたります。
-
src/pkg/crypto/tls/common.go
:ConnectionState
構造体にVersion uint16
フィールドが追加されました。このフィールドは、確立されたTLS接続が使用しているTLSプロトコルのバージョン(例:VersionTLS10
,VersionTLS11
,VersionTLS12
など、uint16
型で定義された定数)を格納します。
-
src/pkg/crypto/tls/conn.go
:Conn
構造体のConnectionState()
メソッド内で、c.handshakeComplete
がtrue
(つまりハンドシェイクが完了している)の場合に、新しく追加されたstate.Version
フィールドにc.vers
の値を代入する行が追加されました。c.vers
は、Conn
構造体の内部フィールドであり、TLSハンドシェイク中にネゴシエートされたTLSプロトコルバージョンを保持しています。この変更により、内部で保持されていたバージョン情報がConnectionState
を通じて外部に公開されるようになります。
-
src/pkg/crypto/tls/handshake_server_test.go
:TestVersion
という新しいテスト関数が追加されました。このテストは、MaxVersion
をVersionTLS11
に設定したサーバーと、デフォルト設定のクライアント間でTLSハンドシェイクを行います。- ハンドシェイクが成功した後、
ConnectionState
から取得したVersion
が期待されるVersionTLS11
と一致するかどうかを検証します。これにより、ConnectionState.Version
フィールドが正しく設定されていることが保証されます。
これらの変更により、TLS接続が確立された後、アプリケーションはConnectionState().Version
を呼び出すことで、実際に使用されているTLSプロトコルバージョンを簡単に取得できるようになります。これは、特定のTLSバージョンが非推奨になった場合や、セキュリティポリシーの遵守を確認する際に非常に有用です。
コアとなるコードの変更箇所
src/pkg/crypto/tls/common.go
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -155,6 +155,7 @@ var supportedClientCertSignatureAlgorithms = []signatureAndHash{\
// ConnectionState records basic TLS details about the connection.
type ConnectionState struct {
+ Version uint16 // TLS version used by the connection (e.g. VersionTLS12)
HandshakeComplete bool // TLS handshake is complete
DidResume bool // connection resumes a previous TLS connection
CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)\
src/pkg/crypto/tls/conn.go
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -969,6 +969,7 @@ func (c *Conn) ConnectionState() ConnectionState {\
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete
if c.handshakeComplete {\
+ state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
state.DidResume = c.didResume
state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback\
src/pkg/crypto/tls/handshake_server_test.go
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -195,6 +195,23 @@ func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, e\
return
}\
+func TestVersion(t *testing.T) {
+ serverConfig := &Config{
+ Certificates: testConfig.Certificates,
+ MaxVersion: VersionTLS11,
+ }
+ clientConfig := &Config{
+ InsecureSkipVerify: true,
+ }
+ state, err := testHandshake(clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.Version != VersionTLS11 {
+ t.Fatalf("Incorrect version %x, should be %x", state.Version, VersionTLS11)
+ }
+}
+
func TestCipherSuitePreference(t *testing.T) {
serverConfig := &Config{
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},\
コアとなるコードの解説
-
src/pkg/crypto/tls/common.go
におけるConnectionState
の拡張:ConnectionState
構造体は、TLS接続の確立後にその状態をアプリケーションに公開するためのデータ構造です。このコミットでは、この構造体にVersion uint16
という新しいフィールドが追加されました。uint16
型は、TLSプロトコルバージョンを表すために使用されます。例えば、VersionTLS10
はTLS 1.0、VersionTLS11
はTLS 1.1、VersionTLS12
はTLS 1.2といった定数に対応します。これにより、アプリケーションは確立された接続がどのTLSバージョンを使用しているかを明確に識別できるようになります。
-
src/pkg/crypto/tls/conn.go
におけるバージョン情報の代入:Conn
構造体のConnectionState()
メソッドは、現在のTLS接続の状態をConnectionState
構造体として返します。- このメソッド内で、TLSハンドシェイクが正常に完了した場合(
c.handshakeComplete
がtrue
の場合)に、Conn
オブジェクト内部で保持されているネゴシエート済みのTLSバージョン(c.vers
)が、新しく追加されたstate.Version
フィールドに代入されます。 - これにより、TLSハンドシェイクの過程でクライアントとサーバー間で合意された最終的なTLSバージョンが、
ConnectionState
を通じて外部からアクセス可能になります。
-
src/pkg/crypto/tls/handshake_server_test.go
におけるテストの追加:TestVersion
という新しい単体テストが追加されました。このテストの目的は、ConnectionState.Version
フィールドが正しく機能していることを検証することです。- テストでは、サーバーの
MaxVersion
をVersionTLS11
に設定し、クライアントが接続を試みます。これにより、ネゴシエートされるTLSバージョンがTLS 1.1になることが期待されます。 testHandshake
関数を通じてハンドシェイクを実行し、その結果として得られるConnectionState
のVersion
フィールドがVersionTLS11
と等しいことをアサートします。もし一致しない場合はテストが失敗し、実装に問題があることを示します。- このテストは、機能が正しく実装され、期待通りに動作することを保証するための重要なステップです。
これらの変更は、Goのcrypto/tls
パッケージのAPIを改善し、TLS接続に関するより詳細な情報を提供することで、開発者がより堅牢でセキュリティ意識の高いアプリケーションを構築できるように貢献しています。
関連リンク
- Go issue #7231: crypto/tls: ConnectionState should report TLS version
- Gerrit Code Review: https://golang.org/cl/68250043
参考にした情報源リンク
- Go issue #7231 (変更の背景を理解するために参照)
- TLS - Wikipedia (TLSプロトコル全般の知識を補完するために参照)
- Go言語
crypto/tls
パッケージのドキュメント (GoのTLS実装に関する一般的な理解のために参照) - コミットに含まれるコード差分 (変更内容の直接的な分析)
- Go言語のテストに関する一般的な知識 (テストコードの理解のために参照)