2009-05-21 6 views
9

Я думал, что это будет просто, но, видимо, это не так. У меня установлен сертификат, который имеет закрытый ключ, экспортируемый, и я хочу программно экспортировать его только с открытым ключом. Другими словами, я хочу получить результат, эквивалентный выбору «Не экспортировать закрытый ключ» при экспорте через certmgr и экспортировании в .CER.Экспорт сертификата X.509 БЕЗ частного ключа

Кажется, что все методы X509Certificate2.Export будут экспортировать закрытый ключ, если он существует, как PKCS # 12, что является противоположностью того, что я хочу.

Есть ли способ использовать C# для этого, или мне нужно начать копать в CAPICOM?

ответ

17

Для всех, кто мог наткнуться на это, я понял это. Если вы укажете X509ContentType.Cert в качестве первого (и единственного) параметра до X509Certificate.Export, он экспортирует только открытый ключ. С другой стороны, указание X509ContentType.Pfx включает закрытый ключ, если таковой существует.

Я мог бы поклясться, что на прошлой неделе я наблюдал за другим поведением, но я должен был иметь закрытый ключ, когда я тестировал. Когда я удалил этот сертификат сегодня и начал с нуля, я увидел, что в экспортированном сертификате не было закрытого ключа.

+0

вы знаете, если есть способ экспортировать только закрытый ключ без всего сертификата ?, я должен высвободиться секретный ключ, как массив байтов, и я не найти любой способ сделать это .... – RRR

+2

@RRR: Что бы вы ни пытались сделать, я бы посоветовал это, потому что «закрытый ключ» сертификата намного больше, чем просто массив байтов, это криптографический * алгоритм *, в частности «Асимметричный алгоритм», а разные сертификаты могут иметь совершенно разные алгоритмы. Если вы потеряете эту информацию, будет очень сложно восстановить и расшифровать/проверить что-либо зашифрованное/подписанное открытым ключом. Если вы действительно хотите попытаться покончить с этим, посмотрите на 'X509Certificate2.PrivateKey' и работайте оттуда. – Aaronaught

+1

@Aaronaught: Обычно вы не хотите экспортировать закрытый ключ вместе с сертификатом. Частный ключ должен оставаться тайной. Вы можете проверить все, что подписано с закрытым ключом, имея только сертификаты - сертификаты содержат только открытый ключ, и это все, что необходимо для проверки подписи. Обычно вы не хотите использовать закрытый ключ для шифрования данных. Кроме того, частные и открытые ключи не являются взаимозаменяемыми - с помощью открытого ключа почти невозможно угадать закрытый ключ, но не наоборот. Итак, держите этот секретный ключ дома. –

6

я нашел следующую программу полезной для успокаивая себя, что RawData свойство сертификата содержит только открытый ключ (MSDN неясен на этом), и что ответ выше относительно X509ContentType.Cert vs. X509ContentType.Pfx работ, как и ожидалось:

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

Он выводит следующее:

 
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