You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中使用BouncyCastle为CSR添加Subject Alternative Name(SAN)

使用BouncyCastle生成带SAN扩展的CSR(C#)

核心问题分析

你遇到的错误根源是直接将Dictionary<DerObjectIdentifier, X509Extension>传给Pkcs10CertificationRequest构造函数不符合类型要求,该构造函数需要的是**Asn1Set格式的扩展集合**,而非字典结构,必须先完成格式转换。

完整实现代码示例

以下是可直接运行的完整流程代码,包含密钥对生成、SAN扩展构造、CSR组装:

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
using System.Collections.Generic;
using System.IO;

public class CsrWithSanGenerator
{
    public static Pkcs10CertificationRequest GenerateCsr()
    {
        // 1. 生成RSA密钥对(2048位,可按需调整长度)
        var keyGenerator = new RsaKeyPairGenerator();
        keyGenerator.Init(new KeyGenerationParameters(new SecureRandom(), 2048));
        AsymmetricCipherKeyPair keyPair = keyGenerator.GenerateKeyPair();

        // 2. 构造证书主体DN信息
        var subjectEntries = new List<X509NameEntry>
        {
            new X509NameEntry(X509Name.CN, "example.com"),
            new X509NameEntry(X509Name.O, "Example Organization"),
            new X509NameEntry(X509Name.C, "US")
        };
        var subjectDN = new X509Name(subjectEntries);

        // 3. 构造Subject Alternative Name扩展
        var sanNames = new GeneralNames();
        // 添加支持的SAN类型:域名、IP等
        sanNames.AddName(new GeneralName(GeneralName.DnsName, "example.com"));
        sanNames.AddName(new GeneralName(GeneralName.DnsName, "www.example.com"));
        sanNames.AddName(new GeneralName(GeneralName.IPAddress, "192.168.1.100"));

        var sanExtension = new X509Extension(
            false, // SAN通常设为非关键扩展
            new DerOctetString(sanNames));

        // 4. 将扩展转换为Asn1Set格式(解决类型不匹配问题的关键)
        var extensionDict = new Dictionary<DerObjectIdentifier, X509Extension>
        {
            { X509Extensions.SubjectAlternativeName, sanExtension }
        };

        var extensionGenerator = new X509ExtensionsGenerator();
        foreach (var ext in extensionDict)
        {
            extensionGenerator.AddExtension(ext.Key, ext.Value.IsCritical, ext.Value.GetValue());
        }
        Asn1Set extensionSet = extensionGenerator.Generate().ToAsn1Object();

        // 5. 构造并返回PKCS#10 CSR
        return new Pkcs10CertificationRequest(
            "SHA256withRSA",
            subjectDN,
            keyPair.Public,
            extensionSet,
            keyPair.Private);
    }

    // 可选:将CSR导出为PEM格式便于验证
    public static string ExportCsrToPem(Pkcs10CertificationRequest csr)
    {
        using var stringWriter = new StringWriter();
        var pemWriter = new Org.BouncyCastle.OpenSsl.PemWriter(stringWriter);
        pemWriter.WriteObject(csr);
        return stringWriter.ToString();
    }
}

关键步骤说明

  • SAN扩展构造:通过GeneralNames和GeneralName类定义SAN条目,支持DNS域名、IP地址、邮箱等多种类型,可根据需求添加。
  • 格式转换:使用X509ExtensionsGenerator将字典格式的扩展转换为Asn1Set,这是解决你遇到的DerBitString错误的核心操作。
  • CSR验证:导出PEM格式后,可使用OpenSSL命令验证SAN扩展是否正确:
    openssl req -text -noout -in csr.pem
    
    在输出中找到X509v3 Subject Alternative Name字段,确认包含你添加的所有条目。

内容的提问来源于stack exchange,提问作者Abraham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:07:28