[インデックス 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
関数内で行われています。
-
NextCert:
ラベルの追加:for i := len(chain) - 1; i >= 0; i-- {
の直前にNextCert:
というラベルが追加されました。これはGo言語のgoto
ステートメントやcontinue
/break
ステートメントで特定のループにジャンプするために使用されるラベルです。 -
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
を持つ証明書が正しく解釈され、証明書チェーンの検証ロジックがより堅牢かつ正確になりました。
関連リンク
- Go Issue 6831: https://github.com/golang/go/issues/6831
- Go CL 40340043: https://golang.org/cl/40340043
参考にした情報源リンク
- RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile: https://datatracker.ietf.org/doc/html/rfc5280
- Go言語の
crypto/x509
パッケージのドキュメント: https://pkg.go.dev/crypto/x509 - Go言語の
continue
とラベルに関するドキュメント: https://go.dev/ref/spec#For_statements (Go言語の仕様書におけるfor
ステートメントのセクション) - X.509 Extended Key Usage OIDs: https://oid-info.com/get/2.5.29.37 (ExtKeyUsageAny の OID 情報)
- Go言語のソースコード: https://github.com/golang/go