У меня есть файл сертификата, предоставленный другой стороной, который я загружаю в свое приложение и не могу экспортировать параметры его закрытого ключа.Похоже, что сертификат использует CNG, а не CryptoAPI, поэтому я не могу получить доступ к закрытому ключу напрямую, только с помощью метода GetRSAPrivateKey ().Метод возвращает RSACngKey
, а не RSACryptoServiceProvider
, что является другой реализацией RSA.Проблема в том, что возвращенный ключ, кажется, отсутствует CngExportPolicies.AllowPlaintextExport
в его политиках экспорта, и поэтому я не могу экспортировать параметры RSA из этого сертификата.Я могу воспроизвести проблему, сгенерировав новый сертификат, который пропускает необходимые политики экспорта:
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace TestRsaCngConsole
{
class Program
{
static void Main(string[] args)
{
var oldCertificate = CreateCertificate();
var oldCertificateBytes = oldCertificate.Export(X509ContentType.Pfx, "");
var newCertificate = new X509Certificate2(oldCertificateBytes, "",
X509KeyStorageFlags.Exportable |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet);
LogCertificate(oldCertificate, "old certificate"); // this fails
LogCertificate(newCertificate, "new certificate"); // works only on Win10
Console.ReadKey();
}
private static X509Certificate2 CreateCertificate()
{
var keyParams = new CngKeyCreationParameters();
keyParams.KeyUsage = CngKeyUsages.Signing;
keyParams.Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider;
keyParams.ExportPolicy = CngExportPolicies.AllowExport; // here I don't have AllowPlaintextExport
keyParams.Parameters.Add(new CngProperty("Length", BitConverter.GetBytes(2048), CngPropertyOptions.None));
var cngKey = CngKey.Create(CngAlgorithm.Rsa, Guid.NewGuid().ToString(), keyParams);
var rsaKey = new RSACng(cngKey);
var req = new CertificateRequest("cn=mah_cert", rsaKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pss); // requires .net 4.7.2
var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));
return cert;
}
private static void LogCertificate(X509Certificate2 certificate, string name)
{
Console.WriteLine("----- Testing " + name + " ------");
try
{
var rsaPrivateKey = certificate.GetRSAPrivateKey();
var parameters = rsaPrivateKey.ExportParameters(true);
Console.WriteLine("Certificate private key RSA parameters were successfully exported.");
var privateKey = certificate.PrivateKey;
Console.WriteLine("Certificate private key is accessible.");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
Программа показывает следующий вывод при работе в Windows 10:
----- Testing old certificate ------
System.Security.Cryptography.CryptographicException: The requested operation is not supported.
at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format)
at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format)
at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters)
at TestRsaCngConsole.Program.LogCertificate(X509Certificate2 certificate, String name) in D:\Projects\TestRsaCngConsole\TestRsaCngConsole\Program.cs:line 44
----- Testing new certificate ------
Certificate private key RSA parameters were successfully exported.
Certificate private key is accessible.
Итак, первый сертификатне удается экспортировать закрытый ключ, поскольку в его политиках экспорта отсутствует флаг AllowPlaintextExport.Но после перезагрузки старого сертификата с экспортируемыми флагами я могу экспортировать новые параметры сертификата просто отлично.Однако он не работает в Windows Server 2012 или Windows Server 2016 и выдает исключения для обоих сертификатов:
----- Testing old certificate ------
System.Security.Cryptography.CryptographicException: The requested operation is not supported.
at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format)
at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format)
at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters)
at TestRsaCngConsole.Program.LogCertificate(X509Certificate2 certificate, String name) in D:\Projects\TestRsaCngConsole\TestRsaCngConsole\Program.cs:line 44
----- Testing new certificate ------
System.Security.Cryptography.CryptographicException: The requested operation is not supported.
at System.Security.Cryptography.NCryptNative.ExportKey(SafeNCryptKeyHandle key, String format)
at System.Security.Cryptography.CngKey.Export(CngKeyBlobFormat format)
at System.Security.Cryptography.RSACng.ExportParameters(Boolean includePrivateParameters)
at TestRsaCngConsole.Program.LogCertificate(X509Certificate2 certificate, String name) in D:\Projects\TestRsaCngConsole\TestRsaCngConsole\Program.cs:line 44
Мне нужно иметь возможность исправить сертификат и сделать возможным экспорт параметров RSA, дажеесли в сертификате изначально отсутствовал AllowPlaintextExport.Чем отличается Windows Server и есть ли способ исправить сертификат?