Pergunta

Eu pensei que isso seria simples, mas aparentemente não é. Eu tenho um certificado instalado que tem uma chave privada, exportáveis, e eu quero exportar programaticamente com a chave pública só. Em outras palavras, eu quero um resultado equivalente a selecionar "Não exportar a chave privada" ao exportar através certmgr e exportando para .CER.

Parece que todos os métodos X509Certificate2.Export vai exportar a chave privada, se existir, como PKCS # 12, que é o oposto do que eu quero.

Existe alguma maneira usando C # para fazer isso, ou eu preciso para começar a cavar em CAPICOM?

Foi útil?

Solução

Para qualquer outra pessoa que possa ter tropeçado sobre isso, eu descobri-lo. Se você especificar X509ContentType.Cert como o parâmetro primeiro (e único) para X509Certificate.Export, ele só exporta a chave pública. Por outro lado, especificando X509ContentType.Pfx inclui a chave privada, se existir.

Eu poderia jurar que eu estava vendo um comportamento diferente na semana passada, mas já deve ter tido a chave privada instalada quando eu estava testando. Quando eu apaguei esse certificado hoje e começou de novo a partir do zero, eu vi que não havia chave privada do certificado exportado.

Outras dicas

Eu encontrei o seguinte programa útil para tranquilizar-me que a propriedade RawData do certificado contém apenas a chave pública (MSDN não é clara sobre isso), e que a resposta acima referente X509ContentType.Cert vs. X509ContentType.Pfx funciona como esperado:

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

Ele produz o seguinte:

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

Há um OpenSSL .NET invólucro você pode achar útil.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top