导出X.509证书没有私钥

Aar*_*ght 11 .net c# ssl-certificate x509certificate2

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

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

有没有办法使用C#来实现这一目标,还是我需要开始深入了解CAPICOM?

Aar*_*ght 18

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

我本来可以发誓上周我看到了不同的行为,但我在测试时必须已经安装了私钥.当我今天删除该证书并从头开始时,我看到导出的证书中没有私钥.

  • @RRR:无论你想要做什么,我都会建议反对它,因为证书的"私钥"不仅仅是一个字节数组,它是一个加密*算法*,特别是`AsymmetricAlgorithm `,并且不同的证书可能有完全不同的算法.如果丢失此信息,则很难重建和解密/验证由公钥加密/签名的任何内容.如果你真的想要弄乱它,看看`X509Certificate2.PrivateKey`并从那里开始工作. (3认同)
  • @Aaronaught:您通常从不希望将私钥与证书一起导出。私钥必须保持秘密。您可以验证使用仅具有证书的私钥签名的任何内容-证书仅包含公钥,这就是验证签名所需要的全部。通常,您不想使用私钥来加密数据。而且,私钥和公钥不可互换-给定公钥,几乎不可能猜出私钥,反之亦然。因此,请将该私钥放在家里。 (2认同)

exp*_*nit 9

我发现以下程序有助于让我自己确认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();
    }
}
Run Code Online (Sandbox Code Playgroud)

它输出以下内容:

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