Создание самозаверяющего сертификата без внешних библиотек
Мне любопытно узнать, есть ли простой способ создания самозаверяющего сертификата, сопоставимого с приведенным ниже New-SelfSignedCertificate
команда (например, другие провайдеры тоже в порядке). Я хочу использовать только библиотеки.NET без P/Invoke или внешние библиотеки, такие как Bouncy Castle или без вызова PowerShell из приложения.
New-SelfSignedCertificate -DnsName $certificateName -CertStoreLocation $certificateStore -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $certificateNotAfter
Я полагаю, что самой простой альтернативой было бы вызвать PowerShell или использовать библиотеку Nuget, например Bouncy Castle, если это невозможно без внешних средств? Хотя кажется, что если бы я достаточно знал, как создавать сертификаты, можно было бы создать шаблон массива байтов или что-то подобное, и использовать его в X509Certificate2
конструктор.
Похоже, нужно
public X509Certificate2 GenerateCertificate(string fileName, string password, string subjectName, StoreName storeName, DateTime endDate, DateTime notAfter, string provider = "Microsoft Enhanced RSA and AES Cryptographic Provider")
{
//Could provider be taken from https://stackru.com/questions/43474902/generate-self-signed-rsa-2048-sha-256-certificate-pfx-file-using-openssl?
var newCertificate = new X509Certificate2(fileName, password, X509KeyStorageFlags.Exportable);
/*
# The following creates a self-signed certificate with one year of running time.
$currentDate = Get-Date
$certificateEndDate = $currentDate.AddYears(1)
$certificateNotAfter = $certificateEndDate.AddYears(1)
$certificateName = "https://www.test.com/test"
$certificateStore = "Cert:\LocalMachine\My"
New-SelfSignedCertificate -DnsName $certificateName -CertStoreLocation $certificateStore -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $certificateNotAfter
*/
}
Еще несколько вариантов я нашел: Сообщение в блоге Создание сертификатов, подписанных полномочными и самоподписанными в.NET, автором Steve Syfuhs и другим сообщением SO, использующим расширения Mono, Mono.Security не будет устанавливать несколько ключей KeyUsages. Помимо уже обсужденных вариантов, это "что-то вроде этого".
1 ответ
Там нет ничего, чтобы создавать сертификаты в любой выпущенной версии.NET.
В.NET Core 2.0 (который еще не выпущен, но скоро будет) есть и.NET Framework 4.7.2 добавили эту функциональность через CertificateRequest (API, который может делать самоподписанные сертификаты, сертификаты с цепочкой или PKCS#10). запросы на подписание сертификата / сертификата).
Команда PowerShell объединяет три вещи:
- Ключевые параметры хранения (CSP)
- Создание сертификата
- Хранение сертификата (магазин для добавления сертификата)
Чтобы создать самозаверяющий сертификат "несколько наворотов", подходящий для аутентификации сервера TLS на локальном хосте:
X509Certificate2 certificate = null;
var sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddDnsName("localhost");
// New .NET Core Create(int) method. Or use
// rsa = RSA.Create(), rsa.KeySize = newRsaKeySize,
// or (on .NET Framework) new RSACng(newRsaKeySize)
using (RSA rsa = RSA.Create(newRsaKeySize))
{
var certRequest = new CertificateRequest(
$"CN=localhost",
rsa,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
// Explicitly not a CA.
certRequest.CertificateExtensions.Add(
new X509BasicConstraintsExtension(false, false, 0, false));
certRequest.CertificateExtensions.Add(
new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment,
true));
// TLS Server EKU
certRequest.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1"),
},
false));
// Add the SubjectAlternativeName extension
certRequest.CertificateExtensions.Add(sanBuilder.Build());
DateTimeOffset now = DateTimeOffset.UtcNow;
certificate = certRequest.CreateSelfSigned(now, now.AddDays(365.25));
}
Созданный сертификат имеет временный закрытый ключ - в настоящее время он не записывается на диск. Если вас не волнует, какой поставщик хранилища ключей он использует, то в этот момент вам лучше всего экспортировать сертификат (и закрытый ключ) как PFX/PKCS#12, а затем повторно импортировать его с PersistKeySet
(а также Exportable
, так как вы этого хотите), и добавьте импортированную копию в X509Store по вашему выбору.
Если вы заботитесь о поставщике хранилища ключей (в вашем случае - CAPI CSP) или хотите избежать экспорта / импорта, вы можете создать его, используя предварительно сохраненный ключ. Так что вы бы заменить RSA.Create(newRsaKeySize)
с
CAPI:
var cspParameters = new CspParameters(
/* PROV_RSA_AES */ 24,
"Microsoft Enhanced RSA and AES Cryptographic Provider",
Guid.NewGuid().ToString());
using (RSA rsa = new RSACryptoServiceProvider(newRsaKeySize, cspParameters))
CNG:
var keyParams = new CngKeyCreationParameters();
keyParams.Parameters.Add(
new CngProperty(
"Length",
BitConverter.GetBytes(newRsaKeySize),
CngPropertyOptions.Persist));
using (CngKey rsaKey = CngKey.Create(CngAlgorithm.RSA, Guid.NewGuid().ToString(), keyParams)
using (RSA rsa = new RSACng(rsaKey))
А затем добавьте его в открытый экземпляр X509Store обычным способом.
Такое ощущение, что если бы я достаточно знал, как создавать сертификаты, можно было бы создать шаблон байтового массива или тому подобное и использовать его в конструкторе X509Certificate2.
Правда. Но это немного сложно. Вам необходимо изучить ASN.1 ( ITU-T X.680), DER ( ITU-T X.690) и X.509 (либо RFC 5280, либо ITU-T X.509). Если вы хотите создать сертификат, сопряженный с закрытым ключом, вам нужно будет изучить PFX / PKCS # 12 ( RFC 7292, хотя и ограниченный некоторыми более старыми вариантами, если вы не только для Win10), и который имеет кучу обязательное знание тоже.
Я думаю, что это все забавные вещи, о которых нужно узнать, и хорошие вещи, которые нужно знать... но мои коллеги странно смотрят на меня, когда я начинаю рисовать DER на доске, поэтому я, вероятно, не представляю среднестатистическое мнение разработчика о "забаве",