Генерация и подпись запроса сертификата с использованием чистого.net Framework
Я пытаюсь использовать чистый код.net для создания запроса на сертификат и создания сертификата на основе запроса сертификата на основе имеющегося у меня сертификата CA (в хранилище сертификатов Windows или в отдельном файле).
Я знаю, что у меня есть классы X509Certificate
а также X509Certificate2
доступны для загрузки сертификатов и получения доступа к их информации, но я не вижу никаких классов или функций в System.Security.Cryptography
пространство имен, которое можно использовать для создания запроса на сертификат или для подписи такого запроса на сертификат для создания нового подписанного сертификата.
И это хотя документация на System.Security.Cryptography.Pkcs
Пространство имен говорит:
Пространство имен System.Security.Cryptography.Pkcs предоставляет элементы программирования для стандартов шифрования с открытым ключом (PKCS), в том числе методы подписи данных, обмена ключами, запроса сертификатов, шифрования и дешифрования открытого ключа и других функций безопасности.
Итак, как я могу создать запрос сертификата и подписать этот запрос для создания нового сертификата X509, используя только чистые классы.net из System.Security.Cryptography
?
Замечания:
- Я не хочу использовать внешний исполняемый файл, такой как openssl или MakeCert
- Я не хочу использовать BouncyCastle
- Я не хочу использовать API регистрации сертификатов Windows
- Я не хочу использовать встроенные функции Win32 API
2 ответа
Краткий ответ: Вы можете начать с.NET Framework 4.7.2.
Первоначально эта функциональность была добавлена в.NET Core 2.0 в форме класса CertificateRequest, который может создавать запрос подписи сертификации PKCS#10 или сертификат открытого ключа X.509 (самоподписанный или цепочечный).
Классы для этой функции были доступны в.NET Framework 4.7.2.
using (RSA parent = RSA.Create(4096))
using (RSA rsa = RSA.Create(2048))
{
CertificateRequest parentReq = new CertificateRequest(
"CN=Experimental Issuing Authority",
parent,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
parentReq.CertificateExtensions.Add(
new X509BasicConstraintsExtension(true, false, 0, true));
parentReq.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(parentReq.PublicKey, false));
using (X509Certificate2 parentCert = parentReq.CreateSelfSigned(
DateTimeOffset.UtcNow.AddDays(-45),
DateTimeOffset.UtcNow.AddDays(365)))
{
CertificateRequest req = new CertificateRequest(
"CN=Valid-Looking Timestamp Authority",
rsa,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
req.CertificateExtensions.Add(
new X509BasicConstraintsExtension(false, false, 0, false));
req.CertificateExtensions.Add(
new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation,
false));
req.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.8")
},
true));
req.CertificateExtensions.Add(
new X509SubjectKeyIdentifierExtension(req.PublicKey, false));
using (X509Certificate2 cert = req.Create(
parentCert,
DateTimeOffset.UtcNow.AddDays(-1),
DateTimeOffset.UtcNow.AddDays(90),
new byte[] { 1, 2, 3, 4 }))
{
// Do something with these certs, like export them to PFX,
// or add them to an X509Store, or whatever.
}
}
}
Более длинный ответ, если вы застряли на более старых версиях: чтобы достичь цели без добавления каких-либо новых вызовов P/Invoces, вам необходимо прочитать и понять следующие документы:
- МСЭ-T X.680-201508, язык ASN.1
- IETF RFC 5280 или ITU-T X.509, документы, поясняющие поля в сертификатах X.509.
- IETF RFC 2986, объясняет запрос подписи сертификации PKCS#10
- В МСЭ-T X.690 поясняется семейство кодирования BER для ASN.1 (включая DER), в котором рассказывается, как читать и записывать байты для достижения семантического значения из X.509 / PKCS#10.
И тогда вы могли бы написать писателя / читателя DER, и просто испустить байты для того, что вы хотите.
Я не могу комментировать ответ выше, так что это служит комментарием.@Keith
Если проблема заключается в закрытом ключе, используемом для сертификата сервера, отсутствует закрытый ключ, я надеюсь, что это объясняет, что происходит.
Чтобы объединить открытый и закрытый ключи в ответе выше,
cert = RSACertificateExtensions.CopyWithPrivateKey(cert, rsa);
Это свяжет закрытый ключ с сертификатом для экспорта в PFX с
File.WriteAllBytes("filename", cert.Export(X509ContentType.Pfx, "passphrase for export"));
для примера, приведенного выше. Метод
Я думаю, это связано с тем, что обычные методы сертификатов будут использовать CSR для подписи и возврата открытого ключа для принятия клиентом, который никогда не предоставит закрытый ключ серверу подписи.