无需外部库即可生成自签名证书 [英] Generating self-signed certificate without external libraries

查看:27
本文介绍了无需外部库即可生成自签名证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很想知道是否有一种简单的方法可以创建类似于下面的 New-SelfSignedCertificate 命令的自签名证书(例如,其他提供商也可以).我只想使用没有 P/Invoke 的 .NET 库或 Bouncy Castle 等外部库或不从应用程序调用 PowerShell.

I'm curious to know if there's a simplish way to create a self-signed certificate comparable to the below New-SelfSignedCertificate command (other providers are OK too, for instance). I want to use only the .NET libraries without P/Invoke or external libraries such as Bouncy Castle or without calling PowerShell from the application.

New-SelfSignedCertificate -DnsName $certificateName -CertStoreLocation $certificateStore -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $certificateNotAfter

我想最简单的替代方法是调用 PowerShell 或使用 Nuget 库(例如 Bouncy Castle),如果没有外部设施这不可行?虽然感觉如果我对如何构造证书有足够的了解,就可以创建一个字节数组模板等,并在 X509Certificate2 构造函数中使用它.

I suppose the simplest alternative would be to call PowerShell or use a Nuget library such as Bouncy Castle, if this isn't doable without external facilities? Though it feels like that if I knew enough how to construct certificates, it'd be possible to create a byte array template or such and use that in the X509Certificate2 constructor.

看来需要

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://stackoverflow.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:LocalMachineMy"
     New-SelfSignedCertificate -DnsName $certificateName -CertStoreLocation $certificateStore -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $certificateNotAfter
     */
}

<edit:很明显,使用普通的 .NET 没有什么好的方法可以做到这一点.

<edit: It quickly became apparent there isn't a good way to do this with plain .NET.

我发现了更多选项:

一篇博文 Steve Syfuhs 和另一篇使用 Mono 扩展的 SO 帖子Mono.Security 不会设置多个 KeyUsages.除了已经讨论过的选择之外,它是类似的东西".

A blog post Creating Authority-Signed and Self-Signed Certificates in .NET by Steve Syfuhs and another SO post using Mono extensions, Mono.Security won't set multiple KeyUsages. Apart from the choices already discussed, it's "something like this".

推荐答案

在任何已发布的 .NET 版本中都无需创建证书.

.NET Core 2.0 (尚未发布,但应该很快) 和 .NET Framework 4.7.2 已通过 CertificateRequest(可以执行自签名证书的 API、链签名证书或 PKCS#10 证书/证书签名请求).

.NET Core 2.0 (which hasn't released yet, but should soon) has and .NET Framework 4.7.2 have added this functionality via CertificateRequest (an API which can do self-signed certs, chain-signed certs, or PKCS#10 certificate/certification signing requests).

PowerShell 命令结合了三件事:

The PowerShell command is combining three things:

  • 关键存储参数(CSP)
  • 证书创建
  • 证书存储(要将证书添加到的存储)

要创建一个少量装饰"自签名证书适用于本地主机上的 TLS 服务器身份验证:

To create a "few-frills" self-signed certificate good for TLS server authentication on localhost:

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.

The certificate this created has an ephemeral private key -- it's not currently written to disk. If you don't care what key storage provider it uses then at this point your best bet would be to export the certificate (and private key) as a PFX/PKCS#12, then re-import it with PersistKeySet (and Exportable, since you want that), and add the imported copy to the X509Store of your choosing.

如果您关心密钥存储提供程序(在您的情况下是 CAPI CSP),或者您想避免导出/导入,您可以使用预先保留的密钥创建它.所以你要把 RSA.Create(newRsaKeySize) 替换为

If you care about the key storage provider (in your case, a CAPI CSP), or you want to avoid export/import, you can create it using a pre-persisted key. So you'd replace RSA.Create(newRsaKeySize) with

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))

压缩天然气:

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 实例中.

And then add it to an open X509Store instance in the usual way.

感觉就像如果我对如何构造证书有足够的了解,就可以创建一个字节数组模板等,并在 X509Certificate2 构造函数中使用它.

it feels like that if I knew enough how to construct certificates, it'd be possible to create a byte array template or such and use that in the X509Certificate2 constructor.

没错.但这有点棘手.你需要学习 ASN.1 (ITU-T X.680)、DER(ITU-T X.690) 和 X.509(RFC 5280ITU-T X.509).如果您想创建与私钥配对的证书,则需要学习 PFX/PKCS#12 (RFC 7292,但仅限于某些较旧的选项,除非您仅使用 Win10)并且也有大量先决条件知识.

True. But it is a tad bit tricky. You'd need to learn ASN.1 (ITU-T X.680), DER (ITU-T X.690) and X.509 (either RFC 5280 or ITU-T X.509). If you wanted to create the certificate mated with the private key you'd then need to learn PFX/PKCS#12 (RFC 7292, though limited to some of the older options unless you're Win10-only) and that has a bunch of prerequisite knowledge, too.

我认为这些都是值得学习的有趣东西,也是值得了解的好东西……但是当我开始在白板上涂鸦 DER 时,我的同事们给了我奇怪的眼神,所以我可能不代表开发人员的一般意见好玩".

I think these are all fun things to learn about, and good things to know... but my colleagues give me strange looks when I start doodling DER on a whiteboard, so I probably don't represent the average developer opinion of "fun".

这篇关于无需外部库即可生成自签名证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆