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

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

このコミットは、Go言語の標準ライブラリ crypto/x509 における証明書検証テスト SCG test を、システム検証(特にWindowsのCryptoAPIを使用する場合)において無効化する変更です。Windows環境でCryptoAPIが代替の検証パスを見つけることがあり、その挙動が非決定論的であるため、テストの信頼性を確保するために特定のテストケースをスキップするように修正されました。

コミット

commit e0791a3adfd7d42ef3f5b6b208156a2ee085b5cf
Author: Adam Langley <agl@golang.org>
Date:   Sat Feb 9 13:51:39 2013 -0500

    crypto/x509: disable SCG test with system validation.
    
    On Windows, CryptoAPI is finding an alternative validation path. Since
    this is a little non-deterministic, this change disables that test
    when using system validation.
    
    R=golang-dev
    CC=golang-dev
    https://golang.org/cl/7313068

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

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

元コミット内容

crypto/x509: disable SCG test with system validation.

On Windows, CryptoAPI is finding an alternative validation path. Since
this is a little non-deterministic, this change disables that test
when using system validation.

R=golang-dev
CC=golang-dev
https://golang.org/cl/7313068

変更の背景

この変更の背景には、Go言語の crypto/x509 パッケージが提供する証明書検証機能のテストにおける、特定のプラットフォーム(Windows)での挙動の不確実性があります。

Goの crypto/x509 パッケージは、X.509証明書の解析、検証、および管理を行うための機能を提供します。証明書の検証は、その証明書が信頼できる認証局(CA)によって発行され、有効期限内であり、失効していないことなどを確認するプロセスです。この検証プロセスは、セキュリティ上非常に重要であり、TLS/SSL通信などで広く利用されます。

通常、Goの crypto/x509 は独自の検証ロジックを持っていますが、一部のプラットフォームでは、システムの提供する証明書検証メカニズム(システム検証)を利用することがあります。Windowsの場合、これはCryptoAPI(Cryptographic Application Programming Interface)を指します。

問題は、WindowsのCryptoAPIが、Goのテストが期待する検証パスとは異なる「代替の検証パス」を見つけることがある点にありました。証明書の検証パスとは、エンドエンティティ証明書から信頼されたルート証明書までの証明書の連鎖(チェーン)のことです。CryptoAPIが異なるパスを構築することがあるため、Goのテストが期待する結果と実際の検証結果が一致しない、つまりテストが非決定論的(実行するたびに結果が変わる可能性がある)になるという問題が発生しました。

このような非決定論的なテストは、CI/CDパイプラインや開発者のローカル環境でのテストの信頼性を損ないます。テストが不安定であると、実際のバグではないのにテストが失敗したり、逆にバグを見逃したりする可能性があります。この問題を解決し、テストスイートの安定性を向上させるために、特定のテストケース(SCG test)をWindowsのシステム検証時にスキップする変更が導入されました。

前提知識の解説

X.509 証明書と証明書検証

X.509は、公開鍵証明書の標準フォーマットです。インターネット上のエンティティ(ウェブサイト、サーバー、個人など)の公開鍵を識別し、その公開鍵が特定のエンティティに属することを証明するために使用されます。X.509証明書は、TLS/SSL通信、コード署名、電子メールの暗号化など、様々なセキュリティプロトコルで利用されます。

証明書検証(Certificate Validation)は、与えられたX.509証明書が有効で信頼できるものであることを確認するプロセスです。このプロセスには以下の要素が含まれます。

  1. 証明書チェーンの構築: エンドエンティティ証明書から始まり、中間認証局(Intermediate CA)証明書を介して、最終的に信頼されたルート認証局(Root CA)証明書に至るまでの証明書の連鎖を構築します。
  2. 署名の検証: チェーン内の各証明書が、その上位の証明書によって正しく署名されていることを確認します。
  3. 有効期限の確認: 各証明書が有効期限内であることを確認します。
  4. 失効状態の確認: 証明書が失効リスト(CRL)やOCSP(Online Certificate Status Protocol)を通じて失効していないことを確認します。
  5. 名前の制約とポリシーの確認: 証明書に記述された名前の制約やポリシーが満たされているかを確認します。

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

Go言語の標準ライブラリ crypto/x509 は、X.509証明書とPKIX(Public Key Infrastructure X.509)の基本的な実装を提供します。このパッケージは、証明書のパース、検証、証明書プール(信頼されたルート証明書の集合)の管理などの機能を提供します。

Windows CryptoAPI

Windows CryptoAPI(Cryptographic Application Programming Interface)は、Microsoft Windowsオペレーティングシステムが提供する暗号化サービスフレームワークです。これには、証明書の管理、暗号化、ハッシュ、デジタル署名などの機能が含まれます。Windowsアプリケーションは、CryptoAPIを利用してセキュリティ関連の操作を実行します。

特に証明書検証においては、CryptoAPIはWindowsの証明書ストアに保存されている信頼されたルート証明書や中間証明書を利用して、証明書チェーンの構築と検証を行います。CryptoAPIは、証明書のパス構築において、様々なヒューリスティックや設定に基づいて代替パスを探索する能力を持つことがあります。これが、Goのテストが期待する厳密なパスと異なる結果を生む原因となることがあります。

verify_test.goverifyTests

verify_test.go は、crypto/x509 パッケージの証明書検証機能に対する単体テストを定義するファイルです。このファイルには、様々な証明書チェーン、有効期限、失効状態などをシミュレートしたテストケースが含まれています。

verifyTests は、これらのテストケースを構造体として定義したスライス(配列)です。各 verifyTest 構造体は、テスト対象の証明書、信頼するルート証明書、現在の時刻、期待される証明書チェーンなどの情報を含んでいます。

systemSkip フラグ

このコミットで導入された systemSkip は、verifyTest 構造体に追加された新しいフィールド(または既存のフィールドの利用方法の変更)であり、特定のテストケースをシステム検証時にスキップするかどうかを制御するためのものです。systemSkip: true と設定されたテストケースは、Goがシステムの証明書検証メカニズム(例: WindowsのCryptoAPI)を使用している場合に実行されなくなります。これにより、プラットフォーム固有の非決定論的な挙動によるテストの失敗を回避し、テストスイートの安定性を保つことができます。

技術的詳細

このコミットの技術的詳細の中心は、crypto/x509 パッケージのテストフレームワークにおける systemSkip フラグの導入と、それがWindows環境での証明書検証の非決定論的な挙動にどのように対処するかという点です。

Goの crypto/x509 パッケージは、証明書検証の際に、Go自身の純粋なGoコードによる実装と、OSが提供するネイティブな検証機能(システム検証)の両方を使用する可能性があります。特にWindowsでは、GoはCryptoAPIを利用して証明書検証を行うことがあります。

コミットメッセージにある「CryptoAPI is finding an alternative validation path」とは、CryptoAPIが、Goのテストケースが想定している証明書チェーンとは異なる、しかしCryptoAPIの観点からは有効な別の証明書チェーンを構築してしまう状況を指します。これは、CryptoAPIが証明書ストア内の利用可能な証明書を探索し、複数の有効なパスが存在する場合に、Goのテストが期待する特定のパスとは異なるパスを選択する可能性があるためです。

例えば、ある証明書が複数の異なる中間CAによって署名されている場合や、同じCAが異なる証明書を発行している場合、CryptoAPIはGoのテストが意図しないパスを構築する可能性があります。Goのテストは通常、特定の入力に対して特定の出力(この場合は特定の証明書チェーン)を期待するように設計されています。しかし、CryptoAPIのこの「代替パス探索」の挙動は、テストの期待値と実際の検証結果との間に不一致を生じさせ、テストが不安定になる原因となります。

この問題を解決するために、verify_test.go 内の verifyTest 構造体に systemSkip というフィールドが追加されました(または、既存のフィールドがそのように解釈されるようになりました)。このフィールドが true に設定されている場合、そのテストケースは、Goがシステム検証(x509.SystemRoots を使用する検証)を行っている環境では実行されません。

具体的には、src/pkg/crypto/x509/verify_test.goverifyTests スライス内の特定のテストケース(このコミットでは mega.co.nz の証明書検証テスト)に systemSkip: true, が追加されました。これにより、WindowsなどのCryptoAPIを使用する環境でこのテストが実行されるのを防ぎ、テストスイート全体の安定性を向上させています。

このアプローチは、問題の根本的な解決(CryptoAPIの挙動をGoのテストの期待値に合わせる)ではなく、問題のあるテストケースを一時的に回避するものです。これは、テストの信頼性を迅速に確保するための実用的な解決策として採用されました。

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

diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index bb0587e2f6..5103ed814a 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -164,6 +164,9 @@ var verifyTests = []verifyTest{
 		roots:         []string{comodoRoot},
 		currentTime:   1360431182,

+		// CryptoAPI can find alternative validation paths so we don\'t
+		// perform this test with system validation.
+		systemSkip: true,
 		expectedChains: [][]string{
 			{"mega.co.nz", "EssentialSSL CA", "COMODO Certification Authority"},
 		},

コアとなるコードの解説

変更は src/pkg/crypto/x509/verify_test.go ファイル内の verifyTests という変数に定義されているテストケースの一つに対して行われています。

具体的には、mega.co.nz の証明書検証に関するテストケースに、以下の3行が追加されました。

		// CryptoAPI can find alternative validation paths so we don't
		// perform this test with system validation.
		systemSkip: true,
  1. コメント行: // CryptoAPI can find alternative validation paths so we don't // perform this test with system validation. これらのコメントは、この変更の理由を明確に説明しています。「CryptoAPIが代替の検証パスを見つける可能性があるため、システム検証時にはこのテストを実行しない」という意図が示されています。これは、前述の「変更の背景」と「技術的詳細」で説明した問題点を直接的に指しています。

  2. systemSkip: true,: この行が、実際のテストスキップのロジックを有効にする部分です。verifyTest 構造体(verifyTests スライスを構成する要素の型)には、systemSkip というブール型のフィールドが存在するか、またはこのフィールドがテストランナーによって特別に解釈されるようになっています。true に設定することで、テストランナーは、現在のGoの実行環境がシステムの証明書検証メカニズム(特にWindowsのCryptoAPI)を使用している場合に、この特定のテストケースをスキップするようになります。

この変更により、mega.co.nz の証明書検証テストは、Windows環境でCryptoAPIが使用される際に、非決定論的な失敗を引き起こすことなく、安定してテストスイートを通過できるようになります。これは、テストの信頼性を向上させるための実用的な回避策です。

関連リンク

参考にした情報源リンク

  • Go言語の crypto/x509 パッケージのドキュメント (Goの公式ドキュメント)
  • X.509 証明書に関する一般的な情報 (RFC 5280 など)
  • Windows CryptoAPI に関する一般的な情報 (Microsoft Learn ドキュメントなど)
  • Go言語のテストフレームワークに関する一般的な知識
  • コミットメッセージと差分情報