You need to enable JavaScript to run this app. C#中如何用Portable.BouncyCastle提取X509证书CN及相关信息
优惠活动
大模型
产品
解决方案
定价
更多

C#中如何用Portable.BouncyCastle提取X509证书CN及相关信息

基于Portable.BouncyCastle 1.8.8的规范实现

核心逻辑说明

  • 无需手动拆解DerSequence嵌套:certificate.SubjectDN返回的X509Name类型已封装了X.500 Distinguished Name的标准解析逻辑,可直接提取指定属性
  • 证书有效期可通过内置属性直接获取,无需额外解析ASN.1结构
  • 标准解析可正确处理CN中的转义特殊字符(如逗号、引号),避免正则匹配的截断错误

修正后的完整代码

using Org.BouncyCastle.X509;
using Org.BouncyCastle.Asn1.X509;
// 原有命名空间引用保持不变

using (var streamReader = new StreamReader("cert.pem"))
{
    var pemReader = new PemReader(streamReader);
    while (true)
    {
        object pemObject = pemReader.ReadObject();
        if (pemObject == null)
            break;
        switch (pemObject)
        {
            case RsaPrivateCrtKeyParameters privateKey:
                Console.WriteLine("Private key");
                break;
            case X509Certificate certificate:
                Console.WriteLine("Certificate");
                // 全量主题DN(保留用于调试)
                Console.WriteLine($"  Full Subject DN: {certificate.SubjectDN}");

                // 规范提取CN值(无需正则)
                string subjectCN = certificate.SubjectDN.GetValue(X509Name.CN).ToString();
                Console.WriteLine($"  Subject CN: {subjectCN}");

                // 直接获取证书有效期
                Console.WriteLine($"  Valid From: {certificate.NotBefore:yyyy-MM-dd HH:mm:ss}");
                Console.WriteLine($"  Valid Until: {certificate.NotAfter:yyyy-MM-dd HH:mm:ss}");

                // 规范提取SAN(替换原有硬拆ArrayList的逻辑)
                var sanExtension = certificate.GetExtension(X509Extensions.SubjectAlternativeName);
                if (sanExtension != null)
                {
                    var sanGeneralNames = GeneralNames.GetInstance(sanExtension.GetParsedValue());
                    foreach (var name in sanGeneralNames.GetNames())
                    {
                        Console.WriteLine($"  Subject Alternative Name: {name.ToString()}");
                    }
                }

                break;
        }
    }
}
.NET Core 3.1 / 5 内置库替代方案(无第三方依赖)

适用场景

如果你无需兼容旧版本.NET Framework,可完全移除Portable.BouncyCastle依赖,使用官方System.Security.Cryptography.X509Certificates类库实现,API更简洁、长期维护、跨平台兼容。

核心实现代码

using System.Security.Cryptography.X509Certificates;
using System.Linq;

// 直接从PEM文件加载证书(自动识别BEGIN CERTIFICATE块)
using (var cert = X509Certificate2.CreateFromPemFile("cert.pem"))
{
    Console.WriteLine("Certificate");
    
    // 提取Subject CN(标准解析)
    string subjectCN = cert.GetNameInfo(X509NameType.SimpleName, forIssuer: false);
    Console.WriteLine($"  Subject CN: {subjectCN}");

    // 直接获取有效期
    Console.WriteLine($"  Valid From: {cert.NotBefore:yyyy-MM-dd HH:mm:ss}");
    Console.WriteLine($"  Valid Until: {cert.NotAfter:yyyy-MM-dd HH:mm:ss}");

    // 提取SAN
    var sanExtension = cert.Extensions.FirstOrDefault(e => e.Oid.Value == "2.5.29.17");
    if (sanExtension != null)
    {
        // .NET 5+ 可使用强类型扩展获取结构化SAN列表
        // var sanExt = (X509SubjectAlternativeNamesExtension)sanExtension;
        // foreach (var name in sanExt.AlternativeNames) { ... }
        // .NET Core 3.1 可直接输出可读格式的SAN内容
        Console.WriteLine($"  Subject Alternative Names: {sanExtension.Format(false)}");
    }
}

注意:.NET Core 3.1+ 同样支持从PEM文件读取私钥,可通过RSA.CreateFromPemFile("key.pem")等方法直接加载,无需额外处理PEM格式。若PEM文件同时包含证书和私钥,CreateFromPemFile会自动完成绑定。

方案对比
  • Portable.BouncyCastle方案
    • 优点:兼容.NET Framework 4.x等旧版框架,可处理冷门证书格式
    • 缺点:需引入第三方NuGet包,API复杂度较高,更新频率较低
  • .NET内置库方案
    • 优点:无第三方依赖、API标准化、微软官方长期维护、性能更优
    • 缺点:仅支持.NET Core 3.0+/.NET 5+,旧版.NET Framework不支持PEM直接解析API

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.15 12:45:03