【问题标题】:How to add a certificate chain to a JKS如何将证书链添加到 JKS
【发布时间】:2015-08-06 17:42:02
【问题描述】:

我有一个名为: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)?

【问题讨论】:

  • 删除前两行,每次出现时。
  • @EJP 你的意思是我应该删除前两行?我会在几个小时内试一试。谢了!
  • @EJP 我删除了第一条拖线,但结果仍然相同。还有其他想法吗?
  • 证书链将包含一系列证书。每个证书都包含带有页眉/页脚的 Base64 格式数据。这里页眉是“BEGIN CERTIFICATE”,页脚是“END CERTIFICATE”。在页眉和页脚之间,存在原始证书数据。因此,文件中的页眉和页脚之外不应有任何主题值或问题值或任何其他行。因此,请排除这些行再试一次。
  • @SaqibRezwan 感谢您的回复!我有创建这样一个链的命令吗?首先,我按照https://langui.sh/2009/03/20/creating-a-pkcs7-p7b-using-openssl/ 中的描述并发出命令:openssl crl2pkcs7 -nocrl -certfile cacert.pem -certfile clientcert.pem -out cert.p7b 其次,我按照http://stackoverflow.com/a/22028156/1817029 中的说明发出命令:openssl pkcs7 -print_certs -in cert.p7b -out chain.cer,它应该给我一个有效的证书链。您能否提供创建该链的说明。

标签: ssl certificate keystore chain jks


【解决方案1】:

好的,我运行了你的命令来合并 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

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

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

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

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 代码来简化我们的工作(我总是这样做)。
对不起,让这个这么久。但希望这能消除您的大部分困惑。

【讨论】:

  • 不需要那么长。你本可以削减前四分之三。唯一相关的部分是源代码中的引用以及后面的内容。
  • 是的,我同意,很抱歉。我只是描述了所有的过程,如果这对其他人有帮助的话。
  • 嗨@SaqibRezwan,或者,编写一些java代码来简化我们的工作(我总是这样做)。 >> 使用 keytool 执行证书链导入的代码是什么?你能分享一下代码sn-p吗?我需要使用 keytool 导入具有相同别名的多个证书。但它总是只导入第一个证书。 -----BEGIN CERTIFICATE----- ...(服务器证书) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- ...(CA证书) -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- ...(CA 颁发者的根证书) -----END CERTIFICATE-----
【解决方案2】:

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 行应该是单独的行,而不是像你拥有它们那样一起运行。

【讨论】:

  • 这是否意味着应该可以将证书链导入JCEKS 密钥库?
  • @My-Name-Is only in a privatekey entry with a privatekey,这是您在 JKS 中不想要的,出于同样的原因,在 JCEKS 中也不想要
  • 多么痛苦!在 AWS 将 Redshift 转换为基于 ACM 的证书后,我遇到了这个问题。要使用基于 Java 的客户端(例如使用其 Redshift JDBC 驱动程序的 DbVisualizer)连接到 Redshift 集群,需要 JKS 中的 ACM CA 根证书。但 AWS 将 ACM CA 根作为包含六个串联 PEM 证书的文件提供。唯一的解决方案是将它们分解为单独的文件,将每个文件转换为 DER 编码,然后将每个文件单独导入 DbVisualizer 可以使用的 JKS。
  • @Ville:你不需要 DER; keytool -importcert 可以读取 PEM DER,但对于trustedcert,每种格式的每个文件都只能读取一个。 (Java7 甚至可以读取带有无关 'cmets' 的 PEM,许多 OpenSSL 生成的 PEM 文件都有。)你可以这样做 awk <chain.pem '/^-----BEGIN/{cmd="keytool -importcert -keystore xyz.jks -storepass secret -alias cert"(++n);} cmd{print >cmd} /^-----END/{close(cmd);cmd=""}'
  • @dave_thompson_085 感谢您提供的信息。事实证明,AWS 已经发布了一个 keytool 替换,redshift-keytool.jar,专门用于将 Redshift 的 CA 根链导入自定义 JKL(我的用例)或系统密钥库,如下所示:@987654331 @(前)或sudo java -jar redshift-keytool.jar -s(后)。即使它一次读取整个证书链,它也不能用作一般的keytool 替换,因为它会自动从 AWS 加载特定的预定义证书。
猜你喜欢
  • 2013-09-18
  • 1970-01-01
  • 2013-04-10
  • 2017-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
相关资源
最近更新 更多