在Root中插入证书(带私钥),LocalMachine证书存储在.NET 4中失败

alb*_*jan 17 c# bouncycastle certificate .net-4.0 x509certificate

我在localmachine的根证书存储中插入带有私钥的新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 ();
Run Code Online (Sandbox Code Playgroud)

证书被插入,它看起来都很花哨:(见!) 请注意它说它有一个私钥

注意:据说它有一个私钥.

所以你会说用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 
Run Code Online (Sandbox Code Playgroud)

它很可爱......但是它错了!(2只愚蠢的狗参考)

证书导出对话框给了我这个非常好的信息: 替代文字

在使用此代码段模拟管理员时运行此代码:单击此处

我只是想知道为什么?

(在Windows Server 2008 R2和Windows 7上测试过)

我完蛋了!

当我将它编译为v3.5时它可以工作!!!!

该怎么办?

Ole*_*leg 9

在我看来,你应该用其他方式导入密钥.有关示例,请参见http://support.microsoft.com/kb/950090.

此外,我发现保存私钥不好UseMachineKeyStore.在大多数情况下,您需要在某个用户的My store中使用私钥导入证书,并在没有私钥的Root only证书中导入.

您需要在计算机密钥存储区中保存私钥,您至少应该保护密钥以便仅为某些选定用户而非Everyone进行读取.密钥容器只是文件系统中的一个文件(请参阅diriectory"%ALLUSERSPROFILE%\ Microsoft\Crypto\Keys"中的文件),该文件具有安全描述符,如NTFS中的其他文件.要更改文件的安全描述符,可以使用CspKeyContainerInfo.CryptoKeySecurity属性等AddAccessRule,RemoveAccessRule等等.

更新:首先抱歉很长的答案.

我可以将程序代码分为两部分.在第一部分中,您将生成一个可以用作CA证书的自签名证书,并将其另存为rootcert.pfx文件.在第二部分中,您导入证书,但使用RSACryptoServiceProvider先前创建的键的属性填充而不是使用rootcert.pfx.

我建议将代码的第二部分替换为更标准和简单的代码:使用rootcert.pfx中的私钥导入证书,如http://support.microsoft.com/kb/950090中所述.它工作得很好.

我不使用BouncyCastle,所以我无法评论你的代码的第一部分,但一般来说你在代码中做了什么,你也可以使用Windows SDK中的MakeCert.exe实用程序.你可以这样做

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"
Run Code Online (Sandbox Code Playgroud)

然后,您可以导出带有或不带有私钥的证书,证书管理单元(对于mmc.exe).在上面的示例中,我不限制某些特殊EKU的CA,因此您可以不受任何限制地使用它,但如果您确实需要这些限制,则可以向MakeCert.exe添加其他参数.您还可以使用MakeCert.exe创建使用CA证书签名的其他证书.因此,您只能使用MakeCert.exe制作小型PKI.

在我看来,创建证书实际上是代码的一个独立部分.你的主要问题在第二部分.

如果您想要导入CA证书,您应该考虑一些重要的事情:

  • 你应该将其导入RootAuthRootlocalMachine您的组织中的每一个(或多个)的计算机上,但你应该导入证书没有私钥.您可以关注以下内容

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

  • 您应该在台计算机上的计算机上导入带有私钥的 CA证书,并且仅针对将颁发其他证书的用户(谁将使用CA的私钥签署新证书).一种用于在CurrentUserMy certificate store中导入证书.所以计算机上的代码看起来像

以下:

// 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);
Run Code Online (Sandbox Code Playgroud)

如果您将更改StoreName.MyStoreLocation.CurrentUser其他值,代码将工作,但我不建议您这样做.

一般情况下,.NET代码中的证书导入看起来有点奇怪,并没有显示将在底层进行的操作.Windows只知道密钥容器,其中将保存关于CSP和证书存储的私钥(完全是密钥对),其中将保存证书(请参阅http://msdn.microsoft.com/en-us/library/bb204781 .aspx关于商店的位置).为了能够在证书存储中保存有关密钥容器的信息,Microsoft引入了如此命名的证书扩展属性.如果您在.NET属性使用X509Certificate2Thumbprint,FriendlyName,HasPrivateKey,Archived等等,您使用证书的扩展属性.所以我建议你两次导入CA证书.一个Root或多个设置或AuthRoot 设置CERT_KEY_PROV_INFO_PROP_ID 证书扩展属性和另外一个时间My存储设置关键容器的位置与私钥(CERT_KEY_PROV_INFO_PROP_ID)的信息.此外,您可以考虑在使用后直接删除私钥,只有在您确实需要使用它而不是永久保留私钥时才导入私钥.所有这些对于提高安全性非常重要.


Kra*_*ssi 9

我有完全相同的问题,解决方案结果非常简单.我所要做的就是通过

X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
Run Code Online (Sandbox Code Playgroud)

到X509Certificate2的ctor.现在您使用DotNetUtilities将bouncycastle证书转换为.net版本,但是helper方法使用DefaultKeySet(而不是MachineKeySet + PersistKeySet)创建.net证书.

并安排这样的私钥:

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

var rsaProvider = new RSACryptoServiceProvider(cspParams);
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助.