C# 如何以编程方式将带有证书链的 pfx 导入证书存储?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9141198/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to programmatically import a pfx with a chain of certificates into the certificate store?
提问by Edwin de Koning
I am trying to programmatically import a X509 certificate (pfx / PKCS#12) in my local machine's certificate store. This particular certificate has a chain of certificates, the certification path looks something like this:
我正在尝试以编程方式在本地计算机的证书存储中导入 X509 证书 (pfx / PKCS#12)。这个特定的证书有一个证书链,证书路径看起来像这样:
- Root certificate CA
- Organization certificate CA
- Organization 2 certificate CA
- My certificate
- Organization 2 certificate CA
- Organization certificate CA
- 根证书 CA
- 组织证书CA
- 组织 2 证书 CA
- 我的证书
- 组织 2 证书 CA
- 组织证书CA
The code I use looks like this:
我使用的代码如下所示:
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);
}
}
This code does import the certificate, however it seems to ignore the chain. If I check the certificate in the store, the certification path only shows:
此代码确实导入了证书,但它似乎忽略了链。如果我在商店中查看证书,则证书路径仅显示:
- My certificate
- 我的证书
However when I import the pfx manually, it does show the full path. Am I skipping a step here, or am I missing some parameter? Can someone shed some light on this?
但是,当我手动导入 pfx 时,它确实显示了完整路径。我在这里跳过了一步,还是我错过了一些参数?有人可以对此有所了解吗?
采纳答案by Bill Agee
You should be able to iterate over the certs in your PFX (and import each into the cert store of your choice) by opening the PFX file as an X509Certificate2Collection object.
通过将 PFX 文件作为 X509Certificate2Collection 对象打开,您应该能够遍历 PFX 中的证书(并将每个证书导入您选择的证书存储区)。
Here are the docs on X509Certificate2Collection:
以下是 X509Certificate2Collection 上的文档:
MSDN provides some sample code in that docs page on how to inspect each cert in the collection.
MSDN 在该文档页面中提供了一些示例代码,说明如何检查集合中的每个证书。
Once you know the CNs/Issuers/other info about each cert it should be clear which certificate store each one needs to be added to. For that you can use the X509Store class and the StoreName enumeration to specify which store you want to open/add to:
一旦您知道每个证书的 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.x509store.aspx
http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename.aspx
http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename.aspx
Also see my answer to a similar SO question:
另请参阅我对类似问题的回答:
How to retrieve certificates from a pfx file with c#?
As mentioned in one of the latest comments on that answer, when you try to import a cert to the current user's Root store ("StoreName.Root" and "StoreLocation.CurrentUser" as the name/location) you will get a popup dialog asking you to confirm.
正如对该答案的最新评论之一所述,当您尝试将证书导入当前用户的根存储(“StoreName.Root”和“StoreLocation.CurrentUser”作为名称/位置)时,您将收到一个弹出对话框,询问你来确认。
To solve that I just added a little MS UI Automation code to my cert import method, to click OK on the prompt.
为了解决这个问题,我只是在我的证书导入方法中添加了一些 MS UI 自动化代码,在提示上单击“确定”。
Or, as the commenter "CodeWarrior" says in the other SO answer's comment, to avoid the popup dialog you can try putting the root cert into the LocalMachine store instead of CurrentUser.
或者,正如评论者“CodeWarrior”在其他 SO 答案的评论中所说,为了避免弹出对话框,您可以尝试将根证书放入 LocalMachine 存储而不是 CurrentUser。
Sample code:
示例代码:
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
}
回答by andrei m
An X.509 certificate contains only a chain that links it to the root certificate (including the intermediate authorities), but these certificates are not contained in the certificate. This chain is used when an end certificate (that is not self-signed) is validated - it must lead to a root certificate that is trusted. More precisely the public key of each CA is used to decode and verify the hash for an issued certificate. This process is repeated until the root certificate is reached. After the whole chain is checked, if the root certificate is trusted the end certificate is also trusted. Of course the process includes other validations too (like start date, end date, certificate revocation list for example), but I have detailed only the part related to the usage of the chain.
X.509 证书仅包含将其链接到根证书(包括中间机构)的链,但这些证书不包含在证书中。当最终证书(非自签名)被验证时使用此链 - 它必须导致受信任的根证书。更准确地说,每个 CA 的公钥用于解码和验证颁发的证书的哈希值。重复此过程,直到达到根证书。检查整个链后,如果根证书受信任,则最终证书也受信任。当然这个过程也包括其他验证(比如开始日期、结束日期、证书吊销列表),但我只详细说明了与链的使用相关的部分。
So you have correctly imported "My certificate" together with the chain to "Root certificate CA" - this chain is encoded in "My certificate" and you can confirm this by viewing its properties, but this chain is only a link and it does not contain any of "Root certificate CA", "Organization certificate CA" and "Organization 2 certificate CA" certificates.
所以你已经正确地将“我的证书”连同链一起导入到“根证书 CA”——这个链被编码在“我的证书”中,你可以通过查看它的属性来确认这一点,但这个链只是一个链接,它没有包含任何“根证书 CA”、“组织证书 CA”和“组织 2 证书 CA”证书。
I hope this solves your issue, but if it doesn't, could you be more specific about what are you trying to accomplish?
我希望这能解决您的问题,但如果没有,您能否更具体地说明您要完成的工作?
回答by Edwin de Koning
For future reference, I discovered another way of doing this, using the X509Chain 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
}
回答by Clarkey
For anyone who wants "to the appropriate store" code generic solution
对于任何想要“到适当的商店”代码通用解决方案的人
This is what I've created using VB so shouldn't be to hard to port to C#. I used the above posts to get me started and I'm a total NooB at this.
这是我使用 VB 创建的,因此移植到 C# 应该不难。我使用上面的帖子让我开始,我在这方面完全是个菜鸟。
Dim certPath = "C:\Users353153\Documents\Visual Studio 2015\Projects\WindowsApplication2\WindowsApplication2\bin\Debug70-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()

