如何以编程方式将带有证书链的pfx导入证书存储

本文关键字:证书链 pfx 导入 存储 证书 编程 方式 | 更新日期: 2023-09-27 18:22:23

我正在尝试以编程方式将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时,它确实显示了完整的路径。我是跳过了一步,还是遗漏了一些参数?有人能解释一下吗?

如何以编程方式将带有证书链的pfx导入证书存储

通过将PFX文件作为X509Certificate2Collection对象打开,您应该能够迭代PFX中的证书(并将每个证书导入到您选择的证书存储中)。

以下是X509Certificate2的文档集合:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2collection.aspx

MSDN在文档页面中提供了一些关于如何检查集合中的每个证书的示例代码。

一旦您知道了每个证书的CN/Issuers/其他信息,就应该清楚每个证书都需要添加到哪个证书存储。为此,您可以使用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问题的回答:

如何使用c#从pfx文件中检索证书?

正如该答案的最新评论中所提到的,当您尝试将证书导入当前用户的根存储("StoreName.Root"answers"StoreLocation.CurrentUser"作为名称/位置)时,您将收到一个弹出对话框,要求您进行确认。

为了解决这个问题,我只是在我的证书导入方法中添加了一点MSUIAutomation代码,然后在提示中单击"确定"。

或者,正如评论者"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
}

为了将来参考,我发现了另一种方法,使用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
}

对于任何想要"到适当的商店"代码通用解决方案的人

这是我用VB创建的,所以不应该很难移植到C#。我用上面的帖子让我开始,我在这方面完全不在行。

    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()

X.509证书只包含一个链接到根证书(包括中间机构)的链,但这些证书不包含在证书中。此链用于验证末端证书(非自签名)时,它必须导致一个受信任的根证书。更准确地说,每个CA的公钥用于解码和验证已颁发证书的哈希。重复此过程,直到到达根证书。在检查了整个链之后,如果根证书是可信的,那么最终证书也是可信的。当然,这个过程还包括其他验证(例如,开始日期、结束日期、证书吊销列表),但我只详细介绍了与链的使用有关的部分。

因此,您已将"我的证书"与链一起正确导入到"根证书CA"-此链编码在"我的证明"中,您可以通过查看其属性来确认这一点,但此链只是一个链接,不包含任何"根证书证书CA"、"组织证书CA"answers"组织2证书CA"证书。

我希望这能解决你的问题,但如果不能,你能更具体地说明你想实现什么吗?