Ohhnews

分类导航

$ cd ..
Baeldung原文

使用 Keytool 将 P7B 证书文件导入 Java 密钥库指南

#java#keytool#数字证书#安全管理#密钥库

1. 前言

在开发 Java 生产环境应用时,我们经常需要配置 HTTPS、启用安全的出站通信或管理信任库(Truststore)。Keytool 是处理密钥和证书的标准工具,也是管理 Java 密钥库(Keystore) 的核心工具。

在本教程中,我们将重点介绍一项特定任务:使用 keytool 将 .p7b 证书文件导入到 Java 密钥库中。

2. 理解 P7B (PKCS#7) 格式

在深入导入 P7B 文件的步骤之前,先了解一下 PKCS#7 格式 是非常有必要的。

在密码学中,PKCS#7 是一种用于存储经加密签名或加密数据的标准语法。

该格式的一种常见用途是存储 SSL 证书。通常,证书包(Certificate Bundle)会以 .p7b 文件格式进行存储和共享。

2.1. 证书包

在创建用于开发环境的 自签名(Self-signed) 证书时,通常只需要一个私钥和一个包含公钥的自签名证书即可。然而,当开发需要通过互联网访问的生产应用时,我们通常需要证书由受信任的证书颁发机构(CA)进行验证。

浏览器通过验证网站证书来验证该网站的合法性。 每个网站都会出示其自身的证书,连同指向中间证书链的信息,最终指向 CA 的根证书。由于浏览器信任该 CA,因此任何出示经验证的证书(且具有通往根 CA 证书的清晰证书链)的网站都会被视为有效。

一旦证书通过 CA 验证,CA 通常会提供一个证书链,其中包括其自身的根证书和零个或多个中间证书。该证书链以证书包的形式提供,有时表现为 .p7b 文件。

2.2. P7B 格式

P7B 文件是一个可以存储一个或多个证书的 PKCS#7 容器。 它可以采用二进制 DER 格式或 Base64 PEM 格式进行编码。

在使用 Java 服务器(如 Tomcat)时,我们需要确保包中的所有证书都已导入到密钥库中,以证明我们证书的有效性。

现代设备上的浏览器都能识别经 CA 验证的证书。在证书验证过程中,CA 通常会共享我们网站已签名的公钥证书以及证书链(即证书包)。

有时,证书包会以 .p7b 为扩展名。需要注意的是,根据编码方式的不同,其内容可能无法直接在纯文本编辑器中轻松读取。因此,我们需要一些工具来处理这些证书并将其导入到密钥库中。

3. 准备 P7B 文件

了解了 P7B 格式后,让我们开始操作。

在导入证书包之前,我们需要一个包含证书包的文件。 由于我们没有现成的 CA 提供的 .p7b 文件,我们将使用 Baeldung.com 的公钥证书作为示例。

首先,下载证书链并将其转换为 P7B 文件格式。

3.1. 下载证书包

大多数现代浏览器都允许将证书导出为 PKCS#7 格式的文件。不过,我们将使用 Linux 终端上的 openssl 命令行工具来完成:

$ shell
$ openssl s_client -connect www.baeldung.com:443 -showcerts </dev/null

该命令会打印出多个证书以及关于每个证书的其他信息。每个证书都可以通过其开头和结尾标记轻松识别:

$ shell
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

现在,我们可以复制每个证书(包括标记),并将它们分别存储为 .pem 文件。这样我们就得到了三个文件:site.pemintermediate.pemroot.pem

接下来,利用它们创建一个 .p7b 证书包:

$ shell
$ openssl crl2pkcs7 -nocrl -certfile site.pem -certfile intermediate.pem \
-certfile root.pem -out site-chain.p7b

最后,我们可以验证包中是否包含了所有需要的证书:

$ shell
$ openssl pkcs7 -print_certs -in site-chain.p7b -noout

可以看到输出了预期的三个证书。

3.2. 导入 P7B 文件时遇到的问题

现在我们有了一个有效的 .p7b 格式证书包,让我们用 keytool 检查一下:

$ shell
$ keytool -printcert -file site-chain.p7b

该命令可以清晰地打印出这三个证书的信息。

现在尝试直接导入:

$ shell
$ keytool -importcert -file site-chain.p7b -keystore test-keystore.jks -alias site

输出显示了一个错误:

$ shell
keytool error: java.lang.Exception: Input not an X.509 certificate

证书导入失败的原因是 keytool -importcert 要求输入文件必须恰好包含一个 X.509 PEM 或 DER 编码的证书。

4. 导入 P7B 文件

我们发现使用 keytool 直接导入证书包会存在问题。解决方案是将证书包拆分为独立的证书,然后逐一进行导入。

4.1. 转换为 PEM 编码

要将证书包拆分为独立的 PEM 文件,首先需要将 PKCS#7 格式的包转换为 PEM 编码的包:

$ shell
$ openssl pkcs7 -print_certs -in site-chain.p7b -out site-chain.pem

这将生成一个包含一个或多个 X.509 证书的 PEM 文件:

$ shell
-----BEGIN CERTIFICATE-----
.......
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
.......
-----END CERTIFICATE-----

现在可以使用 keytool 导入证书了。

4.2. 导入 PEM 证书包

由于文件已转换为 keytool 导入选项所兼容的格式,我们可以执行导入操作:

$ shell
$ keytool -importcert -file site-chain.pem -keystore test-keystore.jks -alias site

该命令会要求设置密钥库密码,并询问是否信任该证书。成功后的输出如下:

$ shell
Trust this certificate? [no]:  yes
Certificate was added to keystore

这将以别名 site 导入站点证书。

如果还需要在同一个密钥库中包含中间证书和根证书,则需要分别导入它们。 我们可以从 site-chain.pem 中复制每个证书(包括开始和结束标记),并将它们分别存储为 .pem 文件。现在我们有了两个额外的文件:intermediate.pemroot.pem

使用相同的命令,配合不同的输入文件和别名,即可导入根证书和中间证书:

$ shell
$ keytool -importcert -file root.pem -keystore test-keystore.jks -alias root
$ keytool -importcert -file intermediate.pem -keystore test-keystore.jks -alias intermediate

4.3. 验证导入结果

现在所有证书已导入,让我们进行验证:

$ shell
$ keytool -list -v -keystore test-keystore.jks

该命令会要求输入之前设置的密码,然后显示所有已导入证书的详细信息。在输出的开头,我们会看到:

Keystore type: PKCS12
Keystore provider: SUN
Your keystore contains 3 entries

完成,我们的密钥库现在可以使用了。

5. 总结

在本文中,我们探讨了 keytool 如何处理 PKCS#7 (.p7b) 格式的证书包。虽然这些文件可以包含完整的证书链,但它们并不总是能直接导入。

我们了解到 keytool 要求输入的是 DER 或 PEM 格式的 X.509 证书,而不是像 PKCS#7 这样的容器格式。.p7b 证书包转换为独立的证书文件,可以确保导入过程顺利且可控。