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

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

このコミットは、Go言語のcrypto/x509パッケージにおける証明書検証ロジックの変更に関するものです。具体的には、Microsoft (MS) および Netscape (NS) のServer Gated Cryptography (SGC) 拡張鍵用途(Extended Key Usage: EKU)を、標準的なServer Authentication (ServerAuth) 鍵用途と同等として扱うように修正しています。これにより、特定の証明書チェーン(特にCOMODOが発行したもの)の検証が正しく行われるようになります。

変更されたファイルは以下の通りです。

  • src/pkg/crypto/x509/verify.go: 証明書チェーンの鍵用途を検証する主要なロジックが変更されました。
  • src/pkg/crypto/x509/verify_test.go: 新しい検証ロジックをテストするためのコードが追加されました。特にCOMODOの証明書チェーンを検証するテストケースが含まれています。
  • src/pkg/crypto/x509/x509.go: Microsoft SGCおよびNetscape SGCの拡張鍵用途に対応するオブジェクト識別子(OID)と定数が追加されました。

コミット

commit e1c309e79251a07ba9a84567aff302fa51815ced
Author: Adam Langley <agl@golang.org>
Date:   Sat Feb 9 13:20:25 2013 -0500

    crypto/x509: allow MS/NS SCG key usage as ServerAuth.
    
    By default, crypto/x509 assumes that users wish to validate
    certificates for ServerAuth. However, due to historical reasons,
    COMODO's intermediates don't specify ServerAuth as an allowed key
    usage.
    
    Rather NSS and CryptoAPI both allow these SGC OIDs to be equivalent to
    ServerAuth.
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/7312070

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

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

元コミット内容

crypto/x509: allow MS/NS SCG key usage as ServerAuth.

By default, crypto/x509 assumes that users wish to validate
certificates for ServerAuth. However, due to historical reasons,
COMODO's intermediates don't specify ServerAuth as an allowed key
usage.

Rather NSS and CryptoAPI both allow these SGC OIDs to be equivalent to
ServerAuth.

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

変更の背景

この変更の背景には、X.509証明書の「拡張鍵用途(Extended Key Usage: EKU)」フィールドの解釈に関する歴史的な経緯と、特定の認証局(CA)が発行する証明書の互換性の問題があります。

Go言語のcrypto/x509パッケージは、デフォルトでサーバー認証(ServerAuth)のために証明書を検証することを想定しています。ServerAuthは、ウェブサーバーが自身の身元をクライアントに証明するために使用される最も一般的なEKUです。しかし、過去には、一部の認証局(特にCOMODO)が発行する中間証明書が、ServerAuth EKUを明示的に含んでいないケースがありました。

これは、かつて存在した「Server Gated Cryptography (SGC)」という技術に起因します。SGCは、古いブラウザがより強力な暗号化(例えば128ビット)を使用できるようにするためのもので、特定のSGC関連のEKU(Microsoft SGCやNetscape SGC)が証明書に埋め込まれていました。これらのSGC EKUは、実質的にサーバー認証の目的で使用されることが多かったにもかかわらず、ServerAuth EKUとは異なるOID(Object Identifier)を持っていました。

主要なブラウザやOSのセキュリティライブラリ(例えばMozillaのNSSやMicrosoftのCryptoAPI)は、これらのSGC OIDをServerAuthと同等として扱うことで、古い証明書との互換性を維持していました。しかし、Goのcrypto/x509パッケージは、この互換性ロジックを当初持っていなかったため、COMODOなどSGC関連のEKUを持つ中間証明書を使用するサイトの検証に失敗する可能性がありました。

このコミットは、Goのcrypto/x509パッケージが、NSSやCryptoAPIと同様に、Microsoft SGCおよびNetscape SGCのEKUをServerAuthとして認識するようにすることで、このような互換性の問題を解決し、より広範な証明書チェーンの検証を可能にすることを目的としています。

前提知識の解説

X.509 証明書

X.509は、公開鍵証明書の標準フォーマットです。インターネット上のエンティティ(ウェブサイト、個人、組織など)の公開鍵と身元情報を関連付け、その情報を信頼できる第三者(認証局: CA)が署名することで、公開鍵の正当性を保証します。X.509証明書には、所有者の公開鍵、所有者の識別情報、発行者の識別情報、有効期間、発行者のデジタル署名など、様々な情報が含まれています。

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

X.509証明書には、その証明書に含まれる公開鍵がどのような目的で使用されるべきかを指定するフィールドがあります。

  • 鍵用途 (Key Usage): 証明書の公開鍵の基本的な用途を定義します。例えば、デジタル署名、鍵の暗号化、証明書署名などがあります。
  • 拡張鍵用途 (Extended Key Usage: EKU): 鍵用途をさらに細分化し、特定のアプリケーションやプロトコルにおける鍵の用途を定義します。各EKUは一意のオブジェクト識別子(OID)で識別されます。

このコミットで特に重要なEKUは以下の通りです。

  • Server Authentication (ServerAuth): OIDは 1.3.6.1.5.5.7.3.1。ウェブサーバーがクライアントに対して自身の身元を証明するために使用されます。HTTPS通信において、サーバー証明書がこのEKUを持つことが一般的です。
  • Server Gated Cryptography (SGC): かつて存在した技術で、古いブラウザがより強力な暗号化(例えば40ビットから128ビットへのアップグレード)を強制するために使用されました。SGCは、特定のEKU OIDによって識別されます。
    • Microsoft Server Gated Cryptography: OIDは 1.3.6.1.4.1.311.10.3.3
    • Netscape Server Gated Cryptography: OIDは 2.16.840.1.113730.4.1。 SGCは現在ではほとんど使用されていませんが、過去に発行された証明書チェーンにはこれらのEKUが含まれている場合があります。

オブジェクト識別子 (Object Identifier: OID)

OIDは、ASN.1(Abstract Syntax Notation One)で定義されたオブジェクトを一意に識別するための数値の階層構造です。X.509証明書では、EKU、アルゴリズム、ポリシーなど、様々な要素を識別するために使用されます。

認証局 (Certificate Authority: CA)

CAは、デジタル証明書を発行し、管理する信頼された第三者機関です。CAは、証明書要求者の身元を確認し、その情報を含む証明書にデジタル署名を行います。これにより、証明書の信頼性が保証されます。COMODO(現在のSectigo)は、世界的に有名な認証局の一つです。

NSS (Network Security Services)

NSSは、Mozillaによって開発された、クロスプラットフォームの暗号化ライブラリのセットです。FirefoxブラウザやThunderbirdメールクライアントなど、多くのアプリケーションでセキュリティ機能(SSL/TLS、X.509証明書処理など)を提供するために使用されています。

CryptoAPI

CryptoAPIは、Microsoft Windowsオペレーティングシステムに組み込まれている暗号化サービスプロバイダ(CSP)のフレームワークです。アプリケーションが暗号化、復号化、デジタル署名、ハッシュなどの暗号操作を実行するためのAPIを提供します。

技術的詳細

このコミットは、Go言語のcrypto/x509パッケージにおける証明書チェーン検証ロジックを拡張し、特定のSGC関連のEKUをServerAuthとして許容するように変更しています。

  1. 新しいEKU定数の追加: src/pkg/crypto/x509/x509.goファイルに、Microsoft SGCとNetscape SGCに対応する新しいExtKeyUsage定数と、それらのOIDが追加されました。これにより、GoのX.509パッケージがこれらの特定のEKUを認識できるようになります。

  2. 検証ロジックの変更: src/pkg/crypto/x509/verify.goファイルのcheckChainForKeyUsage関数が修正されました。この関数は、証明書チェーン内の各証明書が要求された鍵用途(この場合はServerAuth)を満たしているかを検証します。 変更点として、もし要求された鍵用途がExtKeyUsageServerAuthであり、かつ証明書がExtKeyUsageNetscapeServerGatedCryptoまたはExtKeyUsageMicrosoftServerGatedCryptoのいずれかのEKUを含んでいる場合、その証明書はServerAuthの要件を満たしていると見なされるようになりました。これは、コメントにもあるように「COMODO証明書チェーンをサポートするため」であり、NSSやCryptoAPIの振る舞いに合わせています。

  3. テストケースの追加: src/pkg/crypto/x509/verify_test.goファイルに、新しい検証ロジックを検証するためのテストケースが追加されました。具体的には、COMODOが発行した中間証明書を含む証明書チェーン(megaLeafcomodoIntermediate1comodoRoot)が、ServerAuth目的で正しく検証されることを確認するテストが追加されています。これにより、変更が意図通りに機能し、既存の互換性問題を解決することが保証されます。

この変更により、Goアプリケーションは、SGC関連のEKUを持つ古い証明書チェーンに対しても、より堅牢な検証を行うことができるようになり、特にCOMODOのようなCAが発行した証明書を使用するシステムとの互換性が向上します。

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

src/pkg/crypto/x509/verify.go

--- a/src/pkg/crypto/x509/verify.go
+++ b/src/pkg/crypto/x509/verify.go
@@ -389,6 +389,14 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
 			for _, usage := range cert.ExtKeyUsage {
 				if requestedUsage == usage {
 					continue NextRequestedUsage
+				} else if requestedUsage == ExtKeyUsageServerAuth &&
+					(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
+						usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
+					// In order to support COMODO
+					// certificate chains, we have to
+					// accept Netscape or Microsoft SGC
+					// usages as equal to ServerAuth.
+					continue NextRequestedUsage
 				}
 			}
 

src/pkg/crypto/x509/x509.go

--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -360,16 +360,18 @@ const (
 // id-kp-timeStamping           OBJECT IDENTIFIER ::= { id-kp 8 }
 // id-kp-OCSPSigning            OBJECT IDENTIFIER ::= { id-kp 9 }
 var (
-	oidExtKeyUsageAny             = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
-	oidExtKeyUsageServerAuth      = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
-	oidExtKeyUsageClientAuth      = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
-	oidExtKeyUsageCodeSigning     = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
-	oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
-	oidExtKeyUsageIPSECEndSystem  = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
-	oidExtKeyUsageIPSECTunnel     = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
-	oidExtKeyUsageIPSECUser       = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
-	oidExtKeyUsageTimeStamping    = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
-	oidExtKeyUsageOCSPSigning     = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+	oidExtKeyUsageAny                        = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
+	oidExtKeyUsageServerAuth                 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
+	oidExtKeyUsageClientAuth                 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
+	oidExtKeyUsageCodeSigning                = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
+	oidExtKeyUsageEmailProtection            = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
+	oidExtKeyUsageIPSECEndSystem             = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
+	oidExtKeyUsageIPSECTunnel                = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
+	oidExtKeyUsageIPSECUser                  = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
+	oidExtKeyUsageTimeStamping               = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
+	oidExtKeyUsageOCSPSigning                = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+	oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
+	oidExtKeyUsageNetscapeServerGatedCrypto  = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
 )
 
 // ExtKeyUsage represents an extended set of actions that are valid for a given key.
@@ -387,6 +389,8 @@ const (
 	ExtKeyUsageIPSECUser
 	ExtKeyUsageTimeStamping
 	ExtKeyUsageOCSPSigning
+	ExtKeyUsageMicrosoftServerGatedCrypto
+	ExtKeyUsageNetscapeServerGatedCrypto
 )
 
 // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
@@ -404,6 +408,8 @@ var extKeyUsageOIDs = []struct {
 	{ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
 	{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
 	{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
+	{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
+	{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
 }
 
 func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {

コアとなるコードの解説

src/pkg/crypto/x509/verify.go の変更点

checkChainForKeyUsage関数は、証明書チェーン内の各証明書が、検証プロセスで要求されている特定の拡張鍵用途(keyUsages引数で指定される)を満たしているかを確認します。

追加されたコードブロックは以下のロジックを導入しています。

				} else if requestedUsage == ExtKeyUsageServerAuth &&
					(usage == ExtKeyUsageNetscapeServerGatedCrypto ||
						usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
					// In order to support COMODO
					// certificate chains, we have to
					// accept Netscape or Microsoft SGC
					// usages as equal to ServerAuth.
					continue NextRequestedUsage
  • requestedUsage == ExtKeyUsageServerAuth: これは、現在検証中の証明書がサーバー認証の目的で使われることが期待されていることを意味します。
  • (usage == ExtKeyUsageNetscapeServerGatedCrypto || usage == ExtKeyUsageMicrosoftServerGatedCrypto): これは、証明書が実際にNetscape SGCまたはMicrosoft SGCのEKUを含んでいるかどうかをチェックします。
  • もし上記の条件が両方とも真であれば、つまり、ServerAuthが要求されているが、証明書がSGCのEKUを持っている場合、Goのcrypto/x509パッケージは、そのSGCのEKUをServerAuthと同等と見なします。
  • continue NextRequestedUsage: この行は、現在のrequestedUsage(ServerAuth)がこの証明書によって満たされたと判断し、次の要求された鍵用途のチェックに進むことを意味します。

この変更により、COMODOなど、ServerAuthを明示的に含まずにSGC EKUを使用している中間証明書を持つ証明書チェーンも、GoのX.509検証器によって正しく「ServerAuth」として認識され、検証が成功するようになります。

src/pkg/crypto/x509/x509.go の変更点

このファイルでは、新しい拡張鍵用途の定数とそのOIDが定義されています。

var (
	// ... 既存のOID定義 ...
	oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
	oidExtKeyUsageNetscapeServerGatedCrypto  = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
)

const (
	// ... 既存のExtKeyUsage定数 ...
	ExtKeyUsageMicrosoftServerGatedCrypto
	ExtKeyUsageNetscapeServerGatedCrypto
)

var extKeyUsageOIDs = []struct {
	// ... 既存のマッピング ...
	{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
	{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
}
  • oidExtKeyUsageMicrosoftServerGatedCryptooidExtKeyUsageNetscapeServerGatedCrypto: これらは、Microsoft SGCとNetscape SGCのEKUに対応する標準的なOIDを定義しています。asn1.ObjectIdentifier型は、ASN.1で定義されたオブジェクト識別子をGoで表現するためのものです。
  • ExtKeyUsageMicrosoftServerGatedCryptoExtKeyUsageNetscapeServerGatedCrypto: これらは、GoのExtKeyUsage型に新しい定数として追加され、対応するOIDと関連付けられます。これにより、コード内でこれらのEKUをシンボリックに参照できるようになります。
  • extKeyUsageOIDs マップへの追加: このマップは、ExtKeyUsage定数とその対応するOID間のマッピングを提供します。これにより、OIDからExtKeyUsage定数をルックアップしたり、その逆を行ったりすることが可能になります。

これらの変更は、crypto/x509パッケージがSGC関連のEKUを認識し、内部で処理するための基盤を構築します。

関連リンク

参考にした情報源リンク