Search code examples
javaandroidsslx509jsse

Reading data in a PEM certificate chain


I can easily read in an x509 certificate in PEM format using something along the lines of:

assets.open("ca.pem").use {
    val cf = CertificateFactory.getInstance("X.509")
    keystore.setCertificateEntry("server", cf.generateCertificate(it))
}

However, I now wish to include multiple trusted server certificates. The additional certificates are appended onto ca.pem and I use the method that claims to read multiple certificates:

val certs = cf.generateCertificates(it)

but only the first certificate is read in (certs is size 1).

 * <p>In the case of a certificate factory for X.509 certificates,
 * <code>inStream</code> may contain a sequence of DER-encoded certificates
 * in the formats described for
 * {@link #generateCertificate(java.io.InputStream) generateCertificate}.
 * In addition, <code>inStream</code> may contain a PKCS#7 certificate
 * chain. This is a PKCS#7 <i>SignedData</i> object, with the only
 * significant field being <i>certificates</i>. In particular, the
 * signature and the contents are ignored. This format allows multiple
 * certificates to be downloaded at once. If no certificates are present,
 * an empty collection is returned.

The referenced section:

 * <p>In the case of a certificate factory for X.509 certificates, the
 * certificate provided in <code>inStream</code> must be DER-encoded and
 * may be supplied in binary or printable (Base64) encoding. If the
 * certificate is provided in Base64 encoding, it must be bounded at
 * the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at
 * the end by -----END CERTIFICATE-----.

ca.pem looks like:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

Am I misunderstanding the certificate factory usage? Might this be a side effect of an input stream that does not support marking (in which case the entire stream is consumed after the first certificate)? Maybe the newlines are not allowed and the parser interprets them as end of data. Would PKCS7 be a more natural choice instead of PEM?


Solution

  • Indeed removing the newlines makes the parser happy.

    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----