用 X509Certificate2
和 CertificateRequest
生成自签名证书
.NET Core 2.1+ 和 .NET 5+ 提供了纯托管的证书生成功能,无需调用 Windows CryptoAPI 或 OpenSSL。核心是
CertificateRequest类,它支持 RSA/ECDSA、指定扩展(如 SAN)、有效期等。直接 new 一个请求,调用
CreateSelfSigned即可拿到
X509Certificate2实例。
常见错误:在 .NET Framework 4.7.2 及更早版本中,
CertificateRequest不可用,必须降级用
CspParameters+
RSA手动构造,或改用第三方库(如 BouncyCastle)。 推荐密钥长度:RSA 至少
2048,ECDSA 推荐
secp256r1必须设置
Subject(哪怕只是
"CN=localhost"),否则
CreateSelfSigned抛
ArgumentException若需浏览器信任(如本地 HTTPS 测试),务必添加
SubjectAlternativeName扩展,否则 Chrome 会报
NET::ERR_CERT_INVALID
导出为 .pfx
(含私钥)和 .cer
(仅公钥)
X509Certificate2的
Export方法支持多种格式。导出
.pfx必须传入密码且使用
X509ContentType.Pkcs12;导出
.cer推荐用
X509ContentType.Cert(DER 编码)或
X509ContentType.Pkcs7(PEM 封装的 Base64),后者更易被文本编辑器查看。
容易踩的坑:
Export(X509ContentType.Cert)不包含私钥,但如果你从 PFX 文件加载证书后没显式指定
X509KeyStorageFlags.Exportable,即使原 PFX 有私钥,
Export也会失败并抛
CryptographicException: The parameter is incorrect。 写入
.pfx:用
cert.Export(X509ContentType.Pkcs12, "password123"),再
File.WriteAllBytes("test.pfx", bytes)
写入 PEM 格式 .cer:先
cert.Export(X509ContentType.Cert)得到 DER 字节数组,再手动 Base64 编码并套上
-----BEGIN CERTIFICATE-----头尾 避免用
cert.Export(X509ContentType.SerializedCert)—— 它是 .NET 私有序列化格式,其他工具无法识别
给证书加 Subject Alternative Name(SAN)扩展
现代 HTTPS 测试几乎必加 SAN,否则
https://localhost或
https://127.0.0.1会被浏览器拒绝。.NET 的
CertificateRequest允许通过
AddExtension注入
X509Extension,但更稳妥的是用内置的
X509SubjectAlternativeNameExtension构造器。
注意:不能把 DNS 名和 IP 地址混在一个
X509SubjectAlternativeNameExtension实例里传进去 —— 必须分开调用两次
AddDnsName和
AddIpAddress,否则解析失败导致证书无效。 添加 localhost:调用
req.AddDnsName("localhost")
添加 IPv4:用 req.AddIpAddress(IPAddress.Parse("127.0.0.1"))
添加通配符(仅限测试):req.AddDnsName("*.test.local"),但需确保本地 hosts 绑定对应域名
完整示例:生成带 SAN 的 PFX 用于 Kestrel HTTPS 测试
以下代码在 .NET 6+ 下可直接运行,生成的
test.pfx可直接配置到
Program.cs的 Kestrel HTTPS 端点:
var distinguishedName = new X500DistinguishedName("CN=localhost");
using var req = new CertificateRequest(distinguishedName, RSA.Create(2048), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
req.AddExtension(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment, critical: true);
req.AddDnsName("localhost");
req.AddIpAddress(IPAddress.IPv6Loopback); // 同时支持 [::1]
using var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1));
File.WriteAllBytes("test.pfx", cert.Export(X509ContentType.Pkcs12, "devpass"));
如果后续要用这个 PFX 在 Linux/macOS 上跑 ASP.NET Core,记得确认 OpenSSL 版本 ≥ 1.1.1,否则可能因 PKCS#12 密码派生算法不兼容而加载失败。
