web-dev-qa-db-ja.com

ルートに(秘密鍵を使用して)証明書を挿入すると、ローカルマシンの証明書ストアが.NET4で失敗する

ローカルマシンのルート証明書ストアに秘密鍵を使用して新しいCA証明書を挿入する際に問題が発生します。

これが起こることです:

//This doesn't help either.
new StorePermission (PermissionState.Unrestricted) { Flags = StorePermissionFlags.AddToStore }.Assert();
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
privkey.PersistKeyInCsp = true;
//This shouldn't be necessary doesn't make a difference what so ever.
RSACryptoServiceProvider.UseMachineKeyStore = true;
cert.PrivateKey = privkey;
store.Open (OpenFlags.MaxAllowed);
store.Add (cert);
store.Close ();

証明書が挿入され、すべてがダンディに見えます:(参照してください!) note it says it has a private key

注:それは秘密鍵を持っていると言っています。

したがって、 FindPrivateKey でそれを見つけることができると言うでしょう

C:\Users\Administrator\Desktop>FindPrivateKey.exe Root LocalMachine -t "54 11 b1 f4 31 99 19 d3 5a f0 5f 01 95 fc aa 6f 71 12 13 eb"
FindPrivateKey failed for the following reason:
Unable to obtain private key file name

Use /? option for help 

かわいい....でも間違ってる!! (2匹の愚かな犬の参照)

そして、証明書のエクスポートダイアログは私にこの非常に細かいメッセージを与えます: alt text

このコードは、次のスニペットを使用して管理者になりすましているときに実行されます: ここをクリック

なぜ知りたいのですか?

(Windows Server 2008R2およびWindows7でテスト済み)

いまいましい!

v3.5にコンパイルすると動作します!!!!

何をすべきか?

18
albertjan

私はまったく同じ問題を抱えていましたが、解決策は本当に簡単でした。私がしなければならなかったのは合格することだけです

X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet

x509Certificate2のctorに。現在、DotNetUtilitiesを使用してbouncycastle証明書を.net証明書に変換していますが、ヘルパーメソッドは(MachineKeySet + PersistKeySetの代わりに)DefaultKeySetを使用して.net証明書を作成します。

そして、次のように秘密鍵を配置します。

var cspParams = new CspParameters
{
      KeyContainerName = Guid.NewGuid().ToString(),
      KeyNumber = (int)KeyNumber.Exchange,
      Flags = CspProviderFlags.UseMachineKeyStore
};

var rsaProvider = new RSACryptoServiceProvider(cspParams);

これがお役に立てば幸いです。

9
Krassi

私には、もう少し別の方法でキーをインポートする必要があるようです。例については、 http://support.Microsoft.com/kb/950090 を参照してください。

さらに、秘密鍵をUseMachineKeyStoreに保存するのは良くありません。ほとんどの場合、一部のユーザーのマイストアに秘密鍵を使用して証明書をインポートし、秘密鍵を使用せずにルートのみの証明書をインポートする必要があります。

秘密鍵をマシンキーストアに保存する必要がある場合は、少なくとも、すべてのユーザーからではなく、一部の選択したユーザーの読み取り専用にキーを保護する必要があります。キーコンテナは、NTFSの他のファイルと同様のセキュリティ記述子を持つファイルシステム内のファイル(ディレクトリ "%ALLUSERSPROFILE%\ Microsoft\Crypto\Keys"のファイルを参照)です。ファイルのセキュリティ記述子を変更するには、CspKeyContainerInfo.CryptoKeySecurityプロパティとAddAccessRuleRemoveAccessRuleなどを使用できます。

[〜#〜]更新された[〜#〜]:まず、長い回答をお詫びします。

プログラムコード を2つの部分に分けることができます。最初の部分では、CA証明書として使用できる自己署名証明書を生成し、それをrootcert.pfxファイルとして保存します。 2番目の部分では、証明書をインポートしますが、rootcert.pfxを使用する代わりに、前に作成したキーのプロパティで満たされたRSACryptoServiceProviderを使用します。

コードの2番目の部分を、より標準的で単純なコードに置き換えることをお勧めします。 で説明されているように、rootcert.pfxから秘密鍵を使用して証明書をインポートします。 http://support.Microsoft.com/kb/950090 。それは非常にうまく機能します。

私はBouncyCastleを使用していないため、コードの最初の部分にコメントすることはできませんでしたが、一般に、コードで行うことは、 MakeCert.exe ユーティリティに関しても行うことができます。 WindowsSDKから。あなたは次のようにすることができます

MakeCert.exe -pe -ss MY -a sha1 -cy authority -len 2048 -m 120 -r -# 1
             -n "CN=Some Root CA, C=NL, OU=BleedingEdge, ST=Somewhere, L=Somelane"

次に、証明書スナップイン(mmc.exeの場合)に関して、秘密鍵の有無にかかわらず証明書をエクスポートできます。上記の例では、特別なEKUに対してCAを制限していないため、制限なしで使用できますが、制限が必要な場合は、 MakeCert.exe にパラメーターを追加するだけです。 。 MakeCert.exeを使用して、CA証明書で署名された他の証明書を作成することもできます。したがって、MakeCert.exeに関してのみ小さなPKIを作成できます。

証明書の作成は、実際にはコードの別の部分であるように思われます。あなたの主な問題は第二部にあります。

CA証明書をインポートする場合は、いくつかの重要な点を考慮する必要があります。

  • 組織のすべての(または多くの)コンピューターのRootまたはAuthRootlocalMachineにインポートする必要がありますが、証明書を秘密鍵なしでインポートする必要があります。あなたは以下に関してこれを行うことができます

CertMgr.exe -add -c CA.cer -s -r localMachine AuthRoot

  • CA証明書を秘密鍵でインポートする必要があります1台のコンピューターにコンピューターおよび他の証明書を発行するユーザーのみ(新しい証明書に署名するユーザーCAの秘密鍵)。CurrentUserMy証明書ストアに証明書をインポートするための1つの使用法。したがって、コンピューター上のコードは次のようになります。

以下:

// import PFX
X509Certificate2 cert = new X509Certificate2 (@"c:\Oleg\rootcert.pfx", "password",
    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
// save certificate and private key
X509Store storeMy = new X509Store (StoreName.My, StoreLocation.CurrentUser);
storeMy.Open (OpenFlags.ReadWrite);
storeMy.Add (cert);

// get certificate without private key
// one can import certificate from rootcert.cer instead
byte[] certBlobWithoutPrivateKey = cert.Export (X509ContentType.Cert);
// save pure certificate in Root of the local machine
X509Certificate2 certWithoutPrivateKey = new X509Certificate2 (certBlobWithoutPrivateKey);
X509Store storeRoot = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
storeRoot.Open (OpenFlags.ReadWrite);
storeRoot.Add (certWithoutPrivateKey);

StoreName.MyStoreLocation.CurrentUserを別の値に変更すると、コードは機能しますが、これを行うことはお勧めしません。

一般に、.NETコードでの証明書のインポートは少し奇妙に見え、内部で何が行われるかを示していません。 Windowsは、CSPに関して秘密鍵(正確には鍵のペア)が保存される場所 Key Containers と、証明書が保存される場所 Certificate Stores のみを認識します(ストアの場所については、 http://msdn.Microsoft.com/en-us/library/bb204781.aspx を参照してください)。キーコンテナに関する情報を証明書ストアに保存できるようにするために、Microsoftは Certificate Extended Properties という名前を導入しました。 ThumbprintFriendlyNameHasPrivateKeyArchivedなどのX509Certificate2の.NETプロパティで使用する場合は、証明書の拡張プロパティを使用します。したがって、CA証明書を2回インポートすることをお勧めします。 1つはRootまたはAuthRootなし設定なしCERT_KEY_PROV_INFO_PROP_IDCertificate Extended Properties もう1つはMyストアありに関する情報の設定秘密鍵(CERT_KEY_PROV_INFO_PROP_ID)を持つ鍵コンテナの場所。さらに、使用直後に秘密鍵を削除し、本当に使用する必要がある場合にのみインポートし、永続的に保持しないことを検討できます。これはすべて、セキュリティを向上させるために重要です。

9
Oleg

この問題が発生しました。FindPrivateKeyツールを実行しているユーザーでもキーにアクセスできないため、「秘密キーのファイル名を取得できません」というメッセージが表示されるようです。ツールをLocalSystemプロセスとして実行できます。

詳細はこちら:

http://www.itsolutionbraindumps.com/2011/02/finding-private-key-for-your.html

ディンコ

2
Dinko Fabricni

基本的な問題は、.NET証明書APIがC++ advapi32証明書マネージャーAPIの単なるラッパーであるため、証明書をWindowsに貼り付ける役割を実際に担うこのAPIに渡されるすべてのオプションを指定できないことです。証明書ストアとキーの永続化。つまり、「seMachineStore」オプションはCspProviderFlagsに渡される必要があり、次にCAPI.CRYPT_MACHINE_KEYSETに渡されます。 。これは、キーが実際に永続化されるかどうかを決定する小さな男です。 X509KeyStorageFlags.PersistKeySetおよびMachineKeySetおよびExportableを設定しても、このオプションが設定されない理由はいくつかあるようです。これらのオプションはすべて、愚かなキーがC:\ ProgramData\Microsoft\Crypto\RSA\MachineKeys \フォルダーにある限り有効です。インポート時にCRYPT_MACHINE_KEYSETが設定されていない場合、advapi32は、証明書ハンドルがGCによって破棄されるとすぐにキーを吹き飛ばします。

解決策:証明書をパーソナルマシンストアにインポートする前に、証明書を信頼されたルートに追加します。 CAPI2からログを読み取る際に 、証明書が「インポート」されるたびに、実際には「X509オブジェクト」への2つの呼び出しが表示されます。常に<Flags value="20" CRYPT_MACHINE_KEYSET="true"/>、(必要なもの)が、「チェーンポリシーの確認」がエラーを返さない限り、もう一方はエラーを返しません。したがって、advapi32は証明書の「有効性」をチェックしており、X509Certificate2に飲み込まれる例外を返します( そのコードに空のキャッチブロックがいくつあるかが大好きです =)またはadvapi32は、信頼できない証明書のキーを永続化しないことを一方的に決定します。 (ちなみに、これは2008年から20012年までの動作の変化だと思いますが、それを証明していません。)これを回避するために、コードにIf-checkを追加して、発行者がサブジェクト(自己署名証明書)は、Myに追加する前に、証明書をルートに追加します。

    if (certificate.Issuer.Equals(certificate.Subject))
    {
        using (X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) { 
            store.Open(OpenFlags.ReadWrite);
            store.Add(certificate);
            store.Close();
        }
    }

    using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine)){ 
        store.Open(OpenFlags.ReadWrite);
        store.Add(certificate);
        store.Close();
    }

注:notにサブジェクトキー識別子が既に含まれている証明書を使用する場合、これは不要であることがわかりました。どういうわけか、APIをトリガーして、SKIを渡すのではなく実際に生成すると、条件がトリガーされて、魔法のCRYPT_MACHINE_KEYSETフラグがadvapi32に渡されます。

0
NitrusCS

新しいX509Certificate2(localPFXPath、inputPass、X509KeyStorageFlags.MachineKeySet&X509KeyStorageFlags.PersistKeySet); |の代わりに&を使用私のために働いた。

0
Mumbles76

通常、ルートの証明書には管理する秘密鍵がありません。 Webリクエストでキーを関連付ける場合は、マイフォルダにインポートする必要があります。クライアント証明書のチェーンがあるTLS/SSl例外があります。証明書のチェーンをすべてマイストアに保存すると、その例外はなくなりました。問題がユーザーアカウントにある場合。証明書を保存するユーティリティは現在のユーザーアカウントを使用し、実際のアプリケーションはシステムアカウントで実行されます。

0
sravani