Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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つのファイルにわたります。

  1. src/pkg/crypto/tls/common.go:

    • ConnectionState構造体にVersion uint16フィールドが追加されました。このフィールドは、確立されたTLS接続が使用しているTLSプロトコルのバージョン(例: VersionTLS10, VersionTLS11, VersionTLS12など、uint16型で定義された定数)を格納します。
  2. src/pkg/crypto/tls/conn.go:

    • Conn構造体のConnectionState()メソッド内で、c.handshakeCompletetrue(つまりハンドシェイクが完了している)の場合に、新しく追加されたstate.Versionフィールドにc.versの値を代入する行が追加されました。
    • c.versは、Conn構造体の内部フィールドであり、TLSハンドシェイク中にネゴシエートされたTLSプロトコルバージョンを保持しています。この変更により、内部で保持されていたバージョン情報がConnectionStateを通じて外部に公開されるようになります。
  3. src/pkg/crypto/tls/handshake_server_test.go:

    • TestVersionという新しいテスト関数が追加されました。このテストは、MaxVersionVersionTLS11に設定したサーバーと、デフォルト設定のクライアント間で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},\

コアとなるコードの解説

  1. 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バージョンを使用しているかを明確に識別できるようになります。
  2. src/pkg/crypto/tls/conn.goにおけるバージョン情報の代入:

    • Conn構造体のConnectionState()メソッドは、現在のTLS接続の状態をConnectionState構造体として返します。
    • このメソッド内で、TLSハンドシェイクが正常に完了した場合(c.handshakeCompletetrueの場合)に、Connオブジェクト内部で保持されているネゴシエート済みのTLSバージョン(c.vers)が、新しく追加されたstate.Versionフィールドに代入されます。
    • これにより、TLSハンドシェイクの過程でクライアントとサーバー間で合意された最終的なTLSバージョンが、ConnectionStateを通じて外部からアクセス可能になります。
  3. src/pkg/crypto/tls/handshake_server_test.goにおけるテストの追加:

    • TestVersionという新しい単体テストが追加されました。このテストの目的は、ConnectionState.Versionフィールドが正しく機能していることを検証することです。
    • テストでは、サーバーのMaxVersionVersionTLS11に設定し、クライアントが接続を試みます。これにより、ネゴシエートされるTLSバージョンがTLS 1.1になることが期待されます。
    • testHandshake関数を通じてハンドシェイクを実行し、その結果として得られるConnectionStateVersionフィールドがVersionTLS11と等しいことをアサートします。もし一致しない場合はテストが失敗し、実装に問題があることを示します。
    • このテストは、機能が正しく実装され、期待通りに動作することを保証するための重要なステップです。

これらの変更は、Goのcrypto/tlsパッケージのAPIを改善し、TLS接続に関するより詳細な情報を提供することで、開発者がより堅牢でセキュリティ意識の高いアプリケーションを構築できるように貢献しています。

関連リンク

参考にした情報源リンク

  • Go issue #7231 (変更の背景を理解するために参照)
  • TLS - Wikipedia (TLSプロトコル全般の知識を補完するために参照)
  • Go言語 crypto/tlsパッケージのドキュメント (GoのTLS実装に関する一般的な理解のために参照)
  • コミットに含まれるコード差分 (変更内容の直接的な分析)
  • Go言語のテストに関する一般的な知識 (テストコードの理解のために参照)