15 情経第 1516 号
セキュリティ
API に関する技術調査
− Part 3 −
.NET Crypto API:機能と利用法
2004 年 2 月
登録商標
Microsoft、Windows、Internet Explorer、Outlook、Visual C++は、米国およびその他の国における米国 Microsoft Corp.の登録商標である。
その他、記載されている会社名、製品名などは、一般に各社の商標または登録商標である。 本書では、™、©、®などを記載しない。
― 目 次 ―
1
はじめに ...12
Microsoft .NET Crypto API の構造...12.1
概要...12.2
.NET Framework クラスライブラリ ...23
Microsoft .NET フレームワークにおける Crypto API ...43.1
API の分類...43.2
証明書ストアと構造体 ...53.3
証明書信頼リスト CTL(Certificate Trust List) ...73.4
セキュリティ関連のツールについて...83.4.1
証明書作成ツール Makecert.exe...93.4.2
証明書マネージャ ツール Certmgr.exe ...93.4.3
証明書検査ツール Chktrust.exe ...103.4.4
コードアクセス・セキュリティポリシーツール Caspol.exe... 113.4.5
ファイル署名ツール Signcode.exe ...123.4.6
アクセス許可表示ツール Permview.exe ...123.4.7
PEVerify ツール PEverify.exe ...123.4.8
Secutil ツール Secutil.exe ...123.4.9
レジストリ設定ツール Setreg.exe...133.4.10
ソフトウェア発行元証明書テスト ツール Cert2spc.exe ...133.4.11
厳密名ツール Sn.exe ...134
CryptoAPI を利用したアプリケーション ...144.1
暗号化、復号、ハッシュ計算 ...154.1.1
CSP について...154.1.2
CSP を使ったプログラム...184.2
証明書ストア ...224.2.1
関連する関数の解説 ...224.2.2
証明書ストアを扱うプログラム ...234.2.3
証明書コンテキストを扱うプログラム...244.3
証明書の検証 ...254.3.1
Certificate Verification Functions を使った証明書パス検証...254.3.2
CertVerifyRevocation による証明書ステータスの取得...334.4
デジタル署名とデジタル署名の検証...374.4.1
関連する関数の解説 ...374.4.2
デジタル署名を行うサンプルプログラム ...374.5
証明書および秘密鍵のインポート/エクスポート ...414.5.1
関連する関数の解説 ...414.5.2
証明書および秘密鍵のインポートを行うサンプルプログラム...414.5.3
証明書および秘密鍵のエクスポートを行うサンプルプログラム ...435
CryptoAPI のプロバイダの実装...455.1
Crypto Service Provider ...455.1.1
開発手順 ...455.1.2
単純な換字暗号を実装した CSP のサンプルプログラムの解説 ...495.2
Revocation Provider の実装...535.2.1
関連する関数の解説 ...535.2.2
証明書の有効/無効を通知する Revocation Provider サンプルプログラムの解説 ..565.3
その他の拡張可能な関数...576
まとめ...597
参考文献 ...608
用語(参考) ...61― 図 目 次 ― 図 2-1 MICROSOFT .NETの構成... 2 図 3-1 CRYPTOAPI の構造 ... 4 図 3-2 「証明書」スナップインを追加した管理コンソール ... 5 図 3-3 CTL 作成ツール(MAKECTL)のウィザード画面 ... 8 図 3-4 CERMGRの画面... 10 図 3-5 CHKTRUSTの図面... 11 図 4-1 アプリケーションと CSP... 15 図 4-2 CSP を管理しているレジストリ... 16 図 4-3 CSP を使ったハッシュの例 ... 19 図 4-4 ブロック暗号による暗号化の例... 21 図 4-5 暗号文の復号の例... 21 図 4-6 証明書ストアから証明書コンテキストを獲得する例 ... 23 図 4-7 X.509 証明書ファイルから証明書コンテキストを作成する例 ... 24 図 4-8 CERT_CHAIN_ENGINE_CONFIG の内容... 26
図 4-9 CERTIFICATE VERIFICATION FUNCTIONSを使った証明書パス検証の例... 29
図 4-10 パス検証結果を格納する構造体... 31
図 4-11 CRYPTOAPI での証明書パス検証の処理フロー ... 31
図 4-12 CERTVERIFYREVOCATIONを使った失効ステータス取得の例... 35
図 4-13 CMS SIGNEDDATAを作成する例... 39 図 4-14 CMS SIGNEDDATAから署名者の証明書コンテキストを得る例... 40 図 4-15 PKCS #12 ファイルから秘密鍵をインポートする例 ... 42 図 4-16 PKCS #12 ファイルへ秘密鍵と証明書をエクスポートする例... 44 図 5-1 CSP のリソースファイル... 48 図 5-2 レジストリへの登録/削除の関数 ... 49 図 5-3 CSP の暗号化のサンプルプログラム... 52 図 5-4 REVOCATION PROVIDERでエクスポートする関数... 55 図 5-5 サンプルの REVOCATION PROVIDERが呼ばれたところ... 56 図 5-6 レジストリの拡張関数に関する情報... 58
― 表 目 次 ―
表 3-1 CRYPTOAPI の関数の分類... 4
表 3-2 CRYPTOAPI で扱う証明書ストアの種類... 6
表 3-3 CRYPTOAPI の構造体の例 ... 7
表 3-4 CERTIFICATE TRUST LISTのフォーマット... 7
表 3-5 .NET FRAMEWORK SDK のセキュリティツール ... 9 表 4-1 サンプルプログラムの一覧 ... 14 表 4-2 標準提供される PROVIDER TYPE(一部)... 16 表 4-3 標準で提供される CSP(一部)... 16 表 4-4 PROV_RSA_FULL の 3 つの CSP でサポートされる鍵長の比較 ... 17 表 4-5 ブロック暗号のモード ... 18 表 4-6 ハッシュ、暗号化、復号を行うプログラムが使う関数... 18 表 4-7 証明書ストア、証明書、CRL、CTL を扱う主な関数... 22 表 4-8 パス検証の初期パラメータ ... 25 表 4-9CRYPTOAPI におけるパス検証の診断値... 32 表 4-10 公開鍵証明書を使ったデジタル署名を扱う関数... 37 表 4-11 PKCS #12 を扱う関数 ... 41
表 5-1 CSPDK(CRYPTOGRAPHIC SERVICE PROVIDER DEVELOPER'S TOOLKIT)の内容... 46
表 5-2 テスト用署名ツールCSPSIGNのオプション... 48
1. はじめに
このパートでは、以下の項目について調査を行いMicrosoft 社の.NET Crypto API についての 分析を行う。そして、その結果を踏まえ、.NET CryptoAPI を利用してアプリケーションを実装 する上での留意点に関して、必要であればサンプルプログラムを例示しながら、解説する。
Microsoft .NET Crypto API の構造
Microsoft .NET フレームワークにおける Crypto API CryptoAPI を利用したアプリケーション
CryptoAPI のプロバイダの実装
サンプルプログラムとしては以下の7 種類のカテゴリに分けてプログラムを実装し、各々に関 して解説をする。また、これらを通してWindows .NET Crypto API のフレームワーク、開発者 がアプリケーションへ固有の暗号機能を付与する際の、拡張方法に対しての分析を行う。 暗号化/復号/ハッシュ計算のプログラム 証明書リポジトリィを扱うプログラム 証明書の検証を行うプログラム デジタル署名/デジタル署名の検証を行うプログラム 証明書および秘密鍵のインポート/エクスポートを行うプログラム 単純な換字暗号を実装したCrypto Service Provider の実装
証明書の有効/無効を通知するRevocation Provider の実装
なお、サンプルプログラムの開発は以下の環境で行った。 コンパイラ : Microsoft Visual C++ V6.0 SP5
ライブラリ: Microsoft Platform Software Development Kit (SDK)
CryptoAPI のライブラリやヘッダファイルは Microsoft Platform Software Development Kit (SDK)に含まれる。この SDK は Microsoft 社の Web サイトよりダウンロード可能である。以 下のサイトにアクセスし、「Core SDK」を選択しダウンロードする。
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/default.htm
2. Microsoft .NET Crypto APIの構造
(1) 概要
Microsoft .NET とは、インターネットを利用した Web サービスなどの分散アプリケーション の稼動環境である。.NET は図 2-1のように分類されるサービスにより実現される。
アプリケーション
オーケストレーション
.Net Framework
.Net Enterprise
Server
ビルディングブロック
サービス
図 2-1 Microsoft .Net の構成
アプリケーションの開発及び稼働環境である.Net Framework、サーバソフトウェア(BizTalk Server、Commerce Server、SQL Server など)である.Net Enterprise Server、ビジネスロジッ クを実現したサービスのコンポーネントであるビルディングブロックサービスのコンポーネント を、オーケストレーションという形で組みあせてアプリケーションを提供するのが、
Microsoft .NET の目的である。
アプリケーション開発環境としての.Net Framework は、共通言語ランタイム(CLR : Common Language Runtime)と.NET Framework クラス ライブラリに分類される。
.Net Framework 対応のアプリケーションを開発するためには、.NET Framework SDK を用 いる。.NET Framework SDK は、.NET 対応プログラムを開発するためのコンパイラやクラス ライブラリ、プログラム実行環境、各種開発ツール、ドキュメントなどが含んでおり、Microsoft 社のWeb サイトよりダウンロード可能である。ただし、グラフィカルユーザーインターフェー スを持つアプリケーションの開発には、Microsoft 社の統合開発環境である Visual Studio.NET が必要となる。
Microsoft .NET Framework 1.1 SDK は以下のサイトにアクセスし、セットアッププログラム をダウンロードしてインストーラを行う。
「.NET Framework 1.1 再頒布パッケージ」と「Microsoft .NET Framework Version 1.1 日 本語 Language Pack」のインストールも必要である。
http://www.microsoft.com/japan/msdn/netframework/
(2) .NET Framework クラスライブラリ
.NET Framework クラスライブラリは、Microsoft .NET Framework SDK に含まれるクラス、 インターフェイス、および値型のライブラリである。このライブラリは、システム機能へのアク セスを提供する.NET Framework のアプリケーション、コンポーネント、及び、コントロール を作成する場合の基礎となるように設計されている。クラスライブラリは機能によって名前空間 を持ち、名前空間にクラスが定義されている。これらのうちセキュリティに関連した名前空間を 以下に示す。 System.Security アクセス許可のための基本クラスなど、.NET Framework のセキュリティ システムの基 になる構造が用意されている。 System.Security.Cryptography
データの安全なエンコーディングおよびデコーディングの他、ハッシュ処理、乱数生成、 メッセージ認証などの多数の操作を含む暗号サービスを提供している。 System.Security.Cryptography.X509Certificates 共通言語ランタイムによる Authenticode X.509 v.3 証明書の実装が含まれている。この 証明書は、証明書の所有者を一意に、そして確実に識別する秘密キーで署名される。 System.Security.Cryptography.Xml XML デジタル署名の作成と検証をサポートするためのクラスが含まれている。この名前 空間に含まれるクラスは、W3C(World Wide Web Consortium)による勧告
『XML-Signature Syntax and Processing』を実装している。この勧告は http://www.w3.org/TR/xmldsig-core/ で公開されている。 System.Security.Permissions 操作とリソースへのアクセスをポリシーに基づいて制御するクラスを定義している。 System.Security.Policy コードグループ、メンバシップ条件、及び、証拠の各クラスを含む。これら 3 種類のク ラスは、.NET Framework のセキュリティポリシーシステムによって適用される規則を 作成するために使用される。証拠クラスはセキュリティポリシーへの入力であり、メンバ シップ条件はスイッチである。これら 2 つのクラスの両方によって、ポリシーステート メントが作成され、与えられるアクセス許可セットが決定される。ポリシーレベルとコー ドグループは、ポリシーの階層構造を形成する。コードグループは規則をカプセル化した もので、ポリシーレベルに階層的に配置される。 System.Security.Principal コードが実行されているセキュリティコンテキストを表すプリンシパルオブジェクトを 定義する。 System.ServiceProcess Windows サービスアプリケーションを実装、インストール、および制御するためのクラ スが用意されている。サービスは、ユーザーインターフェイスを表示せずに長時間にわた って動作する実行可能ファイルである。サービスの実装の手順には、ServiceBase クラス から継承し、開始、停止、一時中断、続行の各コマンドが渡されたときの特定を定義し、 さらにシステムがシャットダウンするときのカスタムの動作およびアクションを定義す る手順が含まれている。
.Net Framework におけるセキュリティ関連のクラスライブラリは Windows のコアとなるモ ジュールであるCryptoAPI をラップしている。以降の節では、この.NET におけるセキュリティ 機能の中核をなすCryptoAPI について解説する。
3. Microsoft .NETフレームワークにおけるCrypto API
(1) APIの分類
CryptoAPI の構造を次図に示す。図 3-1では、左側が証明書の関連する関数群、右側は暗号メ ッセージつまり、CMS(PKCS #7)に関連する関数群、下側が暗号プリミティブを提供する関数 群となっている。 Message Functions Certificate and Certificate Store Functionsアプリケーション CryptoAPI インターフェース Certificate Store Functions Certificate Encode Decode Functions
Low Level Message Functions
Simple Message Functions
Cryptographic Functions Base Cryptography Functions CSP Functions Cryptographic Service Provider
(CSP) 鍵 データベース
標準のCSPとしては、
・Microsoft Base Cryptographic Provider ・Microsoft Enhanced Cryptographic Provider ・Microsoft DSS Cryptographic Provider などがある。
SmartCard Service Provider (CSP) 鍵 データベース Certificate Verification
Functions Certificate Services Backup and Restore
Functions Callback Functions Auxiliary Functions 証明書 ストア 図 3-1 CryptoAPI の構造 これらの関数群はさらに以下のように分類することができる。 表 3-1 CryptoAPI の関数の分類 分類名 説明
Base Cryptography Functions 暗号アルゴリズムを利用するための関数 Certificate and Certificate Store
Functions 証明書ストアにアクセスする関数
Certificate Verification Functions 証明書パスの獲得、検証の関数 Message Functions CMS の生成、解析する関数
Auxiliary Functions 関連するデータを扱うにあたって、補足的な関 数
CSP Functions CryptoServiceProvider との I/F 関数 Certificate Services Backup and
Restore Functions 証明書ストアのバックアップ関係の関数 Callback Functions 証明書ストアに関するコールバック関数
なお、CryptoAPI では、PKCS #7 に関して、上位互換を持つ後継仕様である CMS
(Cryptographic Message Syntax)を前提として処理を行っている。そのため、本章では、PKCS #7 ではなく、CMS と表記する。
(2) 証明書ストアと構造体
Windows システムでは、PKI で扱う公開鍵証明書や CRL のリポジトリは「証明書ストア」と 呼ばれる。システムで標準に持つ「証明書ストア」はローカルディスクのファイルやレジストリ を用いて保管されている。また、システムが標準で持つ「証明書ストア」は、「カレントユーザ」 のものと「ローカルコンピュータ」のものに分けられる。それぞれは、以下のように証明書の種 類ごとに分類されている。 「個人」:秘密鍵とペアになった証明書 「ほかの人」:他のEE 証明書 「中間証明機関」:中間CA 証明書 「信頼されたルート証明期間」:トラストポイントとなるルートCA 証明書 「Microsoft 管理コンソール」では、図 3-2のように「証明書」スナップインを追加してこれ らの証明書ストアを管理することができる。 図 3-2 「証明書」スナップインを追加した管理コンソール CryptoAPI で扱う証明書ストアは物理的な格納場所として、以下の4つに分類できる。 レジストリ 証明書ストアをシリアライズしたファイル CMS LDAP サーバーこれらは、プログラミングの観点からは、さらに細かく分けられて、表 3-2のように定義され ている。 表 3-2 CryptoAPI で扱う証明書ストアの種類 定義値 説明 CERT_STORE_PROV_MEMORY メモリを使った証明書ストア CERT_STORE_PROV_FILE 証明書ストアをシリアライズして保持す るファイルのファイルハンドル CERT_STORE_PROV_FILENAME 証明書ストアをシリアライズして保持す るファイルのファイル名 CERT_STORE_PROV_COLLECTION 開いた証明書ストアのコレクション CERT_STORE_PROV_REG 開いたレジストリキーを使う CERT_STORE_PROV_SYSTEM システムの標準の証明書ストア CERT_STORE_PROV_SYSTEM_REGISTRY システムの標準のレジストリの証明書ス トア CERT_STORE_PROV_PHYSICAL レジストリの証明書ストア CERT_STORE_PROV_MSG CMS を オ ー プ ン す る 関 数 CryptMsgOpenToDecode で得たハンド ル CERT_STORE_PROV_PKCS7 CMS のバイナリデータ CERT_STORE_PROV_SERIALIZED 証明書ストアをシリアライズしたバイナ リデータ
PKI の主な要素である、X.509 証明書、CRL、CTL を CryptoAPI で扱う場合の構造体を表 3-3 に示す。 それぞれについて、xxx_INFO は解析された内容を保持し、xxx_CONTEXT は処理中の識別子 であり、その中には、バイナリのデータとxxx_INFO も含む。 表 3-3 CryptoAPI の構造体の例 構造体 役割 CERT_INFO 解析された証明書の各フィールドの情報を持つ CERT_CONTEXT 証明書コンテキスト、証明書のバイナリデータとCERT_INFO を持つ CRL_INFO 解析されたCRL の各フィールドの情報を持つ CRL_CONTEXT CRL コンテキスト、CRL のバイナリデータと CRL_INFO を持つ CTL_INFO 解析されたCTL の各フィールドの情報を持つ CTL_CONTEXT CTL コンテキスト、CTL のバイナリデータと CTL_INFO を持つ
(3) 証明書信頼リスト CTL(Certificate Trust List)
信頼の基点であるルート証明書の配布は、PKI の運用にあたって重要な用件である。CryptoAPI では、ルート証明書の配布に独自仕様であるCertificate Trust List(CTL)という方法を採用して いる。CTL は、CMS をベースに自己署名の証明書とその使用目的に対してデジタル署名が可能 なフォーマットとなっている。これを利用者に配布することで、利用者は署名を検証し、その配 布された証明書の信頼性を確認できる。CTL は表 3-4のような CMS の SignedData 形式を採用 している。
contentType の ObjectID は Microsoft 社のプライベートな ID で certTrustList を指す。対応 するcontent は表に示す様な内容を持つ独自に定義されたフォーマットになっている。
certTrustList には CTL の有効期限や証明書の用途、信頼する証明書のハッシュ値などを含ませ る事が出来る。certTrustList 自体にはデジタル署名が存在しない。つまり signerInfos がなくて もCTL として成立する。ただし、署名し signerInfos を付与したのちに配布し、署名を検証して から受容するという運用が想定されている。
表 3-4 Certificate Trust List のフォーマット
フィールド 内容 SignedData encapContentInfo contentType 1.3.6.1.4.1.311.10.1 content 使用目的(複数) サーバー認証 クライアント認証 など 識別名 CTL の識別名(オプション) 開始有効期日 終了有効期日 (オプション)
フィールド 内容 ハッシュ関数のID 拇印アルゴリズム(SHA1) 信頼する証明書の拇印(複数) certificates 信頼する証明書(オプション) signerInfos CTL 自体の規定に含まれない(オプシ ョン) Platform SDK には、CTL を作成するためのツール MakeCTL.exe がバンドルされている。 このコマンドに適切なパラメータを与えることで、CTL を作成することが可能である。パラメ ータを指定せずに起動すると図 3-3のようなウィザード画面が表示される。 図 3-3 CTL 作成ツール(MakeCTL)のウィザード画面
(4) セキュリティ関連のツールについて
Net Framework SDK には開発者向けに用意されたセキュリティ関連のツールの一覧を表 3-5 に示す。表 3-5 .Net Framework SDK のセキュリティツール ツールの名前 プログラム a 証明書作成ツール Makecert.exe b 証明書マネージャ ツール Certmgr.exe c 証明書検査ツール Chktrust.exe d コードアクセス セキュリティポリシーツール Caspol.exe e ファイル署名ツール Signcode.exe f アクセス許可表示ツール Permview.exe g PEVerify ツール PEverify.exe h Secutil ツール Secutil.exe i レジストリ設定ツール Setreg.exe j ソフトウェア発行元証明書テスト ツール Cert2spc.exe k 厳密名ツール Sn.exe 次にこれら.Net Framework SDK のセキュリティ関連のツールの詳細を解説する。
1.1.1
証明書作成ツール Makecert.exe 証明書作成ツールは、テスト目的専用の X.509 証明書を生成する。このツールは、デジタル 署名用の公開鍵と秘密キーのペアを作成し、証明書ファイルの中に格納する。また、このキーペ アと指定された発行元の名前を関連づけて、ユーザー指定の名前とキーペアの公開部分を結びつ ける X.509 証明書を作成する。 Makecert.exe には基本オプションと拡張オプションがあり、証明書の作成に最も一般的に使 用されるのは基本オプションである。拡張オプションを使用すると、証明書をより柔軟に設定で きる。1.1.2
証明書マネージャ ツール Certmgr.exe証明書マネージャ ツールは、証明書、証明書信頼リスト(CTL: Certificate Trust List)、およ び証明書失効リスト(CRL: Certificate Revocation List)の 2 種類のデータを管理する。
具体的には、Certmgr.exe は次の基本的な機能を実行する。 証明書、CTL、および CRL をコンソールに表示する。 証明書、CTL、および CRL を証明書ストアに追加する。 証明書、CTL、および CRL を証明書ストアから削除する。 証明書ストアに含まれている X.509 証明書、CTL、または CRL をファイルに保存する。 Certmgr.exe は、StoreFile とシステムストアという 2 種類の証明書ストアに対して機能する。 StoreFile 証明書ストアの種類を指定する必要はなく、Certmgr.exe がストアの種類を識別し、適 切な操作が実行される。
オプションを何も指定せずにCertmgr.exe を実行すると、
図
3-4
のような証明書の管理タス クの実行時に役立つGUI が起動する。この GUI には、証明書、CTL、および CRL をディスク から証明書ストアへとコピーする、インポート ウィザードが用意されている。 図 3-4 CerMgr の画面1.1.3
証明書検査ツール Chktrust.exe 証明書検査ツールは、Authenticode 証明書による署名が付いたファイルの有効性をチェック する。有効性のチェックは次の手順で行われる。 1. ファイルから PKCS #7 署名付きデータオブジェクトを抽出する。 2. PKCS #7 署名付きデータオブジェクトから X.509 証明書を抽出する。 3. このファイルの新しいハッシュを計算し、それを PKCS #7 オブジェクトに含まれる署 名付きハッシュと比較する。 4. ハッシュが一致する場合、Chktrust.exe は、署名者の X.509 証明書が信頼できるルー ト証明書に由来する証明書かどうかを検査する。 すべての手順が成功した場合に、ファイルは改ざんされていないと判定する。したがって、フ ァイルの署名に使われた証明書は、信頼できるルート機関から発行されている必要がある。-q オプションを指定しないで有効な Authenticode 署名を持たないファイルを引数に指定する と、図 2-1のようなセキュリティ警告のダイアログボックスが表示される。このダイアログを使 用すると、Authenticode 署名がない場合でも、PE ファイルをインストールして実行できる。ソ フトウェアや発行者について十分な情報がないなどの理由で、そのファイルをインストールして も安全であることが認できない場合は、[いいえ]を選択する。 [いいえ]ボタンを選択すると、ファイルのインストールも実行も行われずに、チェックが異常 終了したことが報告される。 [はい]ボタンをクリックすると、そのファイルがインストール、実行されて、チェックが正常 終了したことが報告される。 図 3-5 ChkTrust の図面
1.1.4
コードアクセス・セキュリティポリシーツール Caspol.exe ユーザーと管理者は、コードアクセス・セキュリティポリシーツールを使用して、マシンポリ シーレベル、ユーザーポリシーレベル、およびエンタープライズポリシーレベルのセキュリティ ポリシーを変更できる。セキュリティポリシーは
3 種類のポリシーレベル、つまりマシンポリシー、
ユーザ ーポリシー、エンタープライズポリシーによって表現される。アセンブリが受信するアクセス許 可のセットは、これらの3 種類のポリシーレベルで許可されるアクセス許可セットの AND 集合 によって決定される。 それぞれのポリシーレベルは、コード グループの階層構造で表現されている。すべてのコード グループは、どのコードをそのグループのメンバとするのかを決定するためのメンバシップ条件 を持っている。名前付きアクセス許可セットも、各コード グループと関連づけられる。このアク セス許可セットは、メンバシップ条件を満たすコードに対してランタイムから与えられるアクセス許可を指定する。コードグループの階層構造、および関連する名前付きアクセス許可セットに よって、各レベルのセキュリティポリシーの定義と保守が行われる。コマンドラインのオプショ ンを使用して、セキュリティポリシーのレベルが設定できる。
1.1.5
ファイル署名ツール Signcode.exe ファイル署名ツールは、Authenticode 用証明書を使用して、ポータブル実行可能(PE)ファ イル(.dll ファイルまたは.exe ファイル)に署名する。マルチファイル アセンブリに含まれてい るアセンブリ、あるいは個別のファイルに署名する。アセンブリを配布する場合は、個別のファ イルではなく、アセンブリに署名する必要がある。オプションを指定せずにSigncode.exe を実行 すると、署名を支援するウィザードが起動する。1.1.6
アクセス許可表示ツール Permview.exe アセンブリによって要求された最小のアクセス許可セット、オプションのアクセス許可セット、 および拒否されたアクセス許可セットを表示するす。このツールを使用して、アセンブリによっ て使用されるすべての宣言セキュリティを表示することもできる。 開発者は、Permview.exe を使用して、作成したコードに対してアクセス許可要求を正しく適 用したかどうかを検査できる。また、作成したコードの利用者は、Permview.exe を実行して、 アセンブリが動作するために必要なアクセス許可を確認できる。これにより、たとえば、マネー ジ実行可能ファイルを実行して、 System.Security.Policy.PolicyException:必要なアクセス許可を取得できません というようなエラーが発生した場合に、Permview.exe を使用して、実行可能ファイルに含ま れるコードを実行する前に得る必要のあるアクセス許可を確認できる。1.1.7
PEVerify ツール PEverify.exePEVerify ツールは、Microsoft Intermediate Language (MSIL) を生成する開発者(コンパイ ラの作成者、スクリプトエンジンの開発者など)が、生成する MSIL コードと関連メタデータ がタイプセーフ要件を満たしているかどうかを確認するために使う。 一部のコンパイラでは、特定の言語構成を使用しなかった場合にだけ、検査可能でタイプセー フなコードが生成される。このようなコンパイラを使用している場合、生成したコードがタイプ セーフかどうかの確認を必要となったような場合などに、ファイルに対してPEVerify ツールを 実行し、MSIL とメタデータを検査できる。
1.1.8
Secutil ツール Secutil.exe Secutil ツールは、厳密な名前情報または X.509 証明書用の公開鍵をアセンブリから抽出し、この情報をコードに組み込むことができる形式に変換する。 .NET Framework におけるセキュリティ・システムには、関連づけられている証拠に基づいて プログラムのアクションを制限するための機構が用意されている。厳密な名前とAuthenticode 発行元という2 種類の証拠は、暗号鍵とデジタル署名の技術に基づいている。 これらの形式の証拠を必須のID アクセス許可チェックで使用するためには、かなり長いバイ ナリデータのシーケンス(厳密な名前の場合は公開鍵の値、Authenticode 発行元の場合は X.509 証明書)を参照する必要がある。チェックする証拠を保持するアセンブリファイルの名前を指定 して、Secutil.exe を実行すと、Secutil.exe からの出力データを定数定義の形式でコードに貼り 付けることができる。その後、この定数値を使用して、チェック対象の正確なID アクセス許可 を構築できる。
1.1.9
レジストリ設定ツール Setreg.exe レジストリ設定ツールを使用すると、公開鍵の暗号化に関するレジストリの設定を変更できる。 これらのレジストリの設定は、ソフトウェア発行状態キーと呼ばれ、証明書の検査処理を制御し ている。 以下の項目について、レジストリ設定を指定する。それぞれについてtrue または false を指 定することができる。 MakeCert で作ったテスト用ルートを信頼する。 証明書の有効期限を使用する。 失効リストを確認する。 オフライン失効サーバーOK。true の場合は、個人用証明書をオフラインで承認できる。 オフライン失効サーバーOK。true の場合は、商用証明書をオフラインで承認できる。 X.509 証明書バージョン 1 による署名付きオブジェクトを無効化する。 Time Stamp Signer の失効リストを確認する。Trust データベース内で見つかった項目だけを信頼する。true の場合は、Personal Trust Database に含まれる発行者からのダウンロードが許可される。
1.1.10
ソフトウェア発行元証明書テスト ツール Cert2spc.exeソフトウェア発行元証明書テストツールは、1 つ以上の X.509 証明書からテスト用のソフトウ ェア発行元証明書(SPC: Software Publisher's Certificate)を作成する。Cert2spc.exe はテスト専 用のツールで、有効なSPC は、VeriSign や Thawte などの証明書発行機関から入手する必要が ある。
1.1.11
厳密名ツール Sn.exe用し、アセンブリと呼ばれる、.NET Framework アプリケーションにおける機能単位をなすモ ジュールに署名をする。Sn.exe には、キーの管理、署名の生成、署名の検査に関するオプション が用意されている。 各コマンドのパラメータなどの詳細な情報は以下のURL を参照してほしい。 http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/m sdn/library/ja/cptools/html/cpconnetframeworktools.asp?frame=true なお、Platform SDK にも、同様のセキュリティ関連のツールがバンドルされている。(3) に 示したMakeCTL 以外に 6 個ある。詳細は以下の URL を参照してほしい。 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sec urity/security/cryptoapi_tools_reference.asp
4. CryptoAPIを利用したアプリケーション
以下では、CryptoAPI を利用したアプリケーションを例示する。 それぞれのアプリケーションにはサンプルプログラムが与えられる。サンプルプログラムは、 ワークスペース cpkismpl”に全て含まれている。 cpkismpl”に含まれるプロジェクトの一覧を 表 4-1に示す。 表 4-1 サンプルプログラムの一覧 プロジェクト 説明 cpkicdec 復号のサンプル cpkicenc 暗号化のサンプル cpkicexp 証明書およびPKCS #12 のエクスポートのサンプル cpkichsh ハッシュのサンプル cpkicimp 証明書およびPKCS #12 のインポートのサンプル cpkicrp Revocation Provider のサンプルcpkicsps Crypto Service provider のサンプル cpkicval 署名検証のサンプル
cspinst CSP のセットアッププログラムのサンプル
(1) 暗号化、復号、ハッシュ計算
1.1.12
CSP について(1)
CSP の役割CryptoAPI では、暗号や、デジタル署名のアルゴリズム自体の実装は Cryptographic Service Provider(CSP)としてモジュール化されている。つまり、暗号エンジンは独立したモジュール として、プラグイン可能な構造となっている。したがって、暗号アルゴリズムの実装者はCSP を開発することになる。また、アプリケーションは、図 4-1に示すように、CryptoAPI を通して、 CSP を選択し、間接的に CSP に実装されているアルゴリズムを利用する。
Windowsアプリケーション A Windowsアプリケーション B Windowsアプリケーション C
(エクスポートされた)関数群 CryptoAPI (advapi32.dll、crypt32.dll) CSP #1 CSP #2 CSP #3 CryptoAPI CryptoSPI アプリケーション OS サービス・プロバイダ 図 4-1 アプリケーションと CSP アプリケーションが呼び出すのは、advapi32.dll、crypt32.dll がエクスポートしている関数で ある。次に、呼び出されたこれらモジュールは、対応するCSP がエクスポートしている関数を 呼び出している。 CSP がエクスポートすべき関数群は CryptoSPI として規定されており、CryptoAPI の関数に 1 対 1 で対応している。CryptoAPI での暗号の関数名は「Crypt」で始まるが、CryptoSPI では 「CP」で始まる。 このような仕組みにより、暗号アルゴリズムを実装し、暗号の鍵を保持するスマートカードも、 アプリケーションからはCSP の 1 つとして利用可能となる。
(2)
Provider Type と Provider NameCSP は Provider Name という名前を持つ。また、CSP はサポートするアルゴリズムによって Provider Type に分類される。各 CSP はいずれか1つの Provider Type となる。標準で定義され ているProvider Type が複数あるが、任意の Provider Type を定義して導入することも可能であ る。各Provider Type にはデフォルトの CSP が設定されている。この関係はレジストリで確認 できる。レジストリでは、図 4-2のように
HKEY_LOCAL_MACHINE¥SOFTWARE¥Microsoft¥Cryptography¥Defaults
をキーとして、これらの情報が保存されている。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults
Provider Types Provider
Type 001 Name = Microsoft Strong Cryptographic Provider TypeName = RSA Full (Signature and Key Exchange) Type 003 Name = Microsoft Base DSS Cryptographic Provider
TypeName = DSS Signature Microsoft Strong Cryptographic Provider
Microsoft Base DSS Cryptographic Provider
Image Path = CSPの実態 DLLファイルのパス SigInFile = CSPの署名に関する情報 Type = Provider Type (この場合は 1)
Image Path = ・・・・・・・・・・ SigInFile = ・・・・・・・・・・ Type = 3 プロバイダのタイプが登録されている 個々のCSPが登録されている タイプごとの デフォルト ・・・・・・・ ・・・・・・・ 図 4-2 CSP を管理しているレジストリ
(3)
標準のCSPMicrosoft 社が提供している標準の CSP を解説する。規定の Provider Type とサポートするア ルゴリズムを表 4-2に示す。表 4-3には、標準で提供される CSP と、その Provider Type を示す。
表 4-2 標準提供される Provider Type(一部)
Provider Type 定義値 鍵交換 署名 共通鍵暗号 ハッシュ
PROV_RSA_FULL 1 RSA RSA RC2,RC4 MD5,SHA
PROV_RSA_SIG 2 − RSA − MD5,SHA
PROV_DSS 3 − DSS − MD5,SHA
PROV_FORTEZZA 4 KEA DSS Skipjack SHA
PROV_MS_EXCHANGE 5 RSA RSA CAST MD5
PROV_SSL 6 RSA RSA 多種 多種
PROV_RSA_SCHANNEL 12 RSA RSA RC4、DES、 トリプルDES
MD5,SHA
PROV_DSS_DH 13 DH DSS CYLINK MEK MD5,SHA PROV_RSA_AES 24 RSA RSA RC2,RC4,AES MD5,SHA
Provider Name 定義値 対 応 す る Provider Type
Microsoft Base Cryptographic
Provider MS_DEF_PROV PROV_RSA_FULL
Microsoft Strong Cryptographic
Provider MS_STRONG_PROV PROV_RSA_FULL
Microsoft Enhanced Cryptographic
Provider MS_ENHANCED_PROV PROV_RSA_FULL
Microsoft DSS Cryptographic
Provider MS_DEF_DSS_PROV PROV_DSS
Microsoft Base DSS and Diffie-Hellman Cryptographic Provider
MS_DEF_DSS_DH_PROV PROV_DSS_DH
Microsoft DH SChannel
Cryptographic Provider MS_DEF_DH_SCHANNEL_PROV PROV_DH_SCHANNEL Microsoft RSA/Schannel
Cryptographic Provider MS_DEF_RSA_SCHANNEL_PROV PROV_RSA_SCHANNEL Microsoft Enhanced RSA and AES
Cryptographic Provider (Prototype) MS_ENH_RSA_AES_PROV PROV_RSA_AES
上記のCSP のうち、Provider Type が PROV_RSA_FULL のものは 3 つあるが、サポートし ているアルゴリズムやその鍵長が異なる。
それらの相違点を表 4-4に示す。
表 4-4 PROV_RSA_FULL の 3 つの CSP でサポートされる鍵長の比較
アルゴリズム MS_DEF_PROV MS_STRONG_PROV MS_ENHANCED_PROV
RSA 署名 512 ∼1024 ∼1024 RSA 鍵交換 512 ∼1024 ∼1024 RC2 40 ∼128 ∼128 ソルト指定可能 RC4 40 ∼128 ∼128 ソルト指定可能 DES 56 56 56 トリプルDES(2 キー) サポートせず 112 112 トリプルDES(3 キー) サポートせず 168 168 表 4-5はこれらの CSP がサポートするブロック暗号のモードを与える。
表 4-5 ブロック暗号のモード
モード 定義値
Cipher Block Chaining CRYPT_MODE_CBC Cipher Feedback 8bits CRYPT_MODE_CFB Electronic Codebook CRYPT_MODE_ECB Output Feedback CRYPT_MODE_OFB
パディングはPKCS #5 V1.5 の仕様をサポートしている。
1.1.13
CSP を使ったプログラム(1)
CSP を使ったハッシュ、暗号化、復号のための関数 CSP を使って、ハッシュ、暗号化、復号を行うプログラムが使う CryptoAPI の関数を表 4-6 に示す。 表 4-6 ハッシュ、暗号化、復号を行うプログラムが使う関数 関数 説明 CryptEnumProviders CSP を列挙する。 CryptAcquireContext CSP のインスタンスを生成し、ハンドルを獲得する。 CryptDeriveKey 暗号鍵を得る。 CryptEncrypt 暗号化する。 CryptDecrypt 復号する。 CryptCreateHash ハッシュのインスタンスを生成し、ハンドルを獲得する CryptGetHashParam ハッシュ値を得る。 CryptHashData ハッシュの入力を与える。(2)
ハッシュのサンプルプログラム 図 4-3に CSP を使ったハッシュの例を示す。プログラムの全体は付録の cpkichsh.cpp を参照 のこと。HCRYPTPROV hCryptProv; HCRYPTKEY hKey; BYTE *pbBuffer; // ハッシュする入力データ DWORD dwBufLen; // ハッシュする入力データの長さ BYTE *pbHash // ハッシュ値の格納バッファ BYTE *dwHashLen // ハッシュ値の長さ // CSP のハンドルの獲得 ::CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, // CSP の名前 PROV_RSA_FULL, // CSP のタイプ 0); // SHA1 ハッシュ関数のハンドルを獲得
::CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash); ::CryptHashData(hHash, pbBuffer, dwBufLen, 0))
::CryptGetHashParam(hHash, HP_HASHVAL, NULL, &dwHashLen, 0); pbHash = (BYTE*)malloc(dwHashLen))
::CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0); printf("The hash is: ");
for(i = 0 ; i < dwHashLen ; i++) {
printf("%2.2x ",pbHash[i]); // ハッシュ値の出力 }
printf("¥n");
(3)
共通鍵暗号による暗号化のサンプルプログラム 図 4-4に標準の CSP を使って、パスワードのハッシュ値を鍵とした、ブロック暗号による暗号 化を行う例を示す。プログラムの全体は付録のcpkicenc.cpp を参照のこと。 HCRYPTPROV hCryptProv; HCRYPTKEY hKey; HCRYPTKEY hXchgKey; HCRYPTHASH hHash;char *szPassword = password”;
BYTE *pbBuffer; // 暗号化対象データと暗号化データのバッファ DWORD dwBufferLen; // 暗号化対象データの長さ DWORD dwCount; // 暗号化データのバッファの長さ /*暗号化データのバッファ ブロック暗号ブロック長と入力データから判断した出力バッファのサイ ズを決める。*/ // CSP のハンドルの獲得 ::CryptAcquireContext(&hCryptProv, NULL, MS_ENHANCED_PROV, // CSP の名前 PROV_RSA_FULL, // CSP のタイプ 0); // MD5 ハッシュ関数のハンドルを獲得
::CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash); // パスワードをハッシュ
::CryptHashData(hHash, (BYTE *)szPassword, strlen(szPassword), 0); //鍵ハンドルの獲得
::CryptDeriveKey( hCryptProv,
CALG_3DES, // アルゴリズム hHash, //ハッシュ関数のハンドル
&hKey); //鍵ハンドル ::CryptEncrypt(hKey, 0, TRUE, //データはこれで最後 0, pbBuffer, // [in/out]暗号化対象データと暗号化データのバッファ &dwCount, //暗号化対象データの長さ dwBufferLen); // pbBuffer の長さ ::CryptDestroyKey(hKey); //鍵ハンドルの破棄 ::CryptDestroyHash(hHash); //ハッシュハンドルの破棄 ::CryptReleaseContext(hCryptProv, 0);// CSP ハンドルの破棄 図 4-4 ブロック暗号による暗号化の例
(4)
共通鍵暗号による復号のサンプルプログラム 図 4-5にパスワードのハッシュ値を鍵とした、ブロック暗号によて暗号化されたデータの復号 を行う例を示す。鍵ハンドルであるhKey の獲得までの処理は暗号化の場合と同様であるため、 省略している。プログラムの全体は付録のcpkicdec.cpp を参照のこと。 BYTE *pbBuffer; // 複号対象データと複号結果データのバッファ DWORD dwCount; //複号対象データの長さ::CryptDecrypt(hKey, 0, TRUE, 0, pbBuffer, &dwCount);
(2) 証明書ストア
1.1.14
関連する関数の解説 証明書ストア、証明書、CRL、CTL を扱う主要な関数を表 4-7に示す。 表 4-7 証明書ストア、証明書、CRL、CTL を扱う主な関数 関数 説明 CertEnumSystemStore システム証明書ストアを列挙する。 CertOpenStore 任意の証明書ストアをオープンする。 CertOpenSystemStore システム証明書ストアを開く。 CertSaveStore 証明書ストアを保存する。 CertCloseStore 証明書ストアを閉じる。 CertAddCertificateContextToStore 証明書ストアへ証明書を証明書コンテキストか ら追加する。 CertAddEncodedCertificateToStore 証明書ストアへ証明書をバイナリデータから追 加する。 CertCreateCertificateContext バイナリデータから証明書コンテキストを作成 する。 CertEnumCertificatesInStore 証明書ストアから証明書コンテキストをを列挙 して得る。 CertFreeCertificateContext 証明書コンテキストを開放する。 CertAddCRLContextToStore 証明書ストアへCRL を CRL コンテキストから 追加する。 CertAddEncodedCRLToStore 証明書ストアへ CRL をバイナリデータから追 加する。 CertCreateCRLContext バイナリデータから CRL コンテキストを作成 する。 CertEnumCRLsInStore 証明書ストアから CRL コンテキストを列挙し て得る。 CertFreeCRLContext CRL コンテキストを開放する。 CertAddCTLContextToStore 証明書ストアへCTL をCTL コンテキストから 追加する。 CertAddEncodedCTLToStore 証明書ストアへCTL をバイナリデータから追加 する。 CertCreateCTLContext バイナリデータからCTL コンテキストを作成す る。 CertEnumCTLsInStore 証明書ストアからCTL コンテキストを列挙して 得る。 CertFreeCTLContext CTL コンテキストを開放する。 CertEnumCertificateContextProperties 証明書コンテキストから証明書の属性の識別子 を列挙する。 CertGetCertificateContextProperty 証明書コンテキストから証明書の属性を得る。 CertSetCertificateContextProperty 証明書コンテキストから証明書の属性をセット する。1.1.15
証明書ストアを扱うプログラム 図 4-6に証明書ストアから証明書コンテキストを獲得する例を示す。 この例では、 5. カレントユーザのシステム証明書ストアのうち中間証明機関の証明書ストアを開く。 6. 証明書コンテキストを得て、サブジェクトの DN を標準出力に出力する。 7. CertOpenSystemStore の 2 番目の引数に以下の文字列を指定し、対象の証明書ストア ハンドルを得る。 処理を行なっている。 「個人」:”MY” 「ほかのひと」:”ADDRESSBOOK” 「中間証明機関」:”CA” 「信頼された証明機関」:”ROOT” 「信頼された発行元」:”SPC” HCERTSTORE hCertStore; /*証明書ストアハンドル*/ PCCERT_CONTEXT pCertContext /*証明書コンテキスト*/ hCertStore = ::CertOpenSystemStore(NULL, “CA”);while(pCertContext = ::CertEnumCertificatesInStore(hCertStore, pCertContext)) { char szNameString[256]; ::CertGetNameString(pCertContext, CERT_NAME_RDN_TYPE, 0, /* CERT_NAME_ISSUER_FLAG だと発行元*/ NULL, szNameString, 256); printf(“subject : %s¥n”, szNameString); } ::CertFreeCertificateContext(pCertContext); ::CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG); 図 4-6 証明書ストアから証明書コンテキストを獲得する例
1.1.16
証明書コンテキストを扱うプログラム図 4-7に DER エンコードされた X.509 証明書ファイルを読み込み、証明書コンテキストを作 成する例を示す。
PCCERT_CONTEXT pCertContext; /*証明書コンテキスト*/ CFile file(szCertFile, CFile::modeRead);
BYTE *pszBuf = new BYTE[file.GetLength()]; file.Read(pszBuf, file.GetLength()); pCertContext = ::CertCreateCertificateContext( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pszBuf, file.GetLength()); file.Close(); delete(pszBuf); if (pCertContext == NULL) { DWORD dwErr = ::GetLastError(); }
(3) 証明書の検証
CryptoAPI の標準の機能では、証明書パス検証に関して RFC 3280 で規定されているパス検証 の初期パラメータ(表 4-8)を指定した検証はできない。 この問題への解決手法については「6. まとめ」で触れる。 証明書の検証を扱うサンプルプログラムは付録のcpkicval.cpp で示す。 表 4-8 パス検証の初期パラメータ パラメータ 定義 user-initial-policy-set 受け入れ可能なポリシーID のセット Initial-policy-mapping-inhibit ポリシーマッピングを許可/非許可 Initial-explicit-policy 検証結果に user-initial-policy-set のいずれかを含める ことの要求/非要求 Initial-any-policy-inhibit 証明書パス中のANY ポリシーの許可/非許可1.1.17
Certificate Verification Functions を使った証明書パス検証CryptoAPI を使った証明書パスの獲得と、パスの失効検証は、通常、「Certificate Verification Functions」にある一連の関数を使って行う。 「証明書パスエンジン」を作成し、対象の証明書を検証する。図 4-11に処理フローを示す。
(1)
証明書パスエンジン(CertCreateCertificateChainEngine) パス構築、パス検証には「証明書パスエンジン」を作成し、「証明書パスエンジン」を指定し て、証明書ストアから証明書パス上の証明書を獲得し、失効の検証を行う。 「証明書パスエンジン」には、検証のパラメータをCERT_CHAIN_ENGINE_CONFIG と いう構造体を入力として与える。これにより、システムのルート証明書ストアのサブセットを 一時的な証明書ストアとして作成し、トラストポイントの証明書を限定することが可能である。 また、中間CA の証明書については、システムの中間 CA 証明書ストアとは別に一時的な証 明書ストアを作成して、証明書、CRL を格納しておくことにより、パス構築処理の際に追加、 あるいは限定的に参照させることも可能である。また、拡張鍵使用法、CTL の使用法など検証 方法を指定できる。 CERT_CHAIN_ENGINE_CONFIG の内容については図 4-8に示す。typedef struct _CERT_CHAIN_ENGINE_CONFIG { DWORD cbSize;
HCERTSTORE hRestrictedRoot; HCERTSTORE hRestrictedTrust; HCERTSTORE hRestrictedOther;
DWORD cAdditionalStore; HCERTSTORE* rghAdditionalStore; DWORD dwFlags; DWORD dwUrlRetrievalTimeout; DWORD MaximumCachedCertificates; DWORD CycleDetectionModulus; } CERT_CHAIN_ENGINE_CONFIG, *PCERT_CHAIN_ENGINE_CONFIG; 図 4-8 CERT_CHAIN_ENGINE_CONFIG の内容 cbSize:本構造体のサイズをセット hRestrictedRoot:参照するルート証明書の格納された証明書の証明書ストアハンド ルを指定する。システムのルート証明書ストアのサブセットとなる。 hRestrictedTrust:参照するCTL の格納された証明書の証明書ストアハンドルを指 定する。 hRestrictedOther:中間CA の証明書、および、CRL、ARL の格納された証明書ス トアハンドルを指定する。 cAdditionalStore : 他 に 参 照 す べ き 証 明 書 ス ト ア ハ ン ド ル の 配 列 rghAdditionalStore の要素数 rghAdditionalStore:他に参照すべき証明書ストアハンドルの配列 dwFlags:以下の定義値が指定可能 CERT_CHAIN_CACHE_END_CERT:EE 証明書もキャッシュする。 CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL:URL 参照があったらキャッシュ のものを使う。 CERT_CHAIN_USE_LOCAL_MACHINE_STORE:カレントユーザではなく、ローカ ルマシンの証明書ストアを参照する。 dwUrlRetrievalTimeout:URL 参照のタイムアウト値、0 はシステムのデフォルト 値を使用。0 を指定 MaximumCachedCertificates:パス構築時にキャッシュする上限サイズを指定する。 0 はシステムのデフォルト値を使用。 CycleDetectionModulus:同一の証明書のパス上での出現回数の制限値を指定する。
(2)
検証処理(CertGetCertificateChain) 検証時のパラメータとしては、EE 証明書の失効検証の有無、パス上の証明書の失効検証の有 無や、キャッシュの使用法、日時を特定しての検証が可能である。 パス検証の失効検証では、内部で関数CertverifyRevocation が呼ばれて、登録されている RevocationProvider が働く。の全体は付録のcpkicval.cpp を参照のこと。 PCCERT_CONTEXT pCertContext; // 検証対象の証明書コンテキスト HCERTCHAINENGINE hChainEngine; //パス検証エンジンのハンドル PCCERT_CHAIN_CONTEXT pChainContext; // パス検証結果コンテキスト CERT_CHAIN_ENGINE_CONFIG ChainConfig; //パス検証エンジンの設定 ChainConfig.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG); ChainConfig.hRestrictedRoot= NULL; ChainConfig.hRestrictedTrust= NULL; ChainConfig.hRestrictedOther= NULL; ChainConfig.cAdditionalStore= 0 ; ChainConfig.rghAdditionalStore = NULL; ChainConfig.dwFlags = CERT_CHAIN_CACHE_END_CERT; ChainConfig.dwUrlRetrievalTimeout= 0 ; ChainConfig.MaximumCachedCertificates=0 ; ChainConfig.CycleDetectionModulus = 0; if (!::CertCreateCertificateChainEngine(&ChainConfig, &hChainEngine)) { cerr << "検証エンジンの作成に失敗しました。" << endl; DWORD dwErr = ::GetLastError();
return; } CERT_ENHKEY_USAGE EnhkeyUsage; CERT_USAGE_MATCH CertUsage; CERT_CHAIN_PARA ChainPara; EnhkeyUsage.cUsageIdentifier = 0; EnhkeyUsage.rgpszUsageIdentifier=NULL; CertUsage.dwType = USAGE_MATCH_TYPE_AND; CertUsage.Usage = EnhkeyUsage; ChainPara.cbSize = sizeof(CERT_CHAIN_PARA); ChainPara.RequestedUsage=CertUsage; if (::CertGetCertificateChain(
hChainEngine, pCertContext, NULL, NULL, &ChainPara, CERT_CHAIN_REVOCATION_CHECK_END_CERT| CERT_CHAIN_REVOCATION_CHECK_CHAIN| CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS, NULL, &pChainContext)) { char szNameString[256]; CString strStatus;
const char* pCodeName = NULL; const char* pText = NULL;
cout << "パス上の個々の証明書に関する情報" << endl; for (int i=0; i < pChainContext->cChain; ++i) {
PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[i]; for (int j = 0; j < pChain->cElement; ++j) {
PCERT_CHAIN_ELEMENT pElemet = pChain->rgpElement[j]; if (::CertGetNameString( pElemet->pCertContext, CERT_NAME_RDN_TYPE, 0, NULL, szNameString, 256)) {
cout << szNameString << endl; } if (pElemet->TrustStatus.dwErrorStatus == 0) { cout << "有効な証明書です。" << endl; } else { cout << "無効な証明書です。ステータスコード : " << pElemet->TrustStatus.dwErrorStatus << endl; } if (pElemet->TrustStatus.dwInfoStatus) {
cout << " 参照情報コード : " << pElemet->TrustStatus.dwInfoStatus << endl; } cout << "統合した情報" << endl; if (pChainContext->TrustStatus.dwErrorStatus == 0) { cout << "有効な証明書です。" << endl; } else { cout << "無効な証明書です。ステータスコード : " << pChainContext->TrustStatus.dwErrorStatus << endl; } if (pChainContext->TrustStatus.dwInfoStatus) { cout << " 参照情報コード : " << pChainContext->TrustStatus.dwInfoStatus << endl; } else {
DWORD dwErr = ::GetLastError(); } if (pChainContext) ::CertFreeCertificateChain(pChainContext); if (pCertContext) ::CertFreeCertificateContext(pCertContext); if (hChainEngine) ::CertFreeCertificateChainEngine(hChainEngine);
パス検証結果を格納する構造体について図 4-10に示す。
PCCERT_CHAIN_CONTEXT の変数から、次のように、パス上の証明書に関する証明書コン テキストとステータス情報が得ることができる。
rgpChain[0]-> rgpElement[0]-> pCertContext //証明書コンテキスト rgpChain[0]-> rgpElement[0]-> TrustStatus //ステータス情報 typedef struct _CERT_CHAIN_CONTEXT {
DWORD cbSize; // 構造体のサイズ
CERT_TRUST_STATUS TrustStatus; // パス検証結果コード DWORD cChain; // rgpChain の配列の要素数
PCERT_SIMPLE_CHAIN* rgpChain; // パス上の証明書に関するステータス DWORD cLowerQualityChainContext; // 次の配列の要素数 PCCERT_CHAIN_CONTEXT* rgpLowerQualityChainContext;
// CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS 情報 BOOL fHasRevocationFreshnessTime; // TRUE:次の値がある
DWORD dwRevocationFreshnessTime; // CRL の ThisUpdate からの差異 } CERT_CHAIN_CONTEXT, *PCERT_CHAIN_CONTEXT;
typedef struct _CERT_SIMPLE_CHAIN {
DWORD cbSize; // 構造体のサイズ CERT_TRUST_STATUS TrustStatus; // パス検証結果コード
DWORD cElement; // rgpElement の配列の要素数 PCERT_CHAIN_ELEMENT* rgpElement;
PCERT_TRUST_LIST_INFO pTrustListInfo;
BOOL fHasRevocationFreshnessTime; DWORD dwRevocationFreshnessTime;
} CERT_SIMPLE_CHAIN, *PCERT_SIMPLE_CHAIN;
typedef struct _CERT_CHAIN_ELEMENT {
DWORD cbSize; // 構造体のサイズ PCCERT_CONTEXT pCertContext; // 証明書コンテキスト CERT_TRUST_STATUS TrustStatus; // パス検証結果コード PCERT_REVOCATION_INFO pRevocationInfo; // 失効情報
PCERT_ENHKEY_USAGE pIssuanceUsage; // 発行元付与の拡張鍵用途 PCERT_ENHKEY_USAGE pApplicationUsage; // 個別の拡張鍵用途 } CERT_CHAIN_ELEMENT, *PCERT_CHAIN_ELEMENT; 図 4-10 パス検証結果を格納する構造体 認証パスエンジン作成 CertCreateCertificateChainEngine 検証対象の証明書を入力とし、認証パス と検証結果を獲得 CertGetCertificateChain 入力 ・システムの証明書ストアの利用を制限、ある いは補足するために作成した一時証明書スト アのハンドル ・証明書、CRLのキャッシュの使い方、上限値 ・URLによる参照時のタイムアウト値 ・パス上の同一証明書の出現回数の上限値 出力 ・認証パスエンジンのハンドル 入力 ・認証パスエンジンのハンドル ・検証対象の証明書コンテキスト ・検証する拡張鍵使用法 ・失効検証の仕方(EEのみ、パスを含むなど) 出力 ・証明書チェーンコンテキスト 証明書チェーンコンテキストの開放 CertFreeCertificateChain 認証パス、検証結 果の表示 一時証明書ストアの作成(トラストポイン ト用、中間CA用の2つ) 認証パスエンジンのハンドルの開放 CertFreeCertificateChainEngine 証明書コンテキストの開放 中間CAの証明書とCRL、ARLを一時証明 書ストアに追加 トラストポイントの証明書からCTLを作成 し、証明書とともに、一時証明書ストアに 追加 システムの証明書ストアをそのまま利用しない 場合、検証に利用する以下のデータを持つ一 時的な証明書ストアを作成する。 ・ルート証明書ストアを制限するため トラストポイントの証明書 トラストポイントCTL ・中間CA証明書ストアを補足するため 中間CAの証明書 中間CA発行のCRL 一時的なCA証明 書ストア 関数内部では CertVerifyRevocation などを呼び出し検証 検証対象の証明書コンテキストの作成 一時証明書ストアの開放 一時的なルート 証明書ストア トラストポイントの証明書をルート証明書 ストアへ追加 通常の処理 図 4-11 CryptoAPI での証明書パス検証の処理フロー
処理の結果として証明書パスとともに、証明書の信頼情報として、以下のようなエラーステー タスと参照情報が獲得される。 表 4-9 CryptoAPI におけるパス検証の診断値 エラーコードの定義値 # 意味 検証対象の証明書または証明書パスに関するエラー CERT_TRUST_NO_ERROR 1 証明書およびパスに問題はない。 CERT_TRUST_IS_NOT_TIME_VALID 2 検証対象の証明書かパス上の証明書で有効期限が妥当ではないものがある。 CERT_TRUST_IS_NOT_TIME_NESTED 3 パス上の証明書で有効期限の関連が適切ではない CERT_TRUST_IS_REVOKED 4 トラストポイントの証明書かパス上の証明書で失効しているものがある。 CERT_TRUST_IS_NOT_SIGNATURE_VALID 5 検証対象の証明書かパス上の証明書で有効な署名でないものがある。 CERT_TRUST_IS_NOT_VALID_FOR_USAGE 6 検証対象の証明書かパス上の証明書で指定された鍵使用法と合致しないものがある。 CERT_TRUST_IS_UNTRUSTED_ROOT 7 証明書パスが信頼されないルート認証局に基づいている。 CERT_TRUST_REVOCATION_STATUS_UNKNOWN 8 検証対象の証明書かパス上の証明書で、失効状態が不明なものがある。 CERT_TRUST_IS_CYCLIC 9 証明書パスが循環している。 CERT_TRUST_INVALID_EXTENSION 10 無効な拡張がある。 CERT_TRUST_INVALID_POLICY_CONSTRAINTS 11 検証対象の証明書かパス上の証明書で、ポリシー制約拡張を持つものがあり、プリシマ ッピングが禁止されているか、ポリシーが要求されているのにない証明書がある。 CERT_TRUST_INVALID_BASIC_CONSTRAINTS 12 検証対象の証明書かパス上の証明書で、基本制約拡張を持つものがあり、CA 制約かパ ス長制約に反する証明書がある。 CERT_TRUST_INVALID_NAME_CONSTRAINTS 13 検証対象の証明書かパス上の証明書で、無効な名前制約拡張がある CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT 14 検証対象の証明書かパス上の証明書で、サポートしていないフィールドを持つ名前制約 拡張を持つものがある。minimum フィールドと maximum フィールドはサポートして いない。したがって、minimum 値は常に 0 として、maximum 値はあってはいけない。 otherName としては MicrosoftUPN(1.3.6.1.4.1.311.20.2.3)がサポートされている。 x400Address、ediPartyName、registeredID はサポートされていない。 CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT 15 検証対象の証明書かパス上の証明書で、名前制約拡張があるが、証明書の名前に使われ ているフィールドに関する制約がない。 CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT 16 検 証 対 象 の 証 明 書 か パ ス 上 の 証 明 書 で 、 名 前 制 約 拡 張 を 持 つ も の が あ り permittedSubtrees フィールドがあるが、許可されていない名前を持つ証明書がある。
エラーコードの定義値 # 意味 CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT 17 検 証 対 象 の 証 明 書 か パ ス 上 の 証 明 書 で 、 名 前 制 約 拡 張 を 持 つ も の が あ り 、 excludedSubtrees フィールドがあるが、受け付けられない名前を持つ証明書がある。 CERT_TRUST_IS_OFFLINE_REVOCATION 18 検証対象の証明書かパス上の証明書に関する失効情報は、オフラインでものであるか古 い。 CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY 19 ポリシー制約拡張でポリシーが要求されているが、要求されたポリシーを満たさないも のがある。 証明書パスに関するエラー CERT_TRUST_IS_PARTIAL_CHAIN 20 証明書パスが完結していない。 CERT_TRUST_CTL_IS_NOT_TIME_VALID 21 この証明書パスを構築するために使ったCTL が古い。 CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID 22 この証明書パスを構築するために使ったCTL に有効な署名がない。 CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE 23 この証明書パスを構築するために使ったCTL の使用法は適切ではない。 参照情報(エラーではない) CERT_TRUST_HAS_EXACT_MATCH_ISSUER 24 適切な発行元の証明書が存在する。 CERT_TRUST_HAS_KEY_MATCH_ISSUER 25 適切な鍵を持つ発行元の証明書が存在する。 CERT_TRUST_HAS_NAME_MATCH_ISSUER 26 適切な名前を持つ発行元の証明書が存在する。 CERT_TRUST_IS_SELF_SIGNED 27 自己署名の証明書である。 CERT_TRUST_IS_COMPLEX_CHAIN 28 証明書パスは複数ある。 CERT_TRUST_HAS_PREFERRED_ISSUER 29 適切な発行元を持つ。 CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY 30 ポリシーを持つ。 CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS 31 有効な名前制約を持つ。
1.1.18
CertVerifyRevocation による証明書ステータスの取得「Auxiliary Functions」に分類される関数 CertVerifyRevocation を使って、証明書のステー タスを確認できる。前述の「Certificate Verification Functions」の関数が証明書パスに対する 処理を行うのに対し、この関数では、個々の証明書コンテキストを入力とし、単一の証明書のス テータスを取得するのが目的である。
この関数の特筆すべき点は、任意の失効検証ルーチンを開発しRevocation Providers としてシ ステムに登録しておくと、関数内部で、登録されている失効検証ルーチンを呼び出すことだ。こ
れにより、開発者は、CryptoAPI 標準の失効検証ルーチン以外の失効検証ルーチンを提供するこ とが可能となる。Revocation Providers の実装については、「5. (2) Revocation Provider の実装」 で解説する。
(1)
CertVerifyRevocation を使った失効検証 CertGetCertificateChain と異なり、CertVerifyRevocation では複数の証明書コンテキストを 配列にして渡すことができる。図 4-12 に CertVerifyRevocation を使った失効ステータスの取得 の例を示す。プログラムの全体は付録のcpkicval.cpp を参照のこと。 引数で使われるCERT_REVOCATION_PARA 構造体の詳細は図 5-4に示した。 // 検証のパラメータをセットします。 DWORD dwFlags = 0; dwFlags |= CERT_VERIFY_REV_CHAIN_FLAG; dwFlags |= CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION; dwFlags |= CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG; dwFlags = 0; pPara = (CERT_REVOCATION_PARA ) malloc(sizeof(CERT_REVOCATION_PARA)); memset(pPara, 0x00, sizeof(CERT_REVOCATION_PARA)); pStatus = (CERT_REVOCATION_STATUS) malloc(sizeof(CERT_REVOCATION_STATUS)); memset(pStatus, 0x00, sizeof(CERT_REVOCATION_STATUS)); pStatus->cbSize = sizeof(CERT_REVOCATION_STATUS);BOOL bRet = ::CertVerifyRevocation(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CERT_CONTEXT_REVOCATION_TYPE, /*固定値*/ 1, /*証明書コンテキスト配列の数*/ (void **)pCertContext, /*検証する証明書コンテキスト配列*/ dwFlags, pPara, pStatus); if (bRet) { cout << "有効な証明書です。" << endl; } else {
cout << "無効な証明書です。" << endl;
cout << ステータス : << pStatus ->dwError << endl; cout << 失効理由: << pStatus -> dwReason << endl; } 図 4-12 CertVerifyRevocation を使った失効ステータス取得の例
(2)
既存のアプリケーションについて 一般的なCryptoAPI を使ったアプリケーションでも、CertVerifyRevocation を使った失効検 証を行っている。その場合、アプリケーションでの設定が必要となる場合がある。以下に設定に ついて記す。(a)
Outlook Express の設定ツール」メニューの「オプション」の「セキュリティ」タブで「セキュリティの詳細設定」を 開く。そこで、「デジタルID が取り消されているか確認する」の「オンラインのときのみ」を チェックする。
(b)
Internet Explorer の設定 インターネットオプションの「詳細設定」で「サーバー証明書の取り消しを確認する」をチェ ックする。(c)
IPsec/ISAKMP での PKI 利用時の設定 IPsec/ISAKMP でのネゴシエーションに公開鍵証明書を利用する場合、CRL-DP を元に CRL を取得し失効検証をさせるためには設定が必要である。レジストリにキー HKEY_LOCAL_MACHINE¥SYSTEM¥CurrentControlSet¥Services¥PolicyAgent¥Oak ley を追加して、 DWORD 値の値「StrongCrlCheck」を追加 StrongCrlCheck が 0 の場合、CRL による検証を行わない。 StrongCrlCheck が 1 の場合、CRL による検証を行う。 StrongCrlCheck が 2 の場合、CRL による検証を行い、かつ、適正な CRL が取得できないよ うな場合、無効な証明書として扱う。 値を追加、変更した後は、コマンドプロンプトから>net stop policyagent >net start policyagent
を実行すると、設定が有効となる。
(3)
CRL のキャッシ
ュ標準のcryptnet.dll では、取得した CRL をキャッシュする。キャッシュに使う場所は、Internet Explorer の Temporary Internet Files などである。