关于java:读取PEM证书链中的数据

Reading data in a PEM certificate chain

我可以使用以下内容轻松读取 PEM 格式的 x509 证书:

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

但是,我现在希望包含多个受信任的服务器证书。附加证书附加到 ca.pem 上,我使用声称读取多个证书的方法:

1
val certs = cf.generateCertificates(it)

但只读取第一个证书(certs 大小为 1)。

1
2
3
4
5
6
7
8
9
10
 * <p>In the case of a certificate factory for X.509 certificates,
 * <wyn>inStream</wyn> may contain a sequence of DER-encoded certificates
 * in the formats described for
 * {@link #generateCertificate(java.io.InputStream) generateCertificate}.
 * In addition, <wyn>inStream</wyn> may contain a PKCS#7 certificate
 * chain. This is a PKCS#7 SignedData object, with the only
 * significant field being certificates. 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.

引用部分:

1
2
3
4
5
6
 * <p>In the case of a certificate factory for X.509 certificates, the
 * certificate provided in <wyn>inStream</wyn> 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 看起来像:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

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

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

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

我是否误解了证书工厂的用法?这可能是不支持标记的输入流的副作用(在这种情况下,整个流在第一个证书之后被消耗)?也许换行是不允许的,解析器将它们解释为数据的结尾。 PKCS7 会比 PEM 更自然吗?


确实删除换行符会让解析器开心。

1
2
3
4
5
6
7
8
9
10
11
12
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

BouncyCastle 的 CertificateFactory 将忽略条目之间的空格:

1
2
3
4
5
6
7
8
9
import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory

assets.open("ca.pem").use { pem ->
    val certreader = CertificateFactory()
    certreader.engineGenerateCertificates(pem)
              .forEach { cert ->
                  keystore.setCertificateEntry("server", cert)
              }
}

我避免响应引用外部依赖项,但如果您在这个领域工作,Bouncy Castle 可能会提供其他实用程序。