Search code examples
javaopensslx509certificatebouncycastlepkcs#7

Extracting individual .cer certificate from a .p7b file in java


I am new to Cryptography and so please excuse me if you think this is a basic question

I have a .p7b file which I need to read and extract the individual public certificates i.e the .cer files and store it in the key store. I need not worry about persisting in the key store as there is already a service which takes in the .cer file as byte[] and saves that.

What i want to know is , how do i read the .p7b and extract the individual .cer file? I know that can be done via the openSSL commands, but i need to do the same in java. I need to also read the Issued By name as that will be used as a unique key to persist the certificate.

Thanks in advance


Solution

  • I was successfully able to read the individual .X509 certificates from the p7b files. Here are the steps

    • First step includes, getting a byte[] from the java.io.File. The steps include to remove the -----BEGIN PKCS7----- and -----END PKCS7----- from the file, and decode the remaining base64 encoded String.

      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());
      
    • The next step is to use the BouncyCastle api to parse the file

      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];
      }
      
    • The above steps are working fine, but i am sure there are other solutions with less lines of code to achieve this. I am using bcjdk16 jars.