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

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

このコミットは、Go言語の標準ライブラリ crypto/x509 パッケージ内の証明書検証ロジックにおける ExtKeyUsageAny の挙動を修正するものです。具体的には、証明書チェーンの検証時に ExtKeyUsageAny が適切に処理されず、誤った検証結果を招く可能性があったバグを修正しています。

コミット

commit ddbad5ef207709ef4fed07e1deba585428588c63
Author: Adam Langley <agl@golang.org>
Date:   Tue Dec 10 14:06:26 2013 -0500

    crypto/x509: fix behaviour of KeyUsageAny.
    
    (Reporter wasn't able to provide a certificate chain that uses this
    feature for testing.)
    
    Fixes #6831
    
    R=golang-dev, bradfitz, r
    CC=golang-dev
    https://golang.org/cl/40340043

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

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

元コミット内容

crypto/x509: fix behaviour of KeyUsageAny.

(Reporter wasn't able to provide a certificate chain that uses this feature for testing.)

Fixes #6831

変更の背景

このコミットは、Go言語の crypto/x509 パッケージにおける、X.509証明書の拡張鍵用途(Extended Key Usage: EKU)の検証に関するバグ修正です。特に ExtKeyUsageAny という特殊な値の取り扱いが問題となっていました。

X.509証明書は、公開鍵暗号の基盤となるデジタル証明書であり、通信の認証、データの完全性、否認防止などに広く利用されています。証明書には、その証明書がどのような目的で使用されるべきかを示す「鍵用途(Key Usage)」や「拡張鍵用途(Extended Key Usage)」といった情報が含まれています。

ExtKeyUsageAny は、RFC 5280 (Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile) で定義されている特別な拡張鍵用途で、その証明書が「任意の目的」で使用できることを示します。つまり、特定の用途に限定されない汎用的な証明書であることを意味します。

Goの crypto/x509 パッケージは、証明書チェーンの検証を行う際に、各証明書がその用途に適しているかをチェックします。このチェックロジックにおいて、ExtKeyUsageAny が含まれる証明書が正しく処理されず、証明書チェーン全体の検証が失敗する、あるいは意図しない結果になる可能性がありました。

コミットメッセージにある Fixes #6831 は、このバグがGoのIssueトラッカーで報告された問題(Issue 6831)を修正するものであることを示しています。このIssueでは、ExtKeyUsageAny を含む証明書が正しく検証されないという具体的な問題が指摘されていたと考えられます。

前提知識の解説

X.509 証明書と証明書チェーン

X.509証明書は、公開鍵とそれに対応するエンティティ(個人、サーバーなど)の識別情報を結びつけるデジタル文書です。認証局(CA)によって署名され、その正当性が保証されます。

証明書チェーンとは、エンドエンティティ証明書(例: Webサーバーの証明書)から始まり、中間CA証明書を介して、最終的に信頼されたルートCA証明書に至るまでの証明書の連なりを指します。クライアントは、このチェーンを辿って各証明書の署名を検証し、最終的にルートCAが信頼できるものであれば、エンドエンティティ証明書も信頼できると判断します。

鍵用途 (Key Usage) と拡張鍵用途 (Extended Key Usage: EKU)

  • 鍵用途 (Key Usage): 証明書の公開鍵がどのような暗号操作に使用できるかを示すビットマスクです。例えば、デジタル署名、鍵の暗号化、証明書の署名などに使われます。
  • 拡張鍵用途 (Extended Key Usage: EKU): 鍵用途をさらに細分化し、特定のアプリケーションやプロトコルにおける証明書の用途を定義します。例えば、TLS Webサーバー認証、TLS Webクライアント認証、コード署名、タイムスタンプなどがあります。EKUはOID (Object Identifier) で識別されます。

ExtKeyUsageAny

ExtKeyUsageAny は、拡張鍵用途の一つで、OID 2.5.29.37.0 に対応します。このOIDが存在する場合、その証明書は「任意の目的」で使用できることを意味します。これは、証明書が特定の用途に限定されず、汎用的に利用可能であることを示すために使用されます。

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

Go言語の標準ライブラリ crypto/x509 は、X.509証明書の解析、生成、検証などの機能を提供します。このパッケージは、TLS(Transport Layer Security)通信やその他のPKI(Public Key Infrastructure)関連のアプリケーションで広く利用されています。

証明書チェーンの検証は、crypto/x509 パッケージの重要な機能の一つです。この検証プロセスでは、各証明書の有効期限、署名、鍵用途、拡張鍵用途などがチェックされます。

技術的詳細

このコミットが修正しているのは、src/pkg/crypto/x509/verify.go ファイル内の checkChainForKeyUsage 関数です。この関数は、証明書チェーン内の各証明書が、指定された拡張鍵用途(keyUsages 引数)に対して有効であるかを検証する役割を担っています。

元のコードでは、証明書が ExtKeyUsageAny を含んでいる場合、内側のループ(for _, usage := range cert.ExtKeyUsage)で continue が実行されていました。これは、現在の証明書の他の拡張鍵用途のチェックをスキップし、次の拡張鍵用途のチェックに進むことを意味します。しかし、ExtKeyUsageAny が存在するということは、その証明書自体が任意の用途に使えるため、その証明書に対する残りの拡張鍵用途のチェックは不要であり、さらに言えば、その証明書がチェーンの検証において有効であると判断し、次の証明書(チェーンの次の要素)の検証に進むべきでした。

つまり、ExtKeyUsageAny が見つかった場合、その証明書は現在の keyUsages の要件を満たしていると見なされ、現在の証明書に対するループ全体を終了し、次の証明書に移るべきだったのです。

このバグにより、ExtKeyUsageAny を持つ証明書が正しく「任意の用途に使える」と認識されず、不必要な追加のチェックが行われたり、場合によっては誤って検証が失敗したりする可能性がありました。

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

--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -425,6 +425,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
 	// by each certificate. If we cross out all the usages, then the chain
 	// is unacceptable.
 
+NextCert:
 	for i := len(chain) - 1; i >= 0; i-- {
 		cert := chain[i]
 		if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
@@ -435,7 +436,7 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
 		for _, usage := range cert.ExtKeyUsage {
 			if usage == ExtKeyUsageAny {
 				// The certificate is explicitly good for any usage.
-				continue
+				continue NextCert
 			}
 		}
 

コアとなるコードの解説

変更は src/pkg/crypto/x509/verify.go ファイルの checkChainForKeyUsage 関数内で行われています。

  1. NextCert: ラベルの追加: for i := len(chain) - 1; i >= 0; i-- { の直前に NextCert: というラベルが追加されました。これはGo言語の goto ステートメントや continue / break ステートメントで特定のループにジャンプするために使用されるラベルです。

  2. continue から continue NextCert への変更: 元のコードでは、if usage == ExtKeyUsageAny { ... continue } となっていました。これは、現在の証明書が ExtKeyUsageAny を含んでいる場合、内側の for _, usage := range cert.ExtKeyUsage ループの次のイテレーションに進むことを意味していました。 修正後のコードでは、continue NextCert に変更されています。これにより、ExtKeyUsageAny が見つかった場合、内側のループをスキップするだけでなく、外側の for i := len(chain) - 1; i >= 0; i-- ループ(証明書チェーンを逆順に辿るループ)の次のイテレーションに直接ジャンプします。

この変更の意図は以下の通りです。 ExtKeyUsageAny は、その証明書が「任意の目的」で使用できることを示します。したがって、証明書が ExtKeyUsageAny を含んでいる場合、その証明書は、検証対象の keyUsages の要件を自動的に満たします。この場合、その証明書に対する残りの拡張鍵用途のチェックは不要であり、現在の証明書の検証を成功とみなし、証明書チェーンの次の証明書(NextCert ラベルが指す外側のループの次のイテレーション)に進むべきです。

この修正により、ExtKeyUsageAny を持つ証明書が正しく解釈され、証明書チェーンの検証ロジックがより堅牢かつ正確になりました。

関連リンク

参考にした情報源リンク