CryptAcquireContext() の使用とトラブルシューティング

この記事では、CryptAcquireContext を呼び出すときに特定のフラグを使用するタイミングと、これらのフラグを使用する理由について説明します。

適用対象: Windows Server 2012 R2
元の KB 番号: 238187

概要

関数の CryptAcquireContext 呼び出しには、さまざまなフラグを含めることができます。 これらのフラグを使用するタイミングを把握することが重要です。 この記事では、呼び出 CryptAcquireContext すときに特定のフラグを使用するタイミングと、これらのフラグを使用する理由について説明します。

詳細

秘密キー操作は実行されません

永続化された秘密キーを使用していない場合は、CryptAcquireContext が呼び出されたときにCRYPT_VERIFYCONTEXT (0xF0000000) フラグを使用できます。 これにより、CryptReleaseContext が呼び出されたときに解放されるキー コンテナーをメモリに作成するように CryptoAPI に指示されます。 このフラグを使用する場合、pszContainer パラメーターは NULL である必要があります。 CRYPT_VERIFYCONTEXT フラグは、次のシナリオで使用できます。

  • ハッシュを作成しています。

  • データを暗号化または暗号化解除するための対称キーを生成しています。

  • データを暗号化または暗号化解除するために、ハッシュから対称キーを派生しています。

  • 署名を確認しています。 公開キーは、CryptImportKey または CryptImportPublicKeyInfo を使用して、PUBLICKEYBLOB または証明書からインポートできます。

  • 対称キーをエクスポートする予定ですが、暗号化コンテキストの有効期間内にはインポートしません。

    注:

    過去 2 つのシナリオの公開キーのみをインポートする予定の場合は、CRYPT_VERIFYCONTEXT フラグを使用してコンテキストを取得できます。

  • 秘密キー操作を実行していますが、キー コンテナーに格納されている永続化された秘密キーを使用していません。

秘密キー操作が実行される

秘密キー操作を実行する予定の場合は、考慮する必要がある多くの問題があります。

コンテキストを取得する最善の方法は、コンテナーを開こうとすることです。 この試行が "NTE_BAD_KEYSET" で失敗した場合は、CRYPT_NEWKEYSET フラグを使用してコンテナーを作成します。

注:

アプリケーションでは、コンテナー名に NULL を 渡して秘密キーを格納することで、既定のキー コンテナーを使用しないでください。 複数のアプリケーションが同じコンテナーを使用する場合、あるアプリケーションは、別のアプリケーションが使用するために必要なキーを変更または破棄できます。 アプリケーションが一意の名前のキー コンテナーを使用する場合、適切な機能に必要なキーを改ざんする他のアプリケーションのリスクが軽減されます。

// Acquire Context of container that is unique to each user.
if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 0))
{
 if (GetLastError() == NTE_BAD_KEYSET)
 {
 if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_NEWKEYSET))
 {
 // Error ...
 }
 }
}

// Or, acquire Context of container that is shared across the machine.
if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_MACHINE_KEYSET))
{
 if (GetLastError() == NTE_BAD_KEYSET)
 {
 if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET)
 {
 // Error ...
 }
 }
}

CRYPT_MACHINE_KEYSET フラグの使用

ユーザーごとに秘密キー操作を実行せず、グローバル秘密キー操作が必要な場合は、CRYPT_MACHINE_KEYSETを使用する必要があります。 このメソッドは、コンピューターごとに秘密キーと公開キーのペアを作成します。 CRYPT_MACHINE_KEYSETを使用する必要がある特定のシナリオは次のとおりです。

  • あなたはサービスを書いている。
  • コンポーネントが Active Server Pages (ASP) ページで実行されています。
  • コンポーネントは Microsoft Transaction Server (MTS) コンポーネントです。 これらの例では、アプリケーションが実行されているセキュリティ コンテキストがユーザー プロファイルにアクセスできないため、CRYPT_MACHINE_KEYSETが使用されます。 たとえば、MTS クライアントはユーザーを偽装できますが、ユーザーがログオンしていないため、ユーザーのプロファイルは使用できません。 ASP ページで実行されているコンポーネントについても同じことが当てはまります。

コンテナーへのアクセスを提供する

既定では、キー コンテナーが作成されると、コンテナーにアクセスできる唯一のユーザーがローカル システムと作成者になります。 この例外は、管理者がキー コンテナーを作成する場合です。 ローカル システムとその他のすべての管理者は、キー コンテナーにアクセスできます。 その他のセキュリティ コンテキストでは、コンテナーを開くことができません。

コードが複数のセキュリティ コンテキストで実行される場合は、適切なユーザーにコンテナーへのアクセス権を付与する必要があります。

コンテナーのセキュリティを設定するには、コンテナーの作成後に PP_KEYSET_SEC_DESCR フラグを指定して CryptSetProvParam 関数を呼び出します。 このメソッドを使用すると、コンテナーにセキュリティ記述子を設定できます。

次のコードは、CryptSetProvParam を呼び出す方法を示しています。 これは、キー コンテナーの作成直後に行われます。

// Acquire Context  
if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 0))
{
 if (GetLastError() == NTE_BAD_KEYSET)
 {
 if (!CryptAcquireContext(&hProv,  
 "Container",  
 NULL,  
 PROV_RSA_FULL,  
 CRYPT_NEWKEYSET))
 {
 // Error ...
 }

// Create Security Descriptor (pSD)...

// Set the Security Descriptor on the container
 if (!CryptSetProvParam(hProv,
 PP_KEYSET_SEC_DESCR,
 pSD,
 DACL_SECURITY_INFORMATION))
 {
 // Error ...
 }
 }
}

CryptAcquireContext エラー

最も一般的なエラー コードと、エラーの原因を次に示します。

  • NTE_BAD_KEYSET (0x80090016)
    • キー コンテナーが存在しません。
    • キー コンテナーにはアクセスできません。
    • 保護されたストレージ サービスが実行されていません。
  • NTE_EXISTS (0x8009000F)
    • キー コンテナーは既に存在しますが、作成しようとしています。 キーを開こうとした前の試行がNTE_BAD_KEYSETで失敗した場合は、キー コンテナーへのアクセスが拒否されたことを意味します。
  • NTE_KEYSET_NOT_DEF (0x80090019)
    • Crypto Service Provider (CSP) が正しく設定されていない可能性があります。 CSP DLL (Rsabase.dll または Rsaenh.dll) で Regsvr32.exe を使用すると、使用しているプロバイダーによっては問題が解決する可能性があります。