如何将证书链添加到 JKS

How to add a certificate chain to a JKS

我有一个名为:cert.cer 的证书链,其内容为:

subject= ... OU=MyCA
issuer= ... OU=MyCA
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

subject= ... OU=Client
issuer= .. OU=MyCA
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

我试图通过调用将此链添加到 JKS:

keytool -import -trustcacerts -file cert.cer -keystore sample.keystore -storepass 123456 -alias chain

,只添加OU=MyCA的顶级证书。

如何将此链正确添加到 JavaKeyStore (JKS)?

好的,我 运行 你的命令以 PKCS7 格式合并证书:

openssl > crl2pkcs7 -nocrl -certfile a.crt -certfile b.crt -out outfile.p7b

成功了。
然后我尝试使用以下命令将 PKCS#7 文件导入 JKS 文件:

keytool -import -trustcacerts -file outfile.p7b -keystore keystore1.jks -storepass 123456 -alias chain

没用。
然后我稍微研究了一下,发现我需要将证书链保存在 Base64 格式或 Der 格式的文件中。 我有 Base64 格式的文件。因此,我尝试使用以下 windows 命令连接文件:

copy /b a.crt+b.crt c.crt

linux 命令为:

cat a.crt b.crt > c.crt

因此输出文件如下所示:

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

然后,尝试使用上述命令在JKS 中导入证书链。有效。然后,我尝试从密钥库中查看证书列表。为此,我 运行 以下命令:

keytool -list -v -keystore keystore1.jks

但是它说,只有“找到一个条目”并且显示了一个证书。由于密钥库没有加载完整的证书链,因此实验失败了。
因此,我尝试使用以下 openssl 命令转换证书链中的 PKCS#7 文件:

pkcs7 -print_certs -in outfile.p7b -out certificates.cer

输出文件与您的完全一样,以主题 dn 和发行者 dn 开头,然后是页眉和页脚。然后我尝试将证书从 'certificates.cer' 存储到 jks 文件 'keystore1.jks'。但是,同样,在导入之后,它显示密钥库只有一个证书。因此,发行人 dn 和主题 dn 不是问题。
然后我尝试将Base64文件转换为Der文件,然后尝试连接数据:

openssl x509 -in a.crt -outform DER -out aa.crt
openssl x509 -in b.crt -outform DER -out bb.crt
copy /b aa.crt+bb.crt cc.crt

然后,我尝试将der连接文件导入JKS。但同样只导入了一个证书。

我真的想过我做错了什么。因此,我查找了 KeyTool 的源代码,找到了导入证书或证书链的方法。

Imports a JDK 1.1-style identity database. We can only store one certificate per identity, because we use the identity's name as the alias (which references a keystore entry), and aliases must be unique.

令我惊讶的是,他们的代码将输入流转换为证书列表,但他们只使用证书中的一个证书(第一个)。

if (certs!=null && certs.length>0) {
      // we can only store one user cert per identity.
      // convert old-style to new-style cert via the encoding
         DerOutputStream dos = new DerOutputStream()
         certs[0].encode(dos);
         .............................

所以我们无法一次添加多个证书。政策是一个条目一个证书。因此,如果您有多个要输入的证书,则必须单独输入它们。或者,编写一些 java 代码来简化我们的工作(我总是这样做)。
抱歉让我这么久。但希望这会消除您的大部分困惑。

two kinds of entries in a JKS-type KeyStore:

  • PrivateKey 条目包含私钥和证书或证书链该私钥

  • 一个 TrustedCert 条目正好包含 一个 证书,没有私钥

通用 KeyStore 接口允许 SecretKey 的第三种条目,但 JKS 不支持它,只有很少使用的 JCEKS 和我相信 BouncyCastle 格式。

我发现了你的另一个问题 https://security.stackexchange.com/questions/95945/how-to-add-a-certificate-chain-to-a-jks,它解释了为什么你 正确地不需要私钥条目。 但是,你可以找到关于 keytool 的大部分说明等是关于将链(通常从 CA 返回)附加到私钥,并掩盖了这样一个事实,即如果没有 私钥,您不能将证书链存储为一个条目

所以是的,您必须分别输入每个证书。但是,这 不一定 意味着您必须 分别获取 每个证书。 CertPathBuilder 的存在正是为了从信任库中提取(但不仅限于)JKS 形成有效链的所有证书。不幸的是,使 CertPathBuilder(特别是 "PKIX")为 SSL/TLS 正常工作所需的花里胡哨的东西使得它在用于更简单的应用程序时相当笨拙,因此您可能更愿意只获取证书。

PS- 串联的 PEM 证书在允许链(仅使用私钥)的情况下有效,但您显示的示例无效。 -----BEGIN-----END 行应该是分开的行,而不是 运行 在一起。