在.NET Core中如何编程创建有效的自签名X509Certificate2证书,而不是从文件加载?

42
我目前使用OpenSSL生成PFX文件。这会导致不必要的依赖,特别是对于Windows用户而言。因此,我找到了一些使用BouncyCastle创建自己证书的示例,但是该库不兼容.NET Core(或者我没有找到兼容的包)。
那么,是否可能只使用.NET core创建自己的自签名X509证书,以避免对OpenSSL(或任何其他证书生成外部工具)的依赖?
编辑:有人(编辑?)建议这个SO问题如何使用C#创建自签名证书?提供了答案。可惜的是,这与.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。

可能是如何使用C#创建自签名证书?的重复问题。 - AStopher
技术还没有达到那个水平 - “这种机制在.NET Core.上尚不可用。”- https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/implementation/key-encryption-at-rest - J. Doe
2个回答

61

我找到了这个 Stack Overflow 的问题,让我找对了方向。 Certificates 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数据的字节数组。

如果你想要PFX文件,X509Certificate2的导出函数可以完成此操作。它返回一个带有原始PFX数据的字节数组。


3
我找了很久这段代码。有许多不正确的版本。你可以通过将request.CertificateExtensions.Add替换为new Request { CertificateExtensions = { new X509KeyUsageExtension(...), new X509EnhancedKeyUsageExtension(...), sanBuilder.Build() } }来简化语法。 - Adassko
1
生成PFX文件的代码如下:var cert = buildSelfSignedServerCertificate(); byte[] certBytes = cert.Export(X509ContentType.Pfx, "PASSWORD"); File.WriteAllBytes("file.pfx", certBytes);但是可能会出现CryptoThrowHelper+WindowsCryptographicException: Key not valid for use in specified state.的错误。解决方法是将.net 6中的X509KeyStorageFlags.MachineKeySet改为X509KeyStorageFlags.Exportable - Remigijus Pankevičius
这一部分将信任链的长度从1更改为2 X509EnhancedKeyUsageExtension(new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false)。有什么想法吗? - matohak

-9

微软的做法是使用makecert和pvk2pfx(来自Windows SDK),而不是在.net代码本身中实现。现在我对.net core不是很熟悉,但由于完整的.net没有本地支持,如果核心版本确实具有该功能,那将让我非常惊讶。

以下是如何执行此操作的说明: https://msdn.microsoft.com/zh-cn/library/ff699202.aspx

编辑:让我重新表述一下:在.net(core)中没有外部依赖项是不可用的。 在完整的.net中有方法,但需要外部dll。


1
抱歉,但这并不是非常有用的。我能够使用OpenSSL甚至跨平台生成PFX证书。问题在于如何避免外部依赖 - 即如何以编程方式创建此类证书。 - Wapac
请注意,我刚刚给您提供了一份“微软最佳实践”的链接,以证明这不仅仅是我的猜测,而且这并不是他们设计的方法。如果这是一个本地功能,人们期望得到的是它们的答案,而不是一些SDK工具。抱歉没有说明得够清楚。 - g6nuk
1
那篇文章可能已经有5-7年的历史了(它提到Visual Studio 2010是最新版本)。在那一年,还没有.NET Core。你如何在Linux上运行pvk2pfx?这不是正确的方法。即使使用OpenSSL也比这个好多了。 - Wapac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接