如何以编程方式将带有证书链的 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 导入证书存储区?的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenSSL 以编程方式将 .PEM 证书转换为 .PFX

从命令行将 pfx 文件导入特定的证书存储

.P7B 证书转换为 .PFX

以编程方式将证书导入 IIS?

pfx格式文件如何打开?如题 谢谢了

从 .pfx 文件中提取证书和私钥文件