[インデックス 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/tls
とcrypto/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.Config
のRootCAs
フィールドに設定することで、システムデフォルトのルート証明書ストアに加えて、または代わりに、独自の信頼されたCAリストを使用できます。
技術的詳細
このコミットは、crypto/tls
とcrypto/x509
パッケージにそれぞれExampleDial
とExampleCertificate_Verify
という新しいテストファイル(example_test.go
)を追加しています。これらのファイルは、GoのテストフレームワークのExample機能を利用しており、ドキュメントとして機能すると同時に、実際のコードとして実行・検証可能です。
crypto/tls/example_test.go
の変更点
このファイルでは、tls.Dial
関数を使用してTLS接続を確立する際に、カスタムのルート証明書リストをtls.Config
に設定する方法が示されています。
- PEM形式のルート証明書:
rootPEM
という定数で、PEM形式のルート証明書が文字列として定義されています。この例では、Google Internet Authority G2の証明書が使用されています。 x509.NewCertPool()
: 新しい空の証明書プールを作成します。roots.AppendCertsFromPEM([]byte(rootPEM))
: 定義されたPEM形式のルート証明書をバイトスライスに変換し、AppendCertsFromPEM
メソッドを使って証明書プールに追加します。このメソッドは、PEMブロックから複数の証明書をパースしてプールに追加できます。- エラーハンドリング: 証明書のパースに失敗した場合のパニック処理が含まれています。
tls.Config
の作成:tls.Config
構造体を作成し、そのRootCAs
フィールドに作成したroots
(カスタム証明書プール)を設定します。tls.Dial
による接続:tls.Dial("tcp", "mail.google.com:443", &tls.Config{RootCAs: roots})
を呼び出し、指定されたホストとポートにTLS接続を試みます。この際、サーバー証明書の検証には、システムデフォルトのCAに加えて(または代わりに)、RootCAs
で指定されたカスタムプールが使用されます。- 接続のクローズ: 確立された接続はすぐにクローズされます。
この例は、クライアントが特定のCAのみを信頼してTLS接続を行いたい場合に非常に有用です。
crypto/x509/example_test.go
の変更点
このファイルでは、既存の証明書をカスタムのルート証明書リストに対して検証する方法が示されています。これは、TLS接続時だけでなく、任意のX.509証明書の検証ロジックをテストする際に役立ちます。
- PEM形式のルート証明書と検証対象証明書:
rootPEM
とcertPEM
という定数で、それぞれPEM形式のルート証明書と検証対象のサーバー証明書が文字列として定義されています。 - ルート証明書プールの作成:
crypto/tls
の例と同様に、rootPEM
からx509.CertPool
を作成します。 - 検証対象証明書のパース:
pem.Decode([]byte(certPEM))
:certPEM
からPEMブロックをデコードします。x509.ParseCertificate(block.Bytes)
: デコードされたバイトスライスからX.509証明書をパースします。
x509.VerifyOptions
の作成:x509.VerifyOptions
構造体を作成し、証明書検証のオプションを設定します。DNSName: "mail.google.com"
: 検証対象の証明書がこのDNS名に対して有効であることを確認します。これは、証明書のSubject Alternative Name (SAN) またはCommon Name (CN) フィールドと照合されます。Roots: roots
: 作成したカスタムルート証明書プールを検証オプションに設定します。
cert.Verify(opts)
による検証: パースした証明書オブジェクトのVerify
メソッドを呼び出し、指定されたオプション(カスタムルートCAとDNS名)に基づいて証明書を検証します。- エラーハンドリング: 検証に失敗した場合のパニック処理が含まれています。
この例は、特定の証明書が特定の信頼された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.Certificate
のVerify
メソッドにx509.VerifyOptions
構造体を渡すことで、カスタムのルート証明書プールと特定のDNS名に対する証明書の検証を行う方法を示しています。VerifyOptions
のRoots
フィールドにカスタムプールを設定することで、検証プロセスがそのプール内のCA証明書を信頼のアンカーとして使用するようになります。
関連リンク
- Go言語
crypto/tls
パッケージドキュメント: https://pkg.go.dev/crypto/tls - Go言語
crypto/x509
パッケージドキュメント: https://pkg.go.dev/crypto/x509 - Go言語のExampleテストについて: https://go.dev/blog/examples
参考にした情報源リンク
- Go言語の公式ドキュメント
- TLS/SSLおよびX.509証明書に関する一般的な知識
- PEMエンコーディングに関する情報
- GitHubのコミット履歴
- Go言語のIssueトラッカー (ただし、#6267は特定できず)