Как создать действительный, самозаверяющий X509Certificate2 программным способом, не загружая из файла в .NET Core

В настоящее время я использую OpenSSL для создания файла PFX. Это вызывает нежелательную зависимость, особенно для пользователей Windows. Поэтому я нашел несколько примеров того, как создать собственный сертификат с помощью BouncyCastle, но эта библиотека не совместима с .NET Core (или мне не удалось найти совместимый пакет).

Итак, можно ли создать собственный сертификат X509 с собственной подписью, используя только ядро ​​.NET, чтобы избежать зависимости от OpenSSL (или любого другого сертификата, генерирующего внешний инструмент)?

EDIT: Кто-то (редактор?) предложил, чтобы этот вопрос SO Как создать самозаверяющий сертификат с помощью С#? дает ответ. К сожалению, это не имеет ничего общего с .NET Core. Принятый ответ начинается с This implementation uses the CX509CertificateRequestCertificate COM object (and friends - MSDN doc) from certenroll.dll to create a self signed certificate request and sign it, который, очевидно, НЕ является .NET Core... На самом деле, ни один из ответов не поддерживает .NET Core.

Ответ 1

Я нашел этот другой ТАК вопрос, который поставил меня на правильный путь. API сертификатов был добавлен в .Net Core версии 2.0. У меня есть функция, подобная следующей, для создания самозаверяющих сертификатов, которые я позже импортирую в "Мой магазин", чтобы использовать их в IIS.

    private X509Certificate2 buildSelfSignedServerCertificate()
    {
        SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
        sanBuilder.AddIpAddress(IPAddress.Loopback);
        sanBuilder.AddIpAddress(IPAddress.IPv6Loopback);
        sanBuilder.AddDnsName("localhost");
        sanBuilder.AddDnsName(Environment.MachineName);

        X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN={CertificateName}");

        using (RSA rsa = RSA.Create(2048))
        {
            var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256,RSASignaturePadding.Pkcs1);

            request.CertificateExtensions.Add(
                new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature , false));


            request.CertificateExtensions.Add(
               new X509EnhancedKeyUsageExtension(
                   new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));

            request.CertificateExtensions.Add(sanBuilder.Build());

            var certificate= request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650)));
            certificate.FriendlyName = CertificateName;

            return new X509Certificate2(certificate.Export(X509ContentType.Pfx, "WeNeedASaf3rPassword"), "WeNeedASaf3rPassword", X509KeyStorageFlags.MachineKeySet);
        }
    }

Если вы хотите PFX, функция экспорта на X509Certificate2 должна сделать свое дело. Возвращает байтовый массив с необработанными данными pfx.

Ответ 2

Путь Microsoft делает это с помощью makecert и pvk2pfx (из окна SDK), а не в самом .net-коде. Теперь я не очень хорошо знаком с ядром .net, но так как полная версия .net не имеет встроенной поддержки, это меня очень удивит, если у базовой версии есть функция.

здесь описание того, как это сделать: https://msdn.microsoft.com/en-us/library/ff699202.aspx

Изменить: Позвольте мне перефразировать его: без внешних зависимостей он недоступен в .net(core).. Есть способы в полномасштабном .net, но для этого вам нужна внешняя dll.