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

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

このコミットは、Go言語の crypto/x509 パッケージにおけるWindowsシステムでの証明書検証ロジックの改善に関するものです。具体的には、WindowsのCryptoAPIを利用した証明書チェーンの検証において、Server Gated Crypto (SGC) 証明書を許可するように変更が加えられています。また、既存の systemVerify 関数内のコードが複数の補助関数に分割され、可読性と保守性が向上しています。

コミット

commit 3133b14b307103b79117a033ddf1ac9d0f7a24d0
Author: Mikkel Krautz <mikkel@krautz.dk>
Date:   Thu Mar 8 11:28:04 2012 -0500

    crypto/x509: allow server gated crypto in windows systemVerify
    
    Also factors out some code into functions to make
    systemVerify easier to read.
    
    R=rsc, agl
    CC=golang-dev
    https://golang.org/cl/5781054

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

https://github.com/golang/go/commit/3133b14b307103b79117a033ddf1ac9d0f7a24d0

元コミット内容

元のコミットメッセージは以下の通りです。

「crypto/x509: allow server gated crypto in windows systemVerify」 「Also factors out some code into functions to make systemVerify easier to read.」

これは、Windows環境における crypto/x509 パッケージの証明書検証機能において、Server Gated Crypto (SGC) 証明書を許可するように変更を加えたことを示しています。さらに、systemVerify 関数内のコードを複数の関数に分割し、コードの可読性を向上させたことも言及されています。

変更の背景

この変更の背景には、以下の点が考えられます。

  1. Server Gated Crypto (SGC) の互換性問題: Server Gated Crypto (SGC) は、かつて輸出規制の対象となっていた暗号化技術であり、一部の古いブラウザやシステムでは、SGC証明書が必須となる場合がありました。Go言語の crypto/x509 パッケージがWindowsのCryptoAPIを利用して証明書を検証する際、SGC証明書が正しく扱われない場合、互換性の問題が発生し、正当な証明書であっても検証に失敗する可能性がありました。このコミットは、このような互換性の問題を解消し、より広範な証明書に対応することを目的としています。コミットメッセージにも「Both IE and Chrome allow certificates with Server Gated Crypto as well. Some certificates in the wild require them.」とあり、実際の環境でSGC証明書が使用されていることが示唆されています。

  2. コードの可読性と保守性の向上: systemVerify 関数は、WindowsのCryptoAPIを呼び出して証明書チェーンを構築・検証する複雑なロジックを含んでいました。この関数が肥大化すると、コードの理解やデバッグが困難になります。コードを複数の小さな関数に分割することで、各関数の役割が明確になり、コード全体の可読性と保守性が向上します。これは、ソフトウェア開発における一般的なベストプラクティスであり、将来的な機能追加やバグ修正を容易にします。

前提知識の解説

このコミットを理解するためには、以下の前提知識が必要です。

  • X.509 証明書: X.509は、公開鍵証明書の標準フォーマットです。WebサイトのSSL/TLS通信などで広く利用されており、公開鍵とそれに対応するエンティティ(Webサイト、個人など)の身元情報を紐付けます。証明書は、信頼された認証局(CA)によって署名され、その信頼の連鎖(証明書チェーン)を通じて検証されます。

  • 証明書チェーン (Certificate Chain): 証明書チェーンは、エンドエンティティ証明書(例: Webサイトの証明書)から始まり、中間認証局(Intermediate CA)の証明書を介して、最終的に信頼されたルート認証局(Root CA)の証明書に至る一連の証明書の階層構造です。証明書の検証は、このチェーンを辿り、各証明書が正しく署名され、有効期限内であるかなどを確認することで行われます。

  • Windows CryptoAPI: Windows CryptoAPI (Cryptographic Application Programming Interface) は、Windowsオペレーティングシステムが提供する暗号化サービスへのインターフェースです。これには、証明書の管理、暗号化操作、ハッシュ計算など、様々な機能が含まれます。Go言語の crypto/x509 パッケージは、Windows環境で証明書を検証する際に、このCryptoAPIを利用してシステムレベルの証明書ストアや検証ロジックと連携します。

  • Server Gated Crypto (SGC): Server Gated Crypto (SGC) は、かつて米国政府の輸出規制により、暗号化の強度に制限があった時代に登場した技術です。規制緩和前は、海外への輸出が許可される暗号化の強度が制限されており、SGCは、規制対象外の弱い暗号化しかサポートしないクライアント(古いブラウザなど)に対しても、より強力な暗号化(通常は128ビット)を提供するための仕組みでした。SGC証明書は、特定の拡張キー使用法 (Extended Key Usage, EKU) OID(Object Identifier)を持つことで識別されます。このコミットで追加された OID_SERVER_GATED_CRYPTO (1.3.6.1.4.1.311.10.3.3) と OID_SGC_NETSCAPE (2.16.840.1.113730.4.1) がそれにあたります。

  • OID (Object Identifier): OIDは、情報オブジェクトを一意に識別するための国際標準の命名メカニズムです。X.509証明書では、証明書の拡張機能やアルゴリズムなどを識別するために使用されます。

技術的詳細

このコミットでは、主に以下の技術的な変更が行われています。

  1. Server Gated Crypto (SGC) OID の追加:

    • src/pkg/syscall/ztypes_windows.go ファイルに、SGCに関連する2つの新しいOIDが追加されました。
      • OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\\x00")
      • OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\\x00")
    • これらのOIDは、crypto/x509/root_windows.gosystemVerify 関数内で、サーバー認証 (OID_PKIX_KP_SERVER_AUTH) と共に para.RequestedUsage.Usage.UsageIdentifiers に追加されます。
    • para.RequestedUsage.Typesyscall.USAGE_MATCH_TYPE_AND から syscall.USAGE_MATCH_TYPE_OR に変更されました。これにより、証明書が OID_PKIX_KP_SERVER_AUTHOID_SERVER_GATED_CRYPTO、または OID_SGC_NETSCAPE のいずれかの拡張キー使用法を持つ場合に、検証が成功するようになります。これは、SGC証明書がサーバー認証目的で利用されることを許可するための重要な変更です。
  2. systemVerify 関数のリファクタリング:

    • systemVerify 関数内のロジックが、以下の3つの新しい補助関数に分割されました。
      • extractSimpleChain: syscall.CertSimpleChain から最終的な証明書チェーンを抽出し、[]*Certificate 型に変換します。これは、Windows CryptoAPIが返す低レベルの構造体から、Go言語の x509.Certificate オブジェクトのリストを構築する役割を担います。
      • checkChainTrustStatus: 証明書チェーンの信頼ステータスをチェックし、syscall.CERT_TRUST_NO_ERROR 以外のエラーをGoのエラー型に変換します。これにより、有効期限切れ (CERT_TRUST_IS_NOT_TIME_VALID) や不明な認証局 (UnknownAuthorityError) などの一般的な信頼エラーを適切に処理できます。
      • checkChainSSLServerPolicy: CertVerifyCertificateChainPolicy を呼び出して、証明書チェーンがSSL/TLSサーバーのポリシーに適合しているかを検証します。これには、DNS名の一致 (CERT_E_CN_NO_MATCH) や、有効期限切れ (CERT_E_EXPIRED)、信頼されていないルート (CERT_E_UNTRUSTEDROOT) などのSSL固有のエラーチェックが含まれます。
    • これらの関数への分割により、systemVerify 関数はより簡潔になり、各検証ステップの責任が明確になりました。
  3. エラーハンドリングの改善:

    • 新しい補助関数内で、より具体的なエラー型 (CertificateInvalidError, HostnameError, UnknownAuthorityError) を返すようにエラーハンドリングが改善されました。これにより、検証失敗の原因をより詳細に特定できるようになります。

これらの変更により、Go言語の crypto/x509 パッケージは、Windows環境においてSGC証明書を適切に処理できるようになり、同時にコードベースの品質も向上しました。

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

主要な変更は src/pkg/crypto/x509/root_windows.gosrc/pkg/syscall/ztypes_windows.go の2つのファイルにあります。

src/pkg/crypto/x509/root_windows.go

  • 新しい関数の追加:
    • extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error)
    • checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error
    • checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error
  • systemVerify 関数の変更:
    • para.RequestedUsage.Type の設定ロジックが変更され、SGC OIDが追加されました。
    • 以前 systemVerify 関数内に直接記述されていた証明書チェーンの信頼ステータスチェックとSSLサーバーポリシーチェックのロジックが、新しく作成された checkChainTrustStatuscheckChainSSLServerPolicy 関数への呼び出しに置き換えられました。
    • 証明書チェーンの抽出ロジックも extractSimpleChain 関数に移動されました。

src/pkg/syscall/ztypes_windows.go

  • 新しいOIDの定義:
    • OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\\x00")
    • OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\\x00")

コアとなるコードの解説

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

systemVerify 関数の変更

// systemVerify is like Verify, except that it uses CryptoAPI calls
// to build certificate chains and verify them.
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
	// ... (省略) ...

	para := new(syscall.CertChainPara)
	para.Size = uint32(unsafe.Sizeof(*para))

	// If there's a DNSName set in opts, assume we're verifying
	// a certificate from a TLS server.
	if hasDNSName {
		oids := []*byte{
			&syscall.OID_PKIX_KP_SERVER_AUTH[0],
			// Both IE and Chrome allow certificates with
			// Server Gated Crypto as well. Some certificates
			// in the wild require them.
			&syscall.OID_SERVER_GATED_CRYPTO[0],
			&syscall.OID_SGC_NETSCAPE[0],
		}
		para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR // ここが変更点
		para.RequestedUsage.Usage.Length = uint32(len(oids))
		para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
	} else {
		para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
		para.RequestedUsage.Usage.Length = 0
		para.RequestedUsage.Usage.UsageIdentifiers = nil
	}

	// ... (省略) ...

	err = checkChainTrustStatus(c, chainCtx) // 新しい関数呼び出し
	if err != nil {
		return nil, err
	}

	if hasDNSName {
		err = checkChainSSLServerPolicy(c, chainCtx, opts) // 新しい関数呼び出し
		if err != nil {
			return nil, err
		}
	}

	chain, err := extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount)) // 新しい関数呼び出し
	if err != nil {
		return nil, err
	}

	chains = append(chains, chain)

	return chains, nil
}

この変更により、systemVerify 関数は、DNS名が指定されている場合に、サーバー認証 (OID_PKIX_KP_SERVER_AUTH) に加えて、Server Gated Crypto (OID_SERVER_GATED_CRYPTO および OID_SGC_NETSCAPE) のOIDも証明書の要求された使用法として考慮するようになりました。USAGE_MATCH_TYPE_OR を使用することで、これらのOIDのいずれかが存在すれば検証が続行されます。また、複雑な検証ロジックが checkChainTrustStatus, checkChainSSLServerPolicy, extractSimpleChain の各関数に委譲され、systemVerify の役割がより明確になりました。

新しい補助関数

  • extractSimpleChain: この関数は、Windows CryptoAPIが返す syscall.CertSimpleChain 構造体から、Go言語の x509.Certificate オブジェクトのリストを抽出します。unsafe.Pointer を使用してCの構造体からGoのスライスに変換し、各証明書のバイトデータをコピーして ParseCertificate で解析しています。

  • checkChainTrustStatus: この関数は、chainCtx.TrustStatus.ErrorStatus をチェックし、証明書チェーンの基本的な信頼ステータス(例:有効期限切れ)を検証します。エラーがある場合は、対応するGoのエラー型(CertificateInvalidErrorUnknownAuthorityError)を返します。

  • checkChainSSLServerPolicy: この関数は、syscall.CertVerifyCertificateChainPolicy を呼び出して、SSL/TLSサーバー証明書としてのポリシー検証を行います。これには、サーバー名の一致(DNSNameの検証)や、SSL固有のエラー(例:CERT_E_CN_NO_MATCH)の処理が含まれます。

src/pkg/syscall/ztypes_windows.go の変更点

var (
	OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\\x00")
	OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\\x00") // 追加
	OID_SGC_NETSCAPE        = []byte("2.16.840.1.113730.4.1\\x00")  // 追加
)

このファイルでは、Server Gated Cryptoに関連する2つの新しいOIDがバイトスライスとして定義されています。これらのOIDは、Windows CryptoAPIがSGC証明書を識別するために使用するものです。

関連リンク

参考にした情報源リンク