2009-05-21 19 views
9

Pensé que esto sería sencillo, pero aparentemente no lo es. Tengo un certificado instalado que tiene una clave privada, exportable, y quiero exportarlo mediante programación SOLAMENTE con la clave pública. En otras palabras, quiero un resultado equivalente a seleccionar "No exportar la clave privada" al exportar a través de certmgr y exportar a .CER.Exportación de certificado X.509 SIN clave privada

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

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

Respuesta

17

Para cualquier otra persona que haya tropezado con esto, me di cuenta. Si especifica X509ContentType.Cert como el primer (y único) parámetro en X509Certificate.Export, solo exporta la clave pública. Por otro lado, al especificar X509ContentType.Pfx, se incluye la clave privada, si existe.

Podría haber jurado que estaba viendo un comportamiento diferente la semana pasada, pero ya debo haber tenido la clave privada instalada cuando estaba probando. Cuando borré ese certificado hoy y comencé de nuevo desde cero, vi que no había una clave privada en el certificado exportado.

+0

Cómo se sabe si hay una manera de exportar sólo la clave privada del certificado sin que todo ?, tengo que sacar a la clave privada como matriz de bytes, y yo no encuentre la manera de hacerlo ... – RRR

+2

@RRR: lo que sea que intente hacer, le aconsejaría que no lo haga porque la "clave privada" de un certificado es mucho más que una matriz de bytes, es un algoritmo criptográfico *, específicamente un'Algoritmo Asimétrico', y diferentes certificados pueden tener algoritmos completamente diferentes. Si pierde esta información, será muy difícil reconstruir y descifrar/verificar cualquier cosa encriptada/firmada por la clave pública. Si realmente quieres tratar de meterse con él, mira 'X509Certificate2.PrivateKey' y trabaja desde allí. – Aaronaught

+1

@Aaronaught: en general, nunca desea exportar la clave privada junto con el certificado. La clave privada debe seguir siendo un secreto mantenido de cerca. Puede verificar todo lo firmado con la clave privada que tiene solo el certificado: los certificados solo contienen la clave pública, y esto es todo lo que se necesita para verificar una firma. Por lo general, no desea utilizar la clave privada para cifrar datos. Además, las claves privadas y públicas no son intercambiables: dada una clave pública, es casi imposible adivinar la clave privada, pero no al revés. Por lo tanto, mantenga esa clave privada en casa. –

6

me encontré con 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 
Cuestiones relacionadas