使用纯.net Framework生成和签署证书请求

Nin*_*rry 19 .net c# cryptography system.security

我正在尝试使用纯.net代码来创建证书请求,并根据我可用的现有CA证书(在Windows证书存储区中或作为单独的文件)从证书请求创建证书.

我知道我有类X509CertificateX509Certificate2可供加载证书并访问他们的信息,但我没有看到中的任何类或功能System.Security.Cryptography,可以用来创建证书请求或签署这样的证书请求创建命名空间新签名证书.

虽然关于System.Security.Cryptography.Pkcs命名空间文档说:

System.Security.Cryptography.Pkcs命名空间提供公钥加密标准(PKCS)的编程元素,包括签名数据,交换密钥,请求证书,公钥加密和解密以及其他安全功能的方法.

那么,如何创建证书请求并使用纯.net类来签署该请求以创建新的X509证书System.Security.Cryptography


注意:

  • 我不想使用像openssl或MakeCert这样的外部可执行文件
  • 我不想使用BouncyCastle
  • 我不想使用Windows 证书注册API
  • 我不想使用本机Win32 API函数

bar*_*njs 40

简短回答:您可以从.NET Framework 4.7.2开始.

此功能最初以CertificateRequest类的形式添加到.NET Core 2.0中,该类可以构建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.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您坚持使用旧版本,则需要更长的答案:要在不添加任何新P/Invokes的情况下实现目标,您需要阅读并理解以下文档:

  • ITU-T X.680 -201508,ASN.1语言
  • IETF RFC 5280或ITU-T X.509,解释X.509证书中字段的文档.
  • IETF RFC 2986解释了PKCS#10认证签名请求
  • ITU-T X.690解释了ASN.1(包括DER)的BER编码系列,它告诉您如何读取和写入字节以实现X.509/PKCS#10的语义含义.

然后你可以写一个DER编写器/阅读器,然后只发出你想要的字节.

  • 可以在.NET Framework 4.7.2早期访问版本中使用CertificateRequest(https://blogs.msdn.microsoft.com/dotnet/2018/02/05/announcing-net-framework-4-7-2-early-access -build-3052 /).当它完全释放时,我(或其他人)会记得编辑答案. (2认同)
  • @mshwf [CA/浏览器论坛的基准要求 (v1.7.2)](https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.7.2.pdf) 仅表示“CA 应生成大于零 (0) 的非连续证书序列号,包含 CSPRNG 的至少 64 位输出。”,这是公共 CA 的指南。如果您是私有 CA:纯随机,递增整数,高 4 字节是整数,低 8 字节是随机的,无论您喜欢什么(只是长度不要超过 20 个字节)。 (2认同)

小智 6

我无法对上面的答案发表评论,所以这作为评论。@基思

如果问题是用于服务器证书的私钥丢失了私钥,我希望这能解释发生了什么。

要结合上面答案中的公钥和私钥,

cert = RSACertificateExtensions.CopyWithPrivateKey(cert, rsa);

这会将私钥与证书捆绑在一起,以便导出到 PFX File.WriteAllBytes("filename", cert.Export(X509ContentType.Pfx, "passphrase for export"));

对于上面提供的示例。该方法CreateSelfSigned返回一个X509Certificate2附加了公钥和私钥的对象。当针对根或从属签名时,该Create方法将仅在对象中创建公钥组件X509Certificate2

我认为这是因为通常的证书方法会使用 CSR 进行签名并返回公钥以供客户端接受,这永远不会将私钥暴露给签名服务器。