このトピックでは、スマート カード ミニドライバーを操作する開発者、またはスマート カード ミニドライバーを開発する開発者向けの一般的なガイドラインについて説明します。スマート カードとそれに関連するアプリケーションの想定される動作を知らせます。
一般的な設計ガイドライン
カード ミニドライバーを配布する方法、論理カード ファイル システムとその他のミニドライバーの設計ガイドラインをマップする方法については、「スマート カード ミニドライバーの概要」の「一般的な設計ガイドライン」セクションを参照してください。
スマート カード PIN のブロック解除のチャレンジ/応答方法
管理者がこのメカニズムを使用してユーザーのカードのブロックを解除するには、発行されたチャレンジに対する応答データを正しく生成できるように、カードに格納されている管理者キーを識別して使用できる必要があります。
これを行う 1 つの方法は、カード識別子を使用してカードを一意に識別する方法です。 (カード識別子はカードの一意の識別子です)。これは UI のユーザーに何らかの形式で表すことができますが、それ以外の場合は、カードに適切な APDU コマンドを送信してこの情報を読み取るプログラムを記述できます。
この情報により、管理者はカード上の秘密鍵を識別し、ユーザーに発行されたチャレンジ データに対する適切な応答を計算できます。
カードに格納されている管理者秘密キーは、有効で信頼できる管理者のみがアクセスできるセキュリティで保護されたメカニズム (可能な限り少ない) を使用して保持されることを前提としています。 ただし、これはこの仕様の範囲外です。
詳細については、次の「チャレンジ/応答メカニズム」セクションを参照してください。
強化された PIN のサポート
バージョン 6.0 では、複数の PIN をサポートするための柔軟なアーキテクチャがサポートされました。 このアーキテクチャでは、各ロールが PIN 識別子に対応するロールの新しい概念が導入されました。 PIN 識別子は、カードから PIN 情報を抽出し、PIN をキー コンテナーに関連付けるために使用されます。
識別子は数値で構成され、現在は 0 から 7 に制限されています。 また、PIN 識別子から生成できるビットマスクであるPIN_SETの概念も導入しました。 現在、PIN セットには下位 8 ビットのみが使用されています。 また、残りのビットを使用して、"and"、"or"、または将来役に立つ可能性があるその他の情報などの条件を示すこともできます。 この方法を選択して、カードが簡単にビット マスクを適用できるようにしました。
ユーザーが PIN #3 に対応するロール 3 で認証されるとします。 これはビット マスク 0000 0100 (ベース 2) に変換されます。 カードは、これを現在認証されている ID として記録でき、ビットごとの AND 操作を実行することで、キーと PIN のアクセス制御規則を簡単に確認できます。 この設計では、カードに複数の認証済み ID を同時に持つことが可能であり、これは v6 カード ミニドライバーをサポートするカードの要件です。 たとえば、PIN #1 が認証され、その後 PIN #2 が認証された場合、これらの PIN コントロールのいずれかの操作を許可する必要があります。
セッション PIN とセキュリティで保護された PIN チャネル
Windows で PIN 認証用のセキュリティで保護された PIN チャネルを確立する必要がある場合は、ミニドライバーで次の一連の操作が実行されます。 準拠するには、ミニドライバーとカードが次のシーケンスと互換性がある必要があります。 特に、セッション PIN はプロセス間で転送でき、一定の時間だけ持続する必要があります。 (GENERATE_SESSION_PIN フラグを設定して CardAuthenticateEx が呼び出された場合でも、CARD_AUTHENTICATE_ SESSION_PIN フラグを使用してカードのコールド リセットが行われるまで、セッション PIN を有効にすることをお勧めします)。
次の動作がサポートされている必要があります。
- 信頼できるシステム プロセスであるアプリケーション A は、スマート カードのハンドルを取得し、PIN を収集します。
- 次に、アプリケーション A は CardAuthenticateEx ミニドライバー関数を呼び出し、収集された PIN を渡し、CARD_AUTHENTICATE_GENERATE_SESSION_PIN フラグを設定します。 これにより、カードのロックが解除されることはありません。
- アプリケーション A は、生成されたセッション PIN を格納し、カードとカード ミニドライバーにハンドルを解放します。 カードはコールド リセットではありません。
- アプリケーション A は、セッション PIN と、手順 1 で取得したカードを持つリーダーの名前をアプリケーション B に送信します。
- アプリケーション B は、1 と同じカードを取得します。
- アプリケーション B は CardAuthenticateEx を 呼び出し、セッション PIN を渡し、CARD_AUTHENTICATE_SESSION_PIN フラグを設定します。 セッション PIN がまだ有効な場合は、カードを認証し、使用するために有効にする必要があります。
- アプリケーション B は、カードの使用が完了すると、 CardDeauthenticateEx を呼び出してカードの認証を解除します。
この動作には、次の実用的な制限があります。
カードは、CP_CARD_PIN_STRENGTH_VERIFYの適切な値を返すことによって、セッション PIN を操作する能力を宣言する必要があります。
各検証に PIN を使用するカードは、このシステムと互換性がありません。
複数のアプリケーションは、有効なセッション PIN であると判断した内容を一度に持つことができます。 各 PIN に対して 1 つのセッション PIN しか使用できない場合は、次の実装をお勧めします。
- カードには、生成された最新のセッション PIN が記憶されている必要があります。
- 無効なセッション PIN が提示された場合、カードは認証に失敗し、サポートされている場合はセッション PIN の再試行カウンターを減少させる必要があります。 再試行回数が 0 に達し、次の認証試行が無効な場合は、セッション PIN を無効にする必要があります。
- 新しいセッション PIN がネゴシエートされるまで、後続のセッション PIN プレゼンテーションは失敗します。
セッション PIN は、システム上のさまざまなアプリケーションから使用できる必要があります。
セッション PIN は、単に PIN のエンコードである必要はありません。
このシステムのセキュリティは、セッション PIN の強度と、それを生成するために使用されるネゴシエーション プロトコルに制限されます。 実際のセッション PIN ネゴシエーションは、この仕様の範囲外です。 このセクションで説明するように動作することを除き、設計に関する要件はありません。
セッション PIN は引き続き価値があると見なされ、シークレットとして扱う必要があります。
カードは無効なセッション PIN を検出できる必要があります。
読み取り専用カード
ベース CSP/KSP 環境の外部でカスタマイズされ、本質的に読み取り専用であるカードに対処するために、読み取り専用カードの新しい概念が導入されました。 カードが読み取り専用の場合は、 CardGetProperty 関数を使用してこれをアドバタイズする必要があります (この仕様の前のセクションを参照)。
読み取り専用カードは、バージョン 7 カード ミニドライバー インターフェイスのサブセットのみをサポートする必要があり、管理者 PIN をサポートする必要はありません。
次の表に、読み取り専用カードでサポートする必要がある関数を示します。
| 伝説 | |
|---|---|
| イエス | この関数を実装する必要があります。 |
| いいえ | エントリ ポイントは存在する必要があり、SCARD_E_UNSUPPORTED_FEATURE を返す必要があります。 |
| いいえ (省略可能) | この操作は、読み取り専用カードでサポートされている必要はありませんが、カードが操作をサポートしている場合に実装される場合があります。 サポートされていない場合、エントリ ポイントはSCARD_E_UNSUPPORTED_FEATUREを返す必要があります。 |
| はい (省略可能) | この関数は、カードが読み取り専用であるかどうかに関係なく、この仕様の定義に従って実装する必要があります。 |
読み取り専用カード用のミニドライバーを開発するときは、次の要件を考慮する必要があります。
- 'msroots' ファイル ('cardcf' や 'cardid' など) を除くすべての Base CSP/KSP ファイルは、読み取り専用カードに存在する必要があります (またはミニドライバー インターフェイスを介して仮想化する必要があります)。
- 読み取り専用カードには、プライマリ カード (つまり、ROLE_USER) PIN によって保護されているカードに少なくとも 1 つのキーが含まれている必要があります。
- 読み取り専用カードには、管理者キーを含めることはできません。 このような場合は、ミニドライバーが CardGetChallenge、 CardAuthenticateChallenge、および CardUnblockPin をサポートしないことが予想されます。
- クエリを実行すると、読み取り専用カードは使用可能なバイト数 0 または使用可能なコンテナー数 0 という結果を返す必要があります。
- 読み取り専用カードで設定できるのは、CP_PARENT_WINDOWプロパティとCP_PIN_CONTEXT_STRING プロパティのみです。
- 読み取り専用カードの場合、CP_SUPPORTS_WIN_X509_ENROLLMENTプロパティは false にする必要があります。
キャッシュ モード
Base CSP/KSP では、パラメーター CP_CARD_CACHE_MODEで呼び出された CardGetProperty によって返されたキャッシュ モードに応じて、3 つの異なるキャッシュ モードがサポートされます。
- 返されたフラグがCP_CACHE_MODE_GLOBAL_CACHEされ、カードが CP_READ_ONLY_CARD プロパティを TRUE として報告した場合、Base CSP/KSP データ キャッシュはグローバル キャッシュです。 カードが読み取り専用の場合、Base CSP/KSP は cardcf ファイルに書き込まれません。 カードを Base CSP/KSP に書き込むことができる場合は、今日のように動作します。
- CP_CARD_CACHE_MODEとCP_CACHE_MODE_GLOBAL_CACHEの詳細については、「 CardGetProperty」を参照してください。
- 返されたフラグがCP_CACHE_MODE_SESSION_ONLYされると、Base CSP/KSP は、カードが削除または再挿入されたことを検出したときにデータ キャッシュがクリアされるように動作します。 つまり、セッションをカードの挿入と削除の間のスパンとして定義しました。
- キャッシュはプロセスごとに実装され、グローバルではありません。 このモードは、ユーザーの PC ではなく、政府機関やその他の外部サイトで変更されない読み取り専用カード用に設計されています。 (このモードは読み取り/書き込みカードでサポートされていますが、これらのカードにはグローバル キャッシュをお勧めします)。
- カードが読み取り専用で、(Base CSP/KSP 以外の方法で) ユーザーの PC でカードが変更される可能性がある場合、アプリケーションは、キャッシュに古いデータが含まれる可能性がある状況を回避するために、この仕様で後述するキャッシュ モードを使用しない必要があります。
- フラグがCP_CACHE_MODE_NO_CACHEされると、Base CSP/KSP はデータ キャッシュを実装しません。 このモードは、cardcf ファイルの書き込みをサポートしていないが、カードの状態を変更できるカード ミニドライバー向けに設計されています。 カード ミニドライバーは、そのレイヤーでキャッシュを実行するかどうかを決定します。
チャレンジ/応答メカニズム
カード ミニドライバー インターフェイスは、チャレンジ/応答認証メカニズムをサポートしています。 カードは、1 つ以上の 8 バイト ブロックのチャレンジを生成する必要があります。 認証エンティティは、168 ビット キー (およびパリティ ビットを無視) で CBC モードで動作する Triple DES (3DES) を使用してチャレンジを暗号化することで、応答を計算します。
カードは、次のいずれかの方法を使用して応答を検証します。
- 以前に発行されたチャレンジに対して暗号化操作を繰り返し、結果を比較する。
- 応答の暗号化を解除し、結果をチャレンジと比較する。
結果の値が同じ場合、認証は成功します。
カードと認証エンティティの両方で、同じ対称キーを使用する必要があります。
次のサンプル コードでは、認証エンティティが応答を計算する方法について詳しく説明します。 このコードは、関連する保証を対象とせず、単に例とガイダンスとして提供されます。
#include <windows.h>
#include <wincrypt.h>
#include <winscard.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
int __cdecl wmain(int argc, __in_ecount(argc) WCHAR **wargv)
{
//Acquire the context Use CryptAcquireContext
HCRYPTPROV hProv= 0;
DWORD dwMode=CRYPT_MODE_ECB;
BYTE *pbLocData = NULL,tempbyte;
DWORD cbLocData = 8, count = 0;
HCRYPTKEY hKey = 0;
BYTE rgEncByte [] = {0xA8,0x92,0xD7,0x56,0x01,0x61,0x7C,0x5D };
BYTE DesKeyBlob [] = {
0x08, 0x02, 0x00, 0x00, 0x03, 0x66, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
pbLocData = (BYTE *) malloc (sizeof(BYTE)*cbLocData);
memcpy(pbLocData,rgEncByte,cbLocData);
if (!CryptAcquireContext(
&hProv,
NULL,
L"Microsoft Enhanced Cryptographic Provider V1.0",
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
printf("Acquire context failed with 0x%08x \n", GetLastError());
goto Cleanup;
}
if (!CryptImportKey(
hProv,
DesKeyBlob,
sizeof(DesKeyBlob),
0,
0,
&hKey ) )
{
printf("Error 0x%08x in importing the 3Des key \n", GetLastError());
goto Cleanup;
}
if (!CryptSetKeyParam(
hKey,
KP_MODE,
(BYTE *)&dwMode,
0))
{
printf("Error 0x%08x in CryptSetKeyParam \n", GetLastError());
goto Cleanup;
}
if (!CryptEncrypt(
hKey,
0,
FALSE,
0,
pbLocData,
&cbLocData,
cbLocData))
{
printf("Error 0x%08x in CryptEncrypt call \n", GetLastError());
goto Cleanup;
}
for (count=0; count < cbLocData; ++count)
{
printf("0x%02x",pbLocData[count]);
}
printf("\n");
Cleanup:
if (hKey)
{
CryptDestroyKey(hKey);
hKey = 0;
}
if (pbLocData)
{
free(pbLocData);
pbLocData = NULL;
}
if (hProv)
{
CryptReleaseContext(hProv,0);
}
return 0;
}
msroots との相互運用性
msroots ファイルは、エンタープライズ信頼ルート用の PKCS #7 形式の証明書ストアです。 (ファイルは、空のコンテンツと空の署名を含む証明書のバッグであり、Base CSP によって書き込まれ、読み取られます)。カード ミニドライバー開発者は、このファイルを処理するためにカード ミニドライバーに特別なコードを記述する必要はありません。 msroots ファイルに証明書を格納する場合、msroots ファイルはコンピューター ストアとは異なる形式で証明書を格納するため、CODE_SIGNING EKU などのプロパティはスマート カードに反映されません。 他のアプリケーションからこのファイルを読み書きする開発者は、次のサンプル コード スニペットを使用してデータにアクセスできます。
読み取り操作
if (FALSE == CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
&dbStore,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
NULL,
NULL,
NULL,
phCertStore,
NULL,
NULL))
{
dwSts = GetLastError();
}
書き込み操作
// Serialize the store
if (FALSE == CertSaveStore( hCertStore,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
CERT_STORE_SAVE_AS_PKCS7,
CERT_STORE_SAVE_TO_MEMORY,
&dbStore,
0))
{
dwSts = GetLastError();
goto Ret;
}
dbStore.pbData = CspAllocH(dbStore.cbData);
if (NULL == dbStore.pbData)
{
dwSts = ERROR_NOT_ENOUGH_MEMORY;
goto Ret;
}
if (FALSE == CertSaveStore( hCertStore,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
CERT_STORE_SAVE_AS_PKCS7,
CERT_STORE_SAVE_TO_MEMORY,
&dbStore,
0))
{
dwSts = GetLastError();
goto Ret;
}
Microsoft Base Smart Card CSP のグループ ポリシー設定
Microsoft Base Smart Card Crypto Service Provider のグループ ポリシー設定は、[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults \Provider\Microsoft Base Smart Card Crypto Provider]にあります。
| Key | Description |
|---|---|
| DefaultPrivateKeyLenBits | dword:00000400 既定のキー生成パラメーター - 1024 ビット キー。 |
| RequireOnCardPrivateKeyGen | dword:000000000 これにより、カード上の秘密キーの生成を要求するためのフラグが設定されます (既定)。 この値が設定されている場合は、ホストで生成されたキーをカードにインポートできます。 これは、カード上のキー生成をサポートしていないカードや、キー エスクローが必要な場合に使用されます。 |
| トランザクションタイムアウトミリ秒 (TransactionTimeoutMilliseconds) | dword:000005dc カードへのトランザクションを保持するための既定のタイムアウトは、1500 秒、1.5 秒です。 |
| プライベート署名キーのインポートを許可する | dword:000000000 署名キーのインポート、つまりキーアーカイブシナリオを許可します。 |
| プライベート交換キーのインポートを許可する | dword:000000000 交換キーのインポートを許可します。つまり、キーアーカイブシナリオです。 |
Microsoft CNG スマート カード KSP のグループ ポリシー設定
Microsoft CNG スマート カード キー ストレージ プロバイダーのグループ ポリシー設定は、[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\Providers\Microsoft Smart Card Key Storage Provider] にあります。
| Key | Description |
|---|---|
| DefaultPrivateKeyLenBits | dword:00000400 既定のキー生成パラメーター - 1024 ビット キー。 |
| RequireOnCardPrivateKeyGen | dword:000000000 これにより、カード上の秘密キーの生成を要求するためのフラグが設定されます (既定)。 この値が設定されている場合は、ホストで生成されたキーをカードにインポートできます。 これは、カード上のキー生成をサポートしていないカードや、キー エスクローが必要な場合に使用されます。 |
| トランザクションタイムアウトミリ秒 | dword:000005dc カードへのトランザクションを保持するための既定のタイムアウトは、1500 秒、1.5 秒です。 |
| プライベート署名キーのインポートを許可する | dword:000000000 署名キーのインポート、つまりキーアーカイブシナリオを許可します。 |
| AllowPrivateExchangeKeyImport | dword:000000000 交換キーのインポートを許可します。つまり、キーアーカイブシナリオです。 |
| AllocPrivateECDHEKeyImport | dword:000000000 ECDH キーのインポートを許可します。つまり、キーアーカイブシナリオ |
| AllowPrivateECDSAKeyImport(プライベートECDSAキーのインポートを許可) | dword:000000000 ECDSA キーのインポートを許可します。つまり、キー アーカイブ シナリオ |
特別な考慮事項
Windows Vista Service Pack 1 (SP1) では、オペレーティング システムがセーフ モードで実行されている間は、Windows ログオン以外の PIN で必要なスマート カード操作は実行できません。
次のいずれかのフラグを指定して CryptAcquireContext を呼び出すと、コンテナーに割り当てられている実際の PIN に関係なく、USER_PINでの PIN 認証が求められます。
- CRYPT_NEWKEYSET
- CRYPT_DEFAULT_CONTAINER_OPTIONAL
- CRYPT_DELETEKEYSET
- CRYPT_VERIFYCONTEXT
CardDeleteContext は、 dllMain が DLL_PROCESS_DETACH で呼び出された後でも呼び出すことができます。