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 を使用すると、使用しているプロバイダーによっては問題が解決する可能性があります。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示