Экспорт сертификата X.509 БЕЗ закрытого ключа
-
23-08-2019 - |
Вопрос
Я думал, что это будет просто, но, видимо, это не так.У меня установлен сертификат с закрытым ключом, который можно экспортировать, и я хочу программно экспортировать его ТОЛЬКО с открытым ключом.Другими словами, мне нужен результат, эквивалентный выбору «Не экспортировать закрытый ключ» при экспорте через certmgr и экспорте в .CER.
Кажется, что все методы X509Certificate2.Export будут экспортировать закрытый ключ, если он существует, как PKCS # 12, что противоположно тому, что я хочу.
Есть ли способ использовать C# для достижения этой цели или мне нужно начать копаться в CAPICOM?
Решение
Для всех, кто мог наткнуться на это, я понял это.Если вы укажете X509ContentType.Cert
в качестве первого (и единственного) параметра X509Certificate.Export
, он экспортирует только открытый ключ.С другой стороны, указав X509ContentType.Pfx
включает закрытый ключ, если он существует.
Я мог бы поклясться, что на прошлой неделе я наблюдал другое поведение, но, должно быть, у меня уже был установлен закрытый ключ, когда я тестировал.Когда я сегодня удалил этот сертификат и начал заново, я увидел, что в экспортированном сертификате нет закрытого ключа.
Другие советы
Я нашел следующую программу полезной, чтобы убедить себя в том, что RawData
свойство сертификата содержит только открытый ключ (MSDN неясно по этому поводу), и что ответ выше относительно X509ContentType.Cert
против. 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
Есть Оболочка OpenSSL .NET вам может пригодиться.