Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java CertificateFactory.generateCertPath(inputStream) not working as expected

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.

like image 820
John Calcote Avatar asked Jun 25 '26 21:06

John Calcote


1 Answers

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

like image 179
Shiv Shrivas Avatar answered Jun 27 '26 09:06

Shiv Shrivas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!