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

Java中使用BouncyCastle从PKCS7 PEM证书生成X509Certificate

解决方案

错误原因说明

你原有代码的两个问题根源:

  • 直接将PEM字符串的字节传入CMSSignedData构造方法:CMSSignedData要求输入DER编码的二进制PKCS7数据,而PEM是Base64编码带页眉页脚的文本格式,直接传字节会解析失败
  • PEMParser.readObject()返回null:大概率是BouncyCastle版本过旧,或者没有正确引入bcpkix依赖,部分旧版本BC将PKCS7解析为ContentInfo对象而不是直接返回CMSSignedData,所以需要做类型兼容判断。

你要实现的openssl pkcs7 -in client-certificate_pkcs7.pem -out client-certificate_chain.pem命令本质是从PEM格式的PKCS7包中提取所有X509证书,拼接成PEM格式的证书链,以下是可直接运行的实现:

前置依赖

首先确保你已经引入了正确的BouncyCastle依赖,以Maven为例:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.77</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.77</version>
</dependency>

完整实现代码

import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.asn1.cms.ContentInfo;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class Pkcs7Parser {

    static {
        // 注册BC安全提供者
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }

    public static String parsePkcs7ToCertChain(String pkcs7Pem) throws Exception {
        // 1. 解析PEM格式的PKCS7内容
        PEMParser parser = new PEMParser(new StringReader(pkcs7Pem));
        Object obj = parser.readObject();
        parser.close();

        CMSSignedData signedData;
        if (obj instanceof ContentInfo) {
            signedData = new CMSSignedData((ContentInfo) obj);
        } else if (obj instanceof CMSSignedData) {
            signedData = (CMSSignedData) obj;
        } else {
            throw new IllegalArgumentException("输入内容不是合法的PKCS7 PEM文件");
        }

        // 2. 提取所有证书
        Collection<X509CertificateHolder> certHolders = signedData.getCertificates().getMatches(null);
        List<X509Certificate> certList = new ArrayList<>();
        JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider("BC");
        for (X509CertificateHolder holder : certHolders) {
            certList.add(converter.getCertificate(holder));
        }

        // 3. 导出为PEM格式的证书链,和openssl输出格式完全一致
        StringWriter sw = new StringWriter();
        JcaPEMWriter pemWriter = new JcaPEMWriter(sw);
        for (X509Certificate cert : certList) {
            pemWriter.writeObject(cert);
        }
        pemWriter.close();
        return sw.toString();
    }

    public static void main(String[] args) throws Exception {
        String pkcs7Pem = "-----BEGIN PKCS7-----\nMIIR...WTEA\n-----END PKCS7-----\n";
        String certChainPem = parsePkcs7ToCertChain(pkcs7Pem);
        // 输出的certChainPem就是和openssl命令输出一致的证书链内容
        System.out.println(certChainPem);
    }
}

常见问题排查

如果遇到PEMParser.readObject()返回null的情况,按以下顺序排查:

  • 确认PEM内容格式正确:页眉-----BEGIN PKCS7-----和页脚-----END PKCS7-----完整,Base64内容的换行符符合规范
  • 升级BouncyCastle到1.70以上版本,旧版本对部分PKCS7标头识别存在兼容性问题
  • 确认没有少引入bcpkix-jdk15on包,PEMParser属于该包的内容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 21:36:02