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

[インデックス 18569] ファイルの概要

このコミットは、Go言語のcrypto/x509およびcrypto/tlsパッケージに、カスタムルート証明書リストを使用する例を追加するものです。これにより、開発者はシステムデフォルトのルート証明書に依存せず、独自の信頼された証明書セットを用いてTLS接続や証明書の検証を行う方法を理解できます。

コミット

commit d4d77052b4d615d72a485fece53879c7c66f5a2a
Author: Adam Langley <agl@golang.org>
Date:   Wed Feb 19 11:18:35 2014 -0500

    crypto/x509: add example of using a custom root list.
    
    Fixes #6267.
    
    LGTM=r, josharian
    R=golang-codereviews, josharian, r
    CC=golang-codereviews
    https://golang.org/cl/61020043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/d4d77052b4d615d72a485fece53879c7c66f5a2a

元コミット内容

crypto/x509: add example of using a custom root list.

このコミットは、crypto/x509パッケージにカスタムルートリストを使用する例を追加します。また、関連するcrypto/tlsパッケージにも同様の例が追加されています。これは、Go言語のTLSクライアントが、オペレーティングシステムが提供するデフォルトの信頼されたルート証明書ストアではなく、アプリケーション固有の信頼されたルート証明書セットを使用してサーバー証明書を検証する方法を示すものです。

変更の背景

TLS(Transport Layer Security)接続において、クライアントはサーバーから提示された証明書が信頼できる認証局(CA)によって署名されていることを検証する必要があります。通常、Goを含む多くのシステムでは、オペレーティングシステムが管理する信頼されたルート証明書ストアがこの検証に使用されます。しかし、特定のユースケースでは、システムデフォルトのルート証明書ストアではなく、アプリケーションが独自に管理する信頼されたルート証明書リストを使用したい場合があります。

例えば、以下のようなシナリオが考えられます。

  • プライベートなPKI(公開鍵基盤): 企業内部のシステムやプライベートネットワーク内で、独自の認証局を運用している場合。これらのCAによって発行された証明書は、パブリックなルート証明書ストアには含まれないため、カスタムルートリストが必要になります。
  • テスト環境: 開発やテストのために自己署名証明書やテスト用のCA証明書を使用する場合。
  • セキュリティ要件: 特定のセキュリティポリシーにより、信頼するCAを厳密に制御したい場合。
  • クロスプラットフォームの一貫性: 異なるOS間でTLSの信頼設定の一貫性を保ちたい場合。

このコミットは、このようなカスタムルートリストの利用方法を開発者に示すための具体的なコード例を提供することで、Go言語のTLS機能の柔軟性と使いやすさを向上させることを目的としています。コミットメッセージにあるFixes #6267は、この機能に関する既存の課題や要望に対応するものであることを示唆していますが、Goの公開リポジトリでは該当するIssueが見つかりませんでした。これは、内部的なトラッキング番号であるか、あるいは非常に古いIssueである可能性があります。

前提知識の解説

このコミットの変更内容を理解するためには、以下の前提知識が必要です。

1. TLS/SSLの基本

  • TLS (Transport Layer Security): インターネット上でデータを安全にやり取りするための暗号化プロトコル。以前はSSL (Secure Sockets Layer) と呼ばれていました。
  • 証明書 (Certificate): 公開鍵と、その公開鍵の所有者情報を結びつけるデジタル文書。認証局 (CA) によって署名され、信頼性を保証します。
  • 認証局 (CA - Certificate Authority): デジタル証明書を発行し、その信頼性を保証する第三者機関。
  • ルート証明書 (Root Certificate): 認証局の階層構造の最上位にある自己署名証明書。これが信頼されていれば、そのルート証明書によって署名された中間CA証明書、そして最終的なサーバー証明書も信頼できると見なされます。
  • 証明書チェーン (Certificate Chain): サーバー証明書から始まり、中間CA証明書を経て、最終的に信頼されたルート証明書に至るまでの証明書の連なり。
  • 証明書検証 (Certificate Validation): クライアントがサーバーから受け取った証明書が、信頼されたルート証明書にまで遡って有効であることを確認するプロセス。これには、署名の検証、有効期限の確認、ホスト名の照合などが含まれます。

2. PEM形式

  • PEM (Privacy-Enhanced Mail): 暗号化されたデータをASCII形式で表現するための標準的なエンコーディング形式。証明書や秘密鍵などをテキストファイルとして保存する際によく用いられます。-----BEGIN CERTIFICATE----------END CERTIFICATE-----のようなヘッダーとフッターで囲まれたBase64エンコードされたデータが特徴です。

3. Go言語のcrypto/tlscrypto/x509パッケージ

  • crypto/tls: TLSプロトコルを実装するためのGo標準ライブラリ。クライアントとサーバーの両方でTLS接続を確立するために使用されます。tls.Config構造体を通じて、TLS接続の様々な設定(証明書、鍵、ルートCA、プロトコルバージョンなど)をカスタマイズできます。
  • crypto/x509: X.509証明書とPKIX (Public Key Infrastructure X.509) を扱うためのGo標準ライブラリ。証明書のパース、検証、証明書プール(x509.CertPool)の管理などを行います。

4. x509.CertPool

  • x509.CertPoolは、信頼されたルート証明書の集合を管理するためのGoのデータ構造です。このプールに証明書を追加し、TLS接続の際にtls.ConfigRootCAsフィールドに設定することで、システムデフォルトのルート証明書ストアに加えて、または代わりに、独自の信頼されたCAリストを使用できます。

技術的詳細

このコミットは、crypto/tlscrypto/x509パッケージにそれぞれExampleDialExampleCertificate_Verifyという新しいテストファイル(example_test.go)を追加しています。これらのファイルは、GoのテストフレームワークのExample機能を利用しており、ドキュメントとして機能すると同時に、実際のコードとして実行・検証可能です。

crypto/tls/example_test.goの変更点

このファイルでは、tls.Dial関数を使用してTLS接続を確立する際に、カスタムのルート証明書リストをtls.Configに設定する方法が示されています。

  1. PEM形式のルート証明書: rootPEMという定数で、PEM形式のルート証明書が文字列として定義されています。この例では、Google Internet Authority G2の証明書が使用されています。
  2. x509.NewCertPool(): 新しい空の証明書プールを作成します。
  3. roots.AppendCertsFromPEM([]byte(rootPEM)): 定義されたPEM形式のルート証明書をバイトスライスに変換し、AppendCertsFromPEMメソッドを使って証明書プールに追加します。このメソッドは、PEMブロックから複数の証明書をパースしてプールに追加できます。
  4. エラーハンドリング: 証明書のパースに失敗した場合のパニック処理が含まれています。
  5. tls.Configの作成: tls.Config構造体を作成し、そのRootCAsフィールドに作成したroots(カスタム証明書プール)を設定します。
  6. tls.Dialによる接続: tls.Dial("tcp", "mail.google.com:443", &tls.Config{RootCAs: roots})を呼び出し、指定されたホストとポートにTLS接続を試みます。この際、サーバー証明書の検証には、システムデフォルトのCAに加えて(または代わりに)、RootCAsで指定されたカスタムプールが使用されます。
  7. 接続のクローズ: 確立された接続はすぐにクローズされます。

この例は、クライアントが特定のCAのみを信頼してTLS接続を行いたい場合に非常に有用です。

crypto/x509/example_test.goの変更点

このファイルでは、既存の証明書をカスタムのルート証明書リストに対して検証する方法が示されています。これは、TLS接続時だけでなく、任意のX.509証明書の検証ロジックをテストする際に役立ちます。

  1. PEM形式のルート証明書と検証対象証明書: rootPEMcertPEMという定数で、それぞれPEM形式のルート証明書と検証対象のサーバー証明書が文字列として定義されています。
  2. ルート証明書プールの作成: crypto/tlsの例と同様に、rootPEMからx509.CertPoolを作成します。
  3. 検証対象証明書のパース:
    • pem.Decode([]byte(certPEM)): certPEMからPEMブロックをデコードします。
    • x509.ParseCertificate(block.Bytes): デコードされたバイトスライスからX.509証明書をパースします。
  4. x509.VerifyOptionsの作成:
    • x509.VerifyOptions構造体を作成し、証明書検証のオプションを設定します。
    • DNSName: "mail.google.com": 検証対象の証明書がこのDNS名に対して有効であることを確認します。これは、証明書のSubject Alternative Name (SAN) またはCommon Name (CN) フィールドと照合されます。
    • Roots: roots: 作成したカスタムルート証明書プールを検証オプションに設定します。
  5. cert.Verify(opts)による検証: パースした証明書オブジェクトのVerifyメソッドを呼び出し、指定されたオプション(カスタムルートCAとDNS名)に基づいて証明書を検証します。
  6. エラーハンドリング: 検証に失敗した場合のパニック処理が含まれています。

この例は、特定の証明書が特定の信頼されたCAによって発行され、かつ特定のホスト名に対して有効であるかをプログラム的に確認するシナリオに適用できます。

コアとなるコードの変更箇所

このコミットは、既存のコードを変更するのではなく、新しいテストファイルを追加しています。

  • src/pkg/crypto/tls/example_test.go: 新規追加
  • src/pkg/crypto/x509/example_test.go: 新規追加

これらのファイルは、GoのExampleテストの慣習に従い、Exampleプレフィックスを持つ関数を含んでいます。これにより、go docコマンドでドキュメントとして表示され、go testコマンドで自動的に実行・検証されます。

コアとなるコードの解説

src/pkg/crypto/tls/example_test.go

package tls_test

import (
	"crypto/tls"
	"crypto/x509"
)

func ExampleDial() {
	// Connecting with a custom root-certificate set.

	const rootPEM = `
-----BEGIN CERTIFICATE-----
... (PEM encoded root certificate) ...
-----END CERTIFICATE-----`

	// First, create the set of root certificates. For this example we only
	// have one. It's also possible to omit this in order to use the
	// default root set of the current operating system.
	roots := x509.NewCertPool()
	ok := roots.AppendCertsFromPEM([]byte(rootPEM))
	if !ok {
		panic("failed to parse root certificate")
	}

	conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{
		RootCAs: roots,
	})
	if err != nil {
		panic("failed to connect: " + err.Error())
	}
	conn.Close()
}

このコードは、tls.Config構造体のRootCAsフィールドにx509.CertPoolインスタンスを設定することで、カスタムのルート証明書リストを使用する方法を示しています。tls.Dialは、この設定に基づいてTLSハンドシェイクを行い、サーバー証明書を検証します。

src/pkg/crypto/x509/example_test.go

package x509_test

import (
	"crypto/x509"
	"encoding/pem"
)

func ExampleCertificate_Verify() {
	// Verifying with a custom list of root certificates.

	const rootPEM = `
-----BEGIN CERTIFICATE-----
... (PEM encoded root certificate) ...
-----END CERTIFICATE-----`

	const certPEM = `
-----BEGIN CERTIFICATE-----
... (PEM encoded server certificate) ...
-----END CERTIFICATE-----`

	// First, create the set of root certificates. For this example we only
	// have one. It's also possible to omit this in order to use the
	// default root set of the current operating system.
	roots := x509.NewCertPool()
	ok := roots.AppendCertsFromPEM([]byte(rootPEM))
	if !ok {
		panic("failed to parse root certificate")
	}

	block, _ := pem.Decode([]byte(certPEM))
	if block == nil {
		panic("failed to parse certificate PEM")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		panic("failed to parse certificate: " + err.Error())
	}

	opts := x509.VerifyOptions{
		DNSName: "mail.google.com",
		Roots:   roots,
	}

	if _, err := cert.Verify(opts); err != nil {
		panic("failed to verify certificate: " + err.Error())
	}
}

このコードは、x509.CertificateVerifyメソッドにx509.VerifyOptions構造体を渡すことで、カスタムのルート証明書プールと特定のDNS名に対する証明書の検証を行う方法を示しています。VerifyOptionsRootsフィールドにカスタムプールを設定することで、検証プロセスがそのプール内のCA証明書を信頼のアンカーとして使用するようになります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • TLS/SSLおよびX.509証明書に関する一般的な知識
  • PEMエンコーディングに関する情報
  • GitHubのコミット履歴
  • Go言語のIssueトラッカー (ただし、#6267は特定できず)