2009-05-21 10 views
9

Ho pensato che sarebbe stato semplice ma a quanto pare non lo è. Ho installato un certificato con una chiave privata, esportabile, e desidero esportarlo programmaticamente con la chiave pubblica SOLO. In altre parole, voglio un risultato equivalente a selezionare "Non esportare la chiave privata" quando esporti attraverso certmgr ed esporti in .CER.Esportazione certificato X.509 SENZA chiave privata

Sembra che tutti i metodi X509Certificate2.Export esporteranno la chiave privata se esiste, come PKCS # 12, che è l'opposto di quello che voglio.

È possibile utilizzare C# per eseguire questa operazione oppure è necessario iniziare a scavare in CAPICOM?

risposta

17

Per chiunque altro abbia inciampato su questo, l'ho capito. Se si specifica X509ContentType.Cert come il primo (e unico) parametro su X509Certificate.Export, viene esportata solo la chiave pubblica. D'altra parte, specificare X509ContentType.Pfx include la chiave privata se ne esiste una.

Avrei potuto giurare che stavo vedendo un comportamento diverso la scorsa settimana, ma devo aver già installato la chiave privata durante il test. Quando ho cancellato quel certificato oggi e ricominciato da capo, ho visto che non c'era una chiave privata nel certificato esportato.

+0

fai a sapere se c'è un modo per esportare solo la chiave privata senza il tutto certificato ?, devo districarmi la chiave privata come array di byte, e io non trova un modo per farlo ... – RRR

+2

@RRR: Qualunque cosa tu stia cercando di fare, ti sconsigliamo perché la "chiave privata" di un certificato è molto più di un semplice array di byte, è un algoritmo * crittografico *, in particolare un 'AsymmetricAlgorithm', e diversi certificati possono avere algoritmi completamente diversi. Se perdi questa informazione, sarà molto difficile ricostruire e decifrare/verificare qualsiasi cosa criptata/firmata dalla chiave pubblica. Se vuoi davvero provare a fare scherzi, guarda 'X509Certificate2.PrivateKey' e lavora da lì. – Aaronaught

+1

@Avatar: in genere non si desidera esportare la chiave privata insieme al certificato. La chiave privata deve rimanere un segreto strettamente segreto. È possibile verificare qualsiasi cosa firmata con la chiave privata avente solo il certificato - i certificati contengono solo la chiave pubblica, e questo è tutto ciò che è necessario per verificare una firma. In genere non si desidera utilizzare la chiave privata per crittografare i dati. Inoltre, le chiavi private e pubbliche non sono intercambiabili: data una chiave pubblica è quasi impossibile indovinare la chiave privata, ma non viceversa. Quindi, mantieni quella chiave privata a casa. –

6

ho trovato il seguente programma utile per rassicurare me stesso che la proprietà del certificato RawData contiene solo la chiave pubblica (MSDN non è chiaro su questo), e che la risposta di cui sopra per quanto riguarda X509ContentType.Cert vs. X509ContentType.Pfx funziona come previsto:

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

Produce il seguente:

 
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