C# 导出没有私钥的 X.509 证书

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/893757/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 08:42:49  来源:igfitidea点击:

Exporting X.509 certificate WITHOUT private key

c#.netssl-certificatex509certificate2

提问by Aaronaught

I thought this would be straightforward but apparently it isn't. I have a certificate installed that has a private key, exportable, and I want to programmatically export it with the public key ONLY. In other words, I want a result equivalent to selecting "Do not export the private key" when exporting through certmgr and exporting to .CER.

我认为这很简单,但显然不是。我安装了一个证书,该证书有一个可导出的私钥,我想仅使用公钥以编程方式导出它。换句话说,当通过 certmgr 导出并导出到 .CER 时,我想要一个等同于选择“不导出私钥”的结果。

It seems that all of the X509Certificate2.Export methods will export the private key if it exists, as PKCS #12, which is the opposite of what I want.

似乎所有 X509Certificate2.Export 方法都将导出私钥(如果存在),作为 PKCS #12,这与我想要的相反。

Is there any way using C# to accomplish this, or do I need to start digging into CAPICOM?

有什么方法可以使用 C# 来实现这一点,还是我需要开始深入研究 CAPICOM?

采纳答案by Aaronaught

For anyone else who might have stumbled on this, I figured it out. If you specify X509ContentType.Certas the first (and only) parameter to X509Certificate.Export, it only exports the public key. On the other hand, specifying X509ContentType.Pfxincludes the private key if one exists.

对于其他可能偶然发现这一点的人,我想通了。如果您将 指定X509ContentType.Cert为第一个(也是唯一的)参数X509Certificate.Export,则它仅导出公钥。另一方面,X509ContentType.Pfx如果存在私钥,则指定包括私钥。

I could have sworn that I was seeing different behaviour last week, but I must have already had the private key installed when I was testing. When I deleted that certificate today and started again from scratch, I saw that there was no private key in the exported cert.

我可以发誓我上周看到了不同的行为,但我在测试时一定已经安装了私钥。今天我删除了那个证书,从头开始,我看到导出的证书中没有私钥。

回答by Nathan

There is an OpenSSL .NET wrapperyou may find useful.

您可能会发现有一个OpenSSL .NET 包装器很有用。

回答by explunit

I found the following program helpful for reassuring myself that the RawDataproperty of the certificate contains only the public key (MSDN is unclear on this), and that the answer above regarding X509ContentType.Certvs. X509ContentType.Pfxworks as expected:

我发现以下程序有助于让自己确信RawData证书的属性仅包含公钥(MSDN 对此不清楚),并且上面关于X509ContentType.Certvs.的答案X509ContentType.Pfx按预期工作:

using System;
using System.Linq;
using System.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;

class Program
{
    static void Main( string[] args )
    {
        var certPath = @"C:\blah\somecert.pfx";
        var certPassword = "somepassword";

        var orig = new X509Certificate2( certPath, certPassword, X509KeyStorageFlags.Exportable );
        Console.WriteLine( "Orig   : RawData.Length = {0}, HasPrivateKey = {1}", orig.RawData.Length, orig.HasPrivateKey );

        var certBytes = orig.Export( X509ContentType.Cert );
        var certA = new X509Certificate2( certBytes );
        Console.WriteLine( "cert A : RawData.Length = {0}, HasPrivateKey = {1}, certBytes.Length = {2}", certA.RawData.Length, certA.HasPrivateKey, certBytes.Length );

        // NOTE that this the only place the byte count differs from the others
        certBytes = orig.Export( X509ContentType.Pfx );
        var certB = new X509Certificate2( certBytes );
        Console.WriteLine( "cert B : RawData.Length = {0}, HasPrivateKey = {1}, certBytes.Length = {2}", certB.RawData.Length, certB.HasPrivateKey, certBytes.Length );

        var keyIdentifier = ( new X509SecurityToken( orig ) ).CreateKeyIdentifierClause<X509RawDataKeyIdentifierClause>();
        certBytes = keyIdentifier.GetX509RawData();
        var certC = new X509Certificate2( certBytes );
        Console.WriteLine( "cert C : RawData.Length = {0}, HasPrivateKey = {1}, certBytes.Length = {2}", certC.RawData.Length, certC.HasPrivateKey, certBytes.Length );

        Console.WriteLine( "RawData equals original RawData: {0}", certC.RawData.SequenceEqual( orig.RawData ) );

        Console.ReadLine();
    }
}

It outputs the following:

它输出以下内容:

Orig   : RawData.Length = 1337, HasPrivateKey = True
cert A : RawData.Length = 1337, HasPrivateKey = False, certBytes.Length = 1337
cert B : RawData.Length = 1337, HasPrivateKey = True, certBytes.Length = 3187
cert C : RawData.Length = 1337, HasPrivateKey = False, certBytes.Length = 1337
RawData equals original RawData: True