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


概要


CryptAcquireContext関数への呼び出しでは、さまざまなフラグを含めることができます。これらのフラグを使用するタイミングを知るために重要です。CryptAcquireContextとこれらのフラグを使用する理由を呼び出すときに特定のフラグを使用する場合にこの資料で説明します。

詳細


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

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

  • ハッシュを作成します。
  • 暗号化またはデータを暗号化解除する対称キーを生成します。
  • 対称キーを暗号化またはデータの暗号化を解除するためのハッシュ値から派生しました。
  • 署名が検証します。CryptImportKeyまたはCryptImportPublicKeyInfoを使用して、PUBLICKEYBLOB とは、証明書から公開キーをインポートすることができます。
  • 計画して、対称キーのエクスポートが、暗号化のコンテキストの有効期間内でインポートできません。

    注: CRYPT_VERIFYCONTEXTフラグを使用して、最後の 2 つのシナリオの公開キーをインポートする場合だけでは、コンテキストを取得できます。
  • 秘密のキー操作を実行しているが、キー コンテナーに格納されている永続化された秘密キーを使用していません。

秘密キーの操作が実行されます。

プライベート キー操作を実行する場合は、考慮する必要がある多くの問題があります。



コンテキストを取得する最良の方法では、コンテナーを開くしようとしています。この試みでは、"nte_bad_keyset"が表示されるが失敗した場合、 CRYPT_NEWKEYSETフラグを使用してコンテナーを作成します。

注: アプリケーションは既定のキー コンテナーを秘密キーを格納するのにNULLの場合、コンテナーの名前を渡すことで使用しないでください。複数のアプリケーションは、同じコンテナーを使用して、1 つのアプリケーションを変更したりするのに必要な他のアプリケーションが利用可能なキーを破棄します。アプリケーションは、一意の名前のキー コンテナーを使用する場合、他のアプリケーションが正常に機能に必要なキーが改ざんされるリスクが減少します。
// 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 トランザクション サーバー (MTS) コンポーネントです。
これらの例については、アプリケーションが実行されるセキュリティ コンテキストにユーザー プロファイルへのアクセス権があるないために、 CRYPT_MACHINE_KEYSETが使用されます。たとえば、MTS クライアントは、ユーザーを偽装することがありますが、ユーザーのプロファイルは、ユーザーがログオンしていないため使用できません。ASP ページで実行されているコンポーネントに対しても同様です。

コンテナーへのアクセスを提供します。

既定では、キー コンテナーが作成されると、ローカル システムと、作成者は、コンテナーへのアクセスを持つユーザーのみです。この例外は、管理者は、キー コンテナーを作成するときです。ローカル システムと他のすべての管理者は、キー コンテナーへのアクセスがあります。 それ以外のセキュリティ コンテキストは、コンテナーを開くことができません。の詳細については、マイクロソフト サポート技術情報の記事を表示するのには次の資料番号をクリックします:

318825 Windows XP ベースのシステム上で管理者の既定の随意アクセス制御リスト (DACL) の動作の変更

1 つ以上のセキュリティ コンテキストでコードが実行される、する場合は、コンテナーに適切なユーザー アクセスを与えなければなりません。

コンテナーのセキュリティを設定するには、コンテナーを作成した後、 PP_KEYSET_SEC_DESCRフラグを使用してCryptSetProvParam関数を呼び出します。このメソッドを使用すると、コンテナーのセキュリティ記述子を設定します。セキュリティ記述子を操作する方法の詳細については、マイクロソフト サポート技術情報の記事を表示するのには次の資料番号をクリックして:

106387カーネル オブジェクトをプロセス間での共有方法

次のコードは、 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)
    • 暗号サービス プロバイダー (CSP) は可能性があります正しく設定されていません。 CSP の Dll 名を指定 (Rsaenh.dll) に Regsvr32.exe の使用は、使用されているプロバイダーによって、この問題を修正することがあります。