2009-05-21 17 views
9

Myślałem, że to będzie proste, ale najwyraźniej tak nie jest. Mam zainstalowany certyfikat, który ma klucz prywatny, który można wyeksportować i chcę programowo wyeksportować go TYLKO za pomocą klucza publicznego. Innymi słowy, chcę, aby wynik był równoważny wybraniu "Nie eksportuj klucza prywatnego" podczas eksportowania przez certmgr i eksportowania do .CER.Eksportowanie certyfikatu X.509 BEZ klucza prywatnego

Wygląda na to, że wszystkie metody X509Certificate2.Export wyeksportują klucz prywatny, jeśli istnieje, jako PKCS # 12, który jest przeciwieństwem tego, co chcę.

Czy jest jakiś sposób użycia C# do osiągnięcia tego, czy muszę zacząć kopać w CAPICOM?

Odpowiedz

17

Dla każdego, kto mógł się o to potknąć, odkryłem to. Jeśli podasz X509ContentType.Cert jako pierwszy (i jedyny) parametr na X509Certificate.Export, wyeksportuje tylko klucz publiczny. Z drugiej strony określenie X509ContentType.Pfx zawiera klucz prywatny, jeśli taki istnieje.

Mogłem przysiąc, że widziałem inne zachowanie w zeszłym tygodniu, ale musiałem już mieć zainstalowany klucz prywatny, kiedy testowałem. Kiedy usunąłem ten certyfikat dzisiaj i zacząłem od nowa, zobaczyłem, że w wyeksportowanym certyfikacie nie ma klucza prywatnego.

+0

wiesz, czy istnieje sposób, aby eksportować tylko klucz prywatny bez całego świadectwa ?, muszę wydobyć klucz prywatny jako tablicy bajtów, a ja nie znajdź jakikolwiek sposób to zrobić ... – RRR

+2

@RRR: Niezależnie od tego, co próbujesz zrobić, odradzam, ponieważ "klucz prywatny" certyfikatu jest o wiele więcej niż tylko tablicą bajtów, jest to algorytm kryptograficzny *, w szczególności "AsymmetricAlgorithm", a różne certyfikaty mogą mieć zupełnie inne algorytmy. Jeśli utracisz te informacje, bardzo trudno będzie zrekonstruować i odszyfrować/zweryfikować wszystko, co zaszyfrowane/podpisane przez klucz publiczny. Jeśli naprawdę chcesz spróbować zadziwić, spójrz na 'X509Certificate2.PrivateKey' i zacznij od tego. – Aaronaught

+1

@Aaronaught: Generalnie nigdy nie chcesz eksportować klucza prywatnego wraz z certyfikatem. Klucz prywatny musi pozostać ściśle tajnym. Możesz zweryfikować wszystko podpisane kluczem prywatnym posiadającym tylko certyfikat - certyfikaty zawierają tylko klucz publiczny i to wszystko, co jest potrzebne do zweryfikowania podpisu. Zwykle nie chcesz używać klucza prywatnego do szyfrowania danych. Klucze prywatne i publiczne nie są wymienne - biorąc pod uwagę klucz publiczny, trudno jest odgadnąć klucz prywatny, ale nie odwrotnie. Tak więc trzymaj ten prywatny klucz w domu. –

6

znalazłem następujący program pomocny dla uspokojenia się, że właściwość certyfikatu RawData zawiera tylko klucz publiczny (MSDN jest jasne w tej sprawie), i że odpowiedź powyżej dotyczące X509ContentType.Cert vs. X509ContentType.Pfx działa zgodnie z oczekiwaniami:

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

to wyprowadza następujące:

 
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