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

.NET中使用官方BouncyCastle.Cryptography构建证书链的方法

基于BouncyCastle.Cryptography构建证书链的解决方案

问题背景

我之前使用Portable.BouncyCastle(v1.9.0)编写了静态辅助方法,在.NET(Core)/C#中从主证书和附加证书构建证书链。现在需要迁移到官方的BouncyCastle.Cryptography库,但原方法中的X509CollectionStoreParameters类型和PkixBuilderParameter.AddStore方法已被移除,导致原有代码无法正常工作。

旧版可正常工作的代码

static IEnumerable<X509Certificate> BuildCertificateChain(byte[] primary, IEnumerable<byte[]> additionalCertificates)
{
    X509CertificateParser parser = new();
    PkixCertPathBuilder builder = new();
    List<X509Certificate> chainedCertificates = [];
    HashSet<TrustAnchor> trustAnchors = [];

    // 区分根证书和从属证书
    foreach (byte[] additionalCertificateBytes in additionalCertificates)
    {
        X509Certificate parsedCertificate = parser.ReadCertificate(additionalCertificateBytes);
        // 区分根证书和从属证书
        if (parsedCertificate.IssuerDN.Equivalent(parsedCertificate.SubjectDN)) // 根证书
            trustAnchors.Add(new TrustAnchor(parsedCertificate, null));
        else
            chainedCertificates.Add(parsedCertificate);
    }

    // 以主证书为起点构建链
    X509CertStoreSelector targetConstraintsCert = new()
    {
        Certificate = parser.ReadCertificate(primary)
    };

    chainedCertificates.Add(targetConstraintsCert.Certificate);
    PkixBuilderParameters builderParams = new(trustAnchors, targetConstraintsCert)
    {
        IsRevocationEnabled = false
    };

    X509CollectionStoreParameters intermediateStoreParameters = new(chainedCertificates);

    builderParams.AddStore(
        X509StoreFactory.Create(
            "Certificate/Collection",
            intermediateStoreParameters));

    PkixCertPathBuilderResult result = builder.Build(builderParams);
    return result.CertPath.Certificates;
}

尝试的新版代码(存在问题)

我参考Java示例尝试修改,但相关类和方法不匹配。目前的新版代码虽然能构建链,但所有附加证书都未被包含,因为找不到在构建过程中添加它们的正确方式:

public static IEnumerable<X509Certificate> BuildCertificateChain2(byte[] primary, IEnumerable<byte[]> additional)
{
    X509CertificateParser parser = new X509CertificateParser();
    
    // 找不到将其余证书包含到链中的方法
    List<X509Certificate> allCerts = new List<X509Certificate>();
    
    HashSet<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();

    foreach (byte[] certBytes in additional)
    {
        X509Certificate cert = parser.ReadCertificate(certBytes);
        allCerts.Add(cert);
        if (cert.IssuerDN.Equivalent(cert.SubjectDN))
        {
            trustAnchors.Add(new TrustAnchor(cert, null));
        }
    }

    X509Certificate primaryCert = parser.ReadCertificate(primary);
    allCerts.Add(primaryCert);

    // 假设主证书不是根证书
    X509CertStoreSelector targetConstraints = new() { Certificate = primaryCert };

    PkixBuilderParameters pkixParams = new(trustAnchors, targetConstraints)
    {
        IsRevocationEnabled = false,
    };

    PkixCertPathBuilderResult result;
    try
    {
        PkixCertPathBuilder builder = new PkixCertPathBuilder();
        result = builder.Build(pkixParams);
    }
    catch (PkixCertPathBuilderException e)
    {
        throw new Exception("Failed to build certificate path", e);
    }

    return result.CertPath.Certificates.Cast<X509Certificate>();
}

适配官方BouncyCastle.Cryptography的解决方案

在新版库中,X509CollectionStoreParameters被替换为CollectionStoreParameters,而PkixBuilderParameters.AddStore方法则被AddCertStore替代。同时,创建集合存储的方式也改为使用CertStore.CreateCollectionStore。以下是修正后的完整代码:

using Org.BouncyCastle.Cert;
using Org.BouncyCastle.Cert.Store;
using Org.BouncyCastle.Security;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public static IEnumerable<X509Certificate> BuildCertificateChain(byte[] primary, IEnumerable<byte[]> additionalCertificates)
{
    var parser = new X509CertificateParser();
    var builder = new PkixCertPathBuilder();
    var intermediateCerts = new List<X509Certificate>();
    var trustAnchors = new HashSet<TrustAnchor>();

    // 解析附加证书,区分根证书和中间证书
    foreach (var certBytes in additionalCertificates)
    {
        var cert = parser.ReadCertificate(certBytes);
        if (cert.IssuerDN.Equivalent(cert.SubjectDN))
        {
            // 根证书加入信任锚
            trustAnchors.Add(new TrustAnchor(cert, null));
        }
        else
        {
            // 中间证书加入待选集合
            intermediateCerts.Add(cert);
        }
    }

    // 解析主证书
    var primaryCert = parser.ReadCertificate(primary);
    intermediateCerts.Add(primaryCert);

    // 设置目标证书约束
    var targetSelector = new X509CertStoreSelector
    {
        Certificate = primaryCert
    };

    // 初始化构建参数
    var pkixParams = new PkixBuilderParameters(trustAnchors, targetSelector)
    {
        IsRevocationEnabled = false // 关闭吊销检查,根据需要调整
    };

    // 创建中间证书存储并添加到参数中
    var certStore = CertStore.CreateCollectionStore(new CollectionStoreParameters(intermediateCerts));
    pkixParams.AddCertStore(certStore);

    // 构建证书链
    PkixCertPathBuilderResult result;
    try
    {
        result = builder.Build(pkixParams);
    }
    catch (PkixCertPathBuilderException ex)
    {
        throw new System.Exception("证书链构建失败", ex);
    }

    // 返回完整的证书链(从主证书到根证书)
    return result.CertPath.Certificates.Cast<X509Certificate>();
}

关键变化说明

  1. 存储创建方式:使用CertStore.CreateCollectionStore替代原有的X509StoreFactory.Create,配合CollectionStoreParameters(替代X509CollectionStoreParameters)来创建基于证书集合的存储。
  2. 添加存储到参数:使用pkixParams.AddCertStore()方法替代原有的AddStore(),将中间证书存储注入到链构建参数中。
  3. 逻辑保持一致:依然保留了区分根证书(作为信任锚)和中间证书的逻辑,确保链构建时能正确找到信任起点和中间层级。

内容的提问来源于Stack Exchange,提问作者joachim-heck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:11:03