更新于 2024-12-09
使用C#原生生成CSR(CertificateSigningRequest)和密钥。
生成的私钥妥善保存,丢失无法找回。
var contents = X509Helper
.SigningRequestHelper
.CreateSigningRequest(
"yourdomain.com",
["*.yourdomain.com"],
X509Helper.AsymmetricAlgorithmType.EC_P256,
out string privateKey
);
Console.WriteLine(contents);
Console.WriteLine(privateKey);
-----BEGIN CERTIFICATE REQUEST-----
MIIBEjCBuQIBADAZMRcwFQYDVQQDEw55b3VyZG9tYWluLmNvbTBZMBMGByqGSM49AgEGCCqGSM49
AwEHA0IABJj1dQnVVGlYxSCzucILf0j+oM1Up7q+5O+IqRXk6+91F4MY+jYmirA/l4pVnADm88Ts
4BOsZQDLL9l860HhZNGgPjA8BgkqhkiG9w0BCQ4xLzAtMCsGA1UdEQQkMCKCDnlvdXJkb21haW4u
Y29tghAqLnlvdXJkb21haW4uY29tMAoGCCqGSM49BAMCA0gAMEUCIQDGpHPxvVodEKQVFiroUQUF
36b3ODhthoghymjjFhl+TQIgAnjkgIkGlmEjr9WIJna2bEOfelRohl/rdiiKnZdlvpA=
-----END CERTIFICATE REQUEST-----
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmECK+y6xcaUBIb5mGjBFlyN2XFLH
/z5zr95ppKMK1t6hRANCAASY9XUJ1VRpWMUgs7nCC39I/qDNVKe6vuTviKkV5OvvdReDGPo2Joqw
P5eKVZwA5vPE7OATrGUAyy/ZfOtB4WTR
-----END PRIVATE KEY-----
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace X509Helper
{
public enum AsymmetricAlgorithmType
{
EC_P256 = 1,
EC_P384 = 2,
EC_P521 = 3,
RSA_2048 = 11,
RSA_4096 = 12,
}
public class SigningRequestHelper
{
/// <summary>
/// 秘钥初始化参数
/// </summary>
private class AsymmetricAlgorithmParameters
{
private readonly AsymmetricAlgorithmType type;
public AsymmetricAlgorithmParameters(AsymmetricAlgorithmType type)
{
this.type = type;
}
public bool IsECC => type < AsymmetricAlgorithmType.RSA_2048;
public bool IsRSA => type >= AsymmetricAlgorithmType.RSA_2048;
/// <summary>
/// 创建非对称加密算法
/// </summary>
/// <returns></returns>
public AsymmetricAlgorithm CreateAsymmetricAlgorithm()
{
return type switch
{
AsymmetricAlgorithmType.EC_P256 => ECDsa.Create(ECCurve.NamedCurves.nistP256),
AsymmetricAlgorithmType.EC_P384 => ECDsa.Create(ECCurve.NamedCurves.nistP384),
AsymmetricAlgorithmType.EC_P521 => ECDsa.Create(ECCurve.NamedCurves.nistP521),
AsymmetricAlgorithmType.RSA_2048 => RSA.Create(2048),
AsymmetricAlgorithmType.RSA_4096 => RSA.Create(4096),
_ => throw new NotSupportedException()
};
}
public CertificateRequest CreateCertificateRequest(X500DistinguishedName names, AsymmetricAlgorithm algorithm)
{
return type switch
{
AsymmetricAlgorithmType.EC_P256 or AsymmetricAlgorithmType.EC_P384 or AsymmetricAlgorithmType.EC_P521
=> new CertificateRequest(names, algorithm as ECDsa, HashAlgorithmName.SHA256),
AsymmetricAlgorithmType.RSA_2048 or AsymmetricAlgorithmType.RSA_4096
=> new CertificateRequest(names, algorithm as RSA, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1),
_ => throw new NotSupportedException()
};
}
}
/// <summary>
/// 创建CSR
/// </summary>
/// <param name="commonName">公用名-commonName</param>
/// <param name="san">备用名称-SubjectAltNames</param>
/// <param name="alg">公钥算法,允许的值:EC-P256, EC-P384, EC-P521, RSA-2048, RSA-4096</param>
/// <param name="privateKey">导出私钥</param>
/// <returns></returns>
public static string CreateSigningRequest(string commonName, List<string> san, AsymmetricAlgorithmType alg, out string privateKey)
{
AsymmetricAlgorithmParameters algorithm = new(alg);
X500DistinguishedName names = new($"CN={commonName}");
using AsymmetricAlgorithm provider = algorithm.CreateAsymmetricAlgorithm();
CertificateRequest request = algorithm.CreateCertificateRequest(names, provider);
//构造SAN扩展
if (san != null && san.Count > 0)
{
if (!san.Contains(commonName)) san.Insert(0, commonName);
SubjectAlternativeNameBuilder builder = new();
foreach (string dnsName in san)
{
builder.AddDnsName(dnsName);
}
request.CertificateExtensions.Add(builder.Build());
}
//导出私钥
privateKey = GenetratePemContents(provider.ExportPkcs8PrivateKey(), "PRIVATE KEY");
//导出CSR
return GenetratePemContents(request.CreateSigningRequest(), "CERTIFICATE REQUEST");
}
private static string GenetratePemContents(byte[] data, string tag)
{
return $"-----BEGIN {tag}-----\r\n{Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks)}\r\n-----END {tag}-----\r\n";
}
}
}