在我看来,您应该以其他方式导入密钥。有关示例,请参见http://support.microsoft.com/kb/950090 。
此外,我发现将私钥保存在UseMachineKeyStore
. 在大多数情况下,您需要在某些用户的 My store 中导入带有私钥的证书,并在没有私钥的情况下仅导入 Root 证书。
如果您确实需要将私钥保存在机器密钥存储中,那么您至少应该保护密钥以供某些选定用户读取,而不是从所有人读取。密钥容器只是文件系统中的一个文件(参见目录“%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"
然后,您可以针对证书管理单元(用于 mmc.exe)导出带有或不带有私钥的证书。在上面的示例中,对于某些特殊的 EKU,我没有限制 CA,因此您可以不受任何限制地使用它,但如果您确实需要限制,您可以在MakeCert.exe中添加其他参数。您还可以使用 MakeCert.exe 创建其他使用 CA 证书签名的证书。因此,您只能针对 MakeCert.exe 制作小型 PKI。
在我看来,证书的创建实际上是代码的一个单独部分。你的主要问题在第二部分。
如果你想导入 CA 证书,你应该考虑一些重要的事情:
- 您应该将其导入组织的每台(
Root
或多台)计算机中,但您应该导入不带私钥的证书。您可以在以下方面做到这一点AuthRoot
localMachine
CertMgr.exe -add -c CA.cer -s -r localMachine AuthRoot
- 您应该在一台计算机上导入带有私钥的 CA 证书,并且仅适用于将颁发其他证书的用户(他们将使用 CA 的私钥签署新证书)。一种用于在CurrentUser的My 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);
如果您更改StoreName.My
并更改StoreLocation.CurrentUser
为其他值,该代码将起作用,但我不建议您这样做。
一般来说,在 .NET 代码中导入证书看起来有点奇怪,并且没有显示在后台会做什么。Windows 只知道将保存私钥(确切地说是密钥对)的密钥容器,以及将保存证书的 CSP 和证书存储(请参阅http://msdn.microsoft.com/en-us/library/bb204781 .aspx关于商店的位置)。为了能够在证书存储中保存有关密钥容器的信息,Microsoft 引入了所谓的Certificate Extended Properties。如果您在 .NET 中使用X509Certificate2
like Thumbprint
, FriendlyName
, HasPrivateKey
,的属性Archived
依此类推,您使用证书的扩展属性。所以我建议你导入两次 CA 证书。一次设置Root
或AuthRoot
不设置CERT_KEY_PROV_INFO_PROP_ID
证书扩展属性,一次My
存储使用私钥 ( ) 设置有关密钥容器位置的信息CERT_KEY_PROV_INFO_PROP_ID
。此外,您可以考虑在使用后直接删除私钥,仅在确实需要使用时才导入,而不是永久保留。所有这些对于拥有更好的安全性都很重要。