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
You can get the certificates from a PKCS#7 object with BouncyCastle. Here is a quick code sample:
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;
}
Note that a PKCS#7 may contain more than one certificate. Most of the time it includes intermediate certification authority certificates required to build the certificate chain between the end-user certificate and the root CA.
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.