Java使用新版BouncyCastle库解码PKCS#7字符串的方案咨询
问题原因
类型转换异常由解析逻辑错误导致:PEMParser读取-----BEGIN PKCS7-----标识的PEM内容时,返回值是PKCS7结构对应的org.bouncycastle.asn1.cms.ContentInfo实例,并非X509Certificate对象。旧版PEMReader内置的自动类型转换逻辑在新版API中被拆分,需要手动完成CMS结构解析和证书提取步骤,不能直接强转。
当前使用的bcpkix-jdk15on:1.58版本完全支持正确解析逻辑,无需升级依赖。
完整实现代码
import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMParser; import java.io.StringReader; import java.security.Security; import java.security.cert.X509Certificate; import java.util.Collection; public class Pkcs7Decoder { public static void main(String[] args) throws Exception { // 注册BouncyCastle安全提供者 if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { Security.addProvider(new BouncyCastleProvider()); } // 待解析的PKCS7格式PEM内容 String pkcs7Pem = "-----BEGIN PKCS7-----\n" + "MIIC5wYJKoZIhvcNAQcCoIIC2DCCAtQCAQExADALBgkqhkiG9w0BBwGgggK8MIICuDCCAl6gAwIB\n" + "AgIQXCpspdawOszPHWPu6BzK7DAKBggqhkjOPQQDAjBAMQswCQYDVQQGEwJERTEUMBIGA1UEChML\n" + "U29mdHdhcmUgQUcxGzAZBgNVBAMTElFBIFRoaW4tRWRnZSBDQSBHMTAeFw0yMjA2MjIwNzM1MDJa\n" + "Fw0yNTA2MjIwNzM1MDJaMCUxIzAhBgNVBAMTGlJlcXVlc3RlZCBUZXN0IENlcnRpZmljYXRlMIIB\n" + "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjahV4/HclaS48gxI6ojGk1WZsBr+oS2PwAG5\n" + "abWG1ilmOGakfSoJt5exz3+vfbqX9Wewge7kE+2ehM3kyhLxtRLc9o2IbvbRsonyncIhb0SqJ+6j\n" + "oTK8b7Dd1XwTFNLMNpQK2trY6c0ScBrdJarPv0QKszlpJHpFCCjozlaExdFKeYINUzSN6UKMd9Kw\n" + "L6T/3QPOQSBLVAwKnBC8dZnxmoG8Nr0XOJE0FBDISnB/PkE70w8bTqquCCqdWInFZJkZog+QsYBu\n" + "LDZq5ODeoUfSrkfnrR1xudgS5/OYRsU5jfwU5h4D1bM1MSQAMseOalFO+Iv5tm4tszNF3HNwSn8N\n" + "KQIDAQABo4GJMIGGMBMGA1UdJQQMMAoGCCsGAQUFBwMCMBMGA1UdIwQMMAqACEhBtjq9T25cMAsG\n" + "A1UdDwQEAwIFoDBNBgNVHR8ERjBEMEKgQKA+hjxodHRwOi8vZHAuMzgucWEuZ28ubmV4dXNncm91\n" + "cC5jb20vY3JsL3FhX3RoaW4tZWRnZV9jYV9nMS5jcmwwCgYIKoZIzj0EAwIDSAAwRQIhALgVQ4GE\n" + "NDd3KkjDjDE1a3Kn5FzjTWVjDc4ZdCsJvm1yAiBHdeGu8Sklq57MM1eSMMS7C4KvAYepzPkM4/9s\n" + "vgRT8zEA\n" + "-----END PKCS7-----"; // 解析PEM结构 PEMParser pemParser = new PEMParser(new StringReader(pkcs7Pem)); ContentInfo contentInfo = (ContentInfo) pemParser.readObject(); pemParser.close(); // 构造PKCS7签名数据对象 CMSSignedData signedData = new CMSSignedData(contentInfo); // 提取结构内嵌入的所有证书 Collection<X509CertificateHolder> certHolders = signedData.getCertificates().getMatches(null); JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter() .setProvider(BouncyCastleProvider.PROVIDER_NAME); for (X509CertificateHolder holder : certHolders) { X509Certificate cert = certConverter.getCertificate(holder); // 可直接使用标准X509Certificate对象完成后续操作 System.out.println("证书主题:" + cert.getSubjectX500Principal().getName()); System.out.println("证书颁发者:" + cert.getIssuerX500Principal().getName()); } } }
关键说明
- 只有
-----BEGIN CERTIFICATE-----开头的单证书PEM内容,才能将PEMParser.readObject()的返回值直接转换为证书对象,其余格式(PKCS7、CSR、私钥等)都需要按照对应ASN.1结构做二次解析。 - 上述代码会提取PKCS7结构中嵌入的所有证书,如果内容包含完整证书链,会一次性返回链上所有证书,按需取用即可。
- 如果后续升级BouncyCastle到1.69+版本,
bcpkix-jdk15on包会改名为bcpkix-jdk18on,类路径和API逻辑无变化,上述代码可直接运行。
内容的提问来源于stack exchange,提问作者Ivajlo Iliev
相关产品推荐
相关产品推荐

