如何以编程方式将带有证书链的 pfx 导入证书存储区?
Posted
技术标签:
【中文标题】如何以编程方式将带有证书链的 pfx 导入证书存储区?【英文标题】:How to programmatically import a pfx with a chain of certificates into the certificate store? 【发布时间】:2012-02-26 19:28:38 【问题描述】:我正在尝试以编程方式将 X509 证书 (pfx / PKCS#12) 导入本地计算机的证书存储区。这个特定的证书有一个证书链,证书路径看起来像这样:
根证书 CA 组织证书CA 组织 2 证书 CA 我的证书我使用的代码如下所示:
cert = new X509Certificate2(pathToCert, password);
if (cert != null)
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
if (!store.Certificates.Contains(cert))
store.Add(cert);
此代码确实导入了证书,但它似乎忽略了链。如果我在商店里查看证书,证书路径只显示:
我的证书但是,当我手动导入 pfx 时,它确实显示了完整路径。 我是在这里跳过一步,还是缺少一些参数?有人可以对此有所了解吗?
【问题讨论】:
A PFX 通常与 PKCS#12 混淆,在您的情况下,您只需要一个证书链,您可以轻松地使用 PEM 文件进行操作。但是..你有自己的私钥文件吗?在这种情况下,您确实需要 PKCS#12 @IanNorton:它实际上是一个 PKCS#12 证书。这不像我有任何选择。 在这种情况下,您想读取this about pkcs#12 您有一个包含 x509 对象的 p12 文件。 有没有办法将该存储用作存储来验证 SOAP 调用上的证书?? 【参考方案1】:X.509 证书仅包含将其链接到根证书(包括中间机构)的链,但这些证书不包含在证书中。当验证最终证书(非自签名)时使用此链 - 它必须指向受信任的根证书。更准确地说,每个 CA 的公钥用于解码和验证已颁发证书的哈希值。重复此过程,直到达到根证书。检查整个链后,如果根证书受信任,则最终证书也受信任。当然这个过程也包括其他验证(例如开始日期、结束日期、证书撤销列表),但我只详细说明了与链的使用相关的部分。
所以你已经正确地将“我的证书”连同链一起导入到“根证书 CA”——这个链被编码在“我的证书”中,你可以通过查看它的属性来确认这一点,但是这个链只是一个链接,并且它不包含任何“根证书 CA”、“组织证书 CA”和“组织 2 证书 CA”证书。
我希望这可以解决您的问题,但如果没有,您能否更具体地说明您要完成的工作?
【讨论】:
感谢证书理论。问题是,我在导入过程中丢失了链信息,我正试图在我的代码中解决这个问题。【参考方案2】:您应该能够通过将 PFX 文件作为 X509Certificate2Collection 对象打开来遍历 PFX 中的证书(并将每个证书导入您选择的证书存储区)。
这是关于 X509Certificate2Collection 的文档:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2collection.aspx
MSDN 在该文档页面中提供了一些示例代码,说明如何检查集合中的每个证书。
一旦您了解每个证书的 CN/颁发者/其他信息,就应该清楚每个证书需要添加到哪个证书存储。为此,您可以使用 X509Store 类和 StoreName 枚举来指定要打开/添加到哪个商店:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509store.aspx
http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename.aspx
另请参阅我对类似 SO 问题的回答:
How to retrieve certificates from a pfx file with c#?
正如该答案的最新 cmets 之一所述,当您尝试将证书导入当前用户的根存储(“StoreName.Root”和“StoreLocation.CurrentUser”作为名称/位置)时,您将获得一个弹出对话框要求您确认。
为了解决我刚刚在证书导入方法中添加了一点 MS UI 自动化代码的问题,在提示符上单击“确定”。
或者,正如评论者“CodeWarrior”在其他 SO 答案的评论中所说,为避免弹出对话框,您可以尝试将根证书放入 LocalMachine 存储而不是 CurrentUser。
示例代码:
string certPath = <YOUR PFX FILE PATH>;
string certPass = <YOUR PASSWORD>;
// Create a collection object and populate it using the PFX file
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import(certPath, certPass, X509KeyStorageFlags.PersistKeySet);
foreach (X509Certificate2 cert in collection)
Console.WriteLine("Subject is: '0'", cert.Subject);
Console.WriteLine("Issuer is: '0'", cert.Issuer);
// Import the certificate into an X509Store object
【讨论】:
这在我的情况下不起作用,导入集合后仅包含一个证书(我的证书)。不过,我认为您正在做某事。 我曾经遇到过同样的问题(将 PFX 文件作为 X509Certificate2 对象打开导致只导入叶/用户证书)。因此,除非您只需要叶子证书,否则 X509Certificate2 显然不起作用。将 PFX 作为 X509Certificate2Collection 打开是解决方法 - 当您这样做并检查集合的长度(或在 for 循环中打印集合中每个证书的主题/颁发者)时,您是否看到链中的所有证书? 我似乎终于到了某个地方。我从我的证书商店进行了新的导出,现在它似乎正在使用您的代码。它现在显示所有证书,除了根证书......有什么想法吗? 要获得对 PFX 文件内容的第二意见,尝试使用 "openssl.exe pkcs12" (slproweb.com/products/Win32OpenSSL.html) 列出证书链,如下所示:@987654326 @ 仅供参考,任何人在 Powershell 中使用此功能而不会产生编译错误,X509Certificate2Collection.Import 没有像 X509Certificate2.Import 方法那样的 SecureString 重载。【参考方案3】:为了将来参考,我发现了另一种方法,使用 X509Chain 对象:
var cert = new X509Certificate2(pathToCert, password);
X509Chain chain = new X509Chain();
chain.Build(cert);
for (int i = 0; i < chain.ChainElements.Count; i++)
//add to the appropriate store
【讨论】:
您是否有机会分享“到适当的商店”代码以使其成为通用解决方案?【参考方案4】:对于任何想要“到适当的商店”代码通用解决方案的人
这是我使用 VB 创建的,因此移植到 C# 应该不难。我用上面的帖子让我开始了,我在这方面完全是 NooB。
Dim certPath = "C:\Users\08353153\Documents\Visual Studio 2015\Projects\WindowsApplication2\WindowsApplication2\bin\Debug\8870-thebigchess.pfx"
Dim certPass = "eduSTAR.NET"
Dim Collection As New X509Certificate2Collection
Collection.Import(certPath, certPass, X509KeyStorageFlags.PersistKeySet)
Dim certOne As X509Certificate2 = Collection(0)
Dim certTwo As X509Certificate2 = Collection(2)
Dim certThree As X509Certificate2 = Collection(1)
Dim personal As New X509Store(StoreName.My, StoreLocation.LocalMachine)
personal.Open(OpenFlags.ReadWrite)
personal.Add(certOne)
personal.Close()
Dim trust As New X509Store(StoreName.Root, StoreLocation.LocalMachine)
trust.Open(OpenFlags.ReadWrite)
trust.Add(certTwo)
trust.Close()
Dim intermed As New X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine)
intermed.Open(OpenFlags.ReadWrite)
intermed.Add(certThree)
intermed.Close()
【讨论】:
以上是关于如何以编程方式将带有证书链的 pfx 导入证书存储区?的主要内容,如果未能解决你的问题,请参考以下文章