Pregunta

Me pareció que esto sería sencillo, pero al parecer no lo es. Tengo un certificado instalado que tiene una clave privada, exportable, y quiero exportar mediante programación con la clave pública sólo. En otras palabras, quiero un resultado equivalente a seleccionar "No exportar la clave privada" cuando se exporta a través certmgr y la exportación a .CER.

Parece que todos los métodos X509Certificate2.Export se exportar la clave privada si es que existe, como PKCS # 12, que es lo contrario de lo que quiero.

¿Hay alguna manera usando C # para lograr esto, o tengo que empezar a cavar en CAPICOM?

¿Fue útil?

Solución

Para cualquier otra persona que pudiera haber tropezado con esto, lo he descubierto. Si especifica X509ContentType.Cert como primer parámetro (y única) a X509Certificate.Export, sólo se exporta la clave pública. Por otro lado, especificando X509ContentType.Pfx incluye la clave privada si es que existe.

Podría haber jurado que estaba viendo un comportamiento diferente la semana pasada, pero ya tengo que tengan instalada la clave privada cuando tenía pruebas. Cuando he eliminado ese certificado hoy y empecé de nuevo desde cero, vi que no había llave privada en el certificado exportado.

Otros consejos

He encontrado el siguiente programa de ayuda para tranquilizar a mí mismo que la propiedad RawData del certificado contiene sólo la clave pública (MSDN está claro en esto), y que la respuesta anterior con respecto X509ContentType.Cert vs X509ContentType.Pfx funciona como se espera:

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

Se muestra la siguiente información:

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

Hay un OpenSSL .NET envoltorio pueden serle de utilidad.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top