Reputation: 872
I recently discovered Java's CertificateFactory as a method of converting PEM content into certs and cert chains. My PEM content is just an X.509 certificate in PEM format (i.e., ----BEGIN CERTIFICATE----\n ...) in a String.
I tried to write my conversion method like this:
public List<? extends Certificate> certChainFromPem(String certPem) {
try (ByteArrayInputStream bais = new ByteArrayInputStream(certPem.trim().getBytes(StandardCharsets.UTF_8))) {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
CertPath certPath = factory.generateCertPath(bais);
return certPath.getCertificates();
} catch (GeneralSecurityException | IOException e) {
throw new InvalidCertChainPemException("invalid cert chain pem content: " + certPem, e);
}
}
This threw an exception indicating "Empty input" in the exception message. After much experimentation, I finally rewrote my method like this:
public List<? extends Certificate> certChainFromPem(String certPem) {
try (ByteArrayInputStream bais = new ByteArrayInputStream(certPem.trim().getBytes(StandardCharsets.UTF_8))) {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certs = factory.generateCertificates(bais);
CertPath certPath = factory.generateCertPath(new ArrayList<>(certs));
return certPath.getCertificates();
} catch (GeneralSecurityException | IOException e) {
throw new InvalidCertChainPemException("invalid cert chain pem content: " + certPem, e);
}
}
And now it works. Can someone please explain to me why the certificate factory is able to generate certificates, but not a cert path, from the input stream? With the exact same input, I'm able to generate a cert path from the certificates generated from the input stream. What key concept am I missing here? Both methods have an InputStream constructor, and stepping into the Java source shows me that the generateCertPath method seems to have no trouble parsing the PEM content from the input stream. It just can't seem to figure out what to do with the parsed content after that.
Upvotes: 4
Views: 1216
Reputation: 63
Actually CertificateFactory expects a List of certificates (or an input stream of a cert chain in a specific format) rather than a raw InputStream containing the PEM data. In your code, you pass a ByteArrayInputStream directly, which does not match the expected input format for generateCertPath. That's why second code is working
I think it's too late but that's a reason
Upvotes: 0