在java中从.p7b文件中提取单个.cer证书

在java中从.p7b文件中提取单个.cer证书,java,openssl,x509certificate,bouncycastle,pkcs#7,Java,Openssl,X509certificate,Bouncycastle,Pkcs#7,我对密码学一无所知,所以如果你认为这是一个基本问题,请原谅 我有一个.p7b文件,我需要读取和提取单个公共证书,即.cer文件,并将其存储在密钥存储中。我不必担心密钥存储中的持久性,因为已经有一个服务将.cer文件作为字节[]接收并保存 我想知道的是,如何读取.p7b并提取单个.cer文件?我知道这可以通过openSSL命令来完成,但我需要在java中也这样做。我还需要读取由名称颁发的证书,因为它将用作持久化证书的唯一密钥 提前感谢您可以使用BouncyCastle从PKCS#7对象获取证书。下

我对密码学一无所知,所以如果你认为这是一个基本问题,请原谅

我有一个.p7b文件,我需要读取和提取单个公共证书,即.cer文件,并将其存储在密钥存储中。我不必担心密钥存储中的持久性,因为已经有一个服务将.cer文件作为字节[]接收并保存

我想知道的是,如何读取.p7b并提取单个.cer文件?我知道这可以通过openSSL命令来完成,但我需要在java中也这样做。我还需要读取由名称颁发的证书,因为它将用作持久化证书的唯一密钥


提前感谢

您可以使用BouncyCastle从PKCS#7对象获取证书。下面是一个快速代码示例:

 public Collection<X59Certificate> getCertificates(String path) throws Exception
 {
     Security.addProvider(new BouncyCastleProvider());
     CMSSignedData sd = new CMSSignedData(new FileInputStream(path));
     X509Store store = sd.getCertificates("Collection", "BC");
     Collection<X509Certificate> certificates = store.getMatches(X509CertStoreSelector.getInstance(new X509CertSelector()));
     return certificates;
 }
公共集合getCertificates(字符串路径)引发异常
{
addProvider(新的BouncyCastleProvider());
CMSSignedData sd=新的CMSSignedData(新文件输入流(路径));
X509Store=sd.getCertificates(“集合”、“BC”);
集合证书=store.getMatches(X509CertStoreSelector.getInstance(新的X509CertSelector());
退货证明书;
}

请注意,PKCS#7可能包含多个证书。大多数情况下,它包括在最终用户证书和根CA之间构建证书链所需的中间证书颁发机构证书。

我成功地从p7b文件中读取了单个.X509证书。以下是步骤

  • 第一步包括从java.io.File获取字节[]。这些步骤包括从文件中删除------BEGIN PKCS7------和------END PKCS7------,并解码剩余的base64编码字符串

    BufferedReader reader = new BufferedReader(new FileReader(file));
    StringBuilder cerfile = new StringBuilder();
    String line = null;
    while(( line = reader.readLine())!=null){
      if(!line.contains("PKCS7")){
        cerfile.append(line);
      }
    }
    byte[] fileBytes = Base64.decode(cerfile.toString().getBytes());
    
  • 下一步是使用BouncyCastleAPI解析文件

    CMSSignedData  dataParser = new CMSSignedData(trustBundleByte);
    ContentInfo contentInfo = dataParser.getContentInfo();
    SignedData signedData = SignedData.getInstance(contentInfo.getContent());
    
    CMSSignedData encapInfoBundle = new CMSSignedData(new CMSProcessableByteArray(signedData.getEncapContentInfo().getContent().getDERObject().getEncoded()),contentInfo);
    SignedData encapMetaData = SignedData.getInstance(encapInfoBundle.getContentInfo().getContent());
    
    CMSProcessableByteArray cin = new CMSProcessableByteArray(((ASN1OctetString)encapMetaData.getEncapContentInfo().getContent()).getOctets());
    CertificateFactory ucf = CertificateFactory.getInstance("X.509");
    
    CMSSignedData  unsignedParser = new CMSSignedData(cin.getInputStream());
    ContentInfo unsginedEncapInfo = unsignedParser.getContentInfo();
    SignedData metaData = SignedData.getInstance(unsginedEncapInfo.getContent());
    Enumeration certificates = metaData.getCertificates().getObjects();
    
    // Build certificate path
    
    while (certificates.hasMoreElements()) {
       DERObject certObj = (DERObject) certificates.nextElement();
       InputStream bin = new ByteArrayInputStream(certObj.getDEREncoded());
       X509Certificate cert = (X509Certificate) ucf.generateCertificate(bin);
     X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
    RDN cn = x500name.getRDNs(BCStyle.CN)[0];
    }
    
  • 上面的步骤工作得很好,但我相信还有其他解决方案可以用更少的代码行来实现这一点。我使用的是bcjdk16罐


首先看看这篇文章:谢谢@SubOptimal提供的参考。我已经开始了Bouncy Castle Api的工作,希望能够实现我想要的。从CertificateFactory获取迭代器是读取p7b或任何其他文件类型的最佳选择。参考解决方案在这里帮助了我。(我不必读取文件并去掉任何开始/结束分隔符。)感谢@Jcs的输入!!。我以前试过这个,但遇到了例外。org.bouncycastle.cms.CMSException:格式不正确的内容。原因:java.lang.IllegalArgumentException:工厂中的未知对象:org.bouncycastle.asn1.DERUnknownTag。我猜(可能是错的)这是因为PKCS#7是base64编码的。我已经找到了解决问题的替代解决方案(可能不理想)(上面提供了答案),如果您觉得合适,请告诉我。谢谢是的,我的解决方案假设数据是DER编码的。我对Bouncycastle API不是很熟悉,但我对CMS/PKCS#7非常了解,在我看来,您的代码正在进行大量不必要的编码和解码。我认为dataParser、contentInfo、signedData、encapInfoBundle、encapMetaData在p7b数据中表示相同的数据结构。您是否尝试调用
Enumeration certificates=dataParser.getCertificates().getObjects()直接?