将 KeyStore 与 .crt 结合使用

using KeyStore with .crt

我需要将应用程序与强制使用 https 的外部 Web 服务集成。此 Web 服务的作者为我提供了 .crt 文件,我应该使用它来发出 https 请求。经过一番调查后,我发现以下代码使用 KeyStore class 进行安全的 https 访问:

        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream instream = new FileInputStream(new File(file));
        try {
            trustStore.load(instream, password.toCharArray());
        } finally {
            instream.close();
        }

        SSLContext sslcontext =
                SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
        SSLConnectionSocketFactory sslsf =
                new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null,
                                               BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        HttpClients.custom().setSSLSocketFactory(sslsf).build();

在此代码中,KeyStore 需要输入流以及 密码 trustStore.load(instream, password.toCharArray());。但是,据我了解,我们在使用 .crt 文件时不需要密码。所以这种加载证书的方式不适合我。同时,根据我目前的发现,我在此处提供的代码是配置 HttpClient 以使用 SSL 证书的唯一方法。是否有任何解决方法来配置 HttpClient 以使用 .crt 证书?

谢谢,

安德烈

我假设 Web 服务正在为您提供自签名证书(即不是由知名 CA 签名的)。如果它已经由 Java 的 cacerts 文件中的知名 CA 签名,则您无需执行任何操作。

否则,您有几个选择:

  1. 将证书导入全局 cacerts 密钥库
  2. 使用特定于应用程序的密钥库启动您的应用程序

无论哪种情况,您首先需要将 crt 文件转换为 Java 使用的 jks 密钥库。您可以通过以下方式做到这一点:

$ keytool -import -keystore mykeystore.jks -storepass horsestaple

请注意,keytool 需要提供密码(horsestaple 以上)才能创建 jks 存储。你可以把任何东西放在那里;正如您所说,public 网站证书不需要密码保护,毕竟它们是 public。

如果您执行选项 1,请备份您的 cacerts 并提供 cacerts 文件而不是 mykeystore.jks。有关 cacerts 的位置,请参阅下面的 link。对于此选项,您已准备就绪,您的应用程序应通过 HTTPS 连接到 Web 服务,无需任何其他配置,因为 Java 默认加载 cacerts。

如果您正在执行选项 2,这可能至少在测试阶段是首选,您需要 运行 您的应用程序使用此参数:

-Djavax.net.ssl.trustStore=mykeystore.jks

这是一个 JVM 参数,因此请适当地提供它。这取决于您 运行 应用的方式。

请注意,在这种情况下您将只有导入的证书,因此您的其他 HTTPS 连接将不起作用。您可以通过首先将标准 cacerts 复制到一个临时位置,将密钥导入其中并在上面的命令中使用它来避免这种情况。这将为您提供所有标准证书,以及您需要的证书。

选项 2 的一个小缺点是,如果添加或撤销新证书,您的应用程序特定密钥库将不会更新。如果这是一个问题,您可以即时合并密钥库,例如:

  • Registering multiple keystores in JVM

无论哪种情况,您现在都应该能够进行标准的 URL 提取,例如此处给出的示例:

即:

final URL url = new URL("https://example.com");
try(final InputStream in = url.openStream()){
  //…
}

更多信息在这里:

  • Keytool 和一般证书信息

https://docs.oracle.com/cd/E19830-01/819-4712/ablqw/index.html

  • 证书位置

http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/keytool.html

  • 导入自签名证书的更多选项

How to properly import a selfsigned certificate into Java keystore that is available to all Java applications by default?

希望这对您有所帮助。

除非他们向您提供他们的 .crt 文件,该文件应该用于验证 到[=25] 的连接=] 他们,这表明他们使用的是自签名证书,他们没有为您提供任何有用的信息。如果需要一个证书作为客户端,你首先需要的是一个public/private密钥对,你可以从中生成一个CSR , 你得到签名。除了签名证书,没有其他人可以安全地提供任何这些。

如果他们提供了自己的(自签名?)证书,您需要通过 keytool 将其加载到 truststore,而不是密钥库使用 -trustcacerts 选项,然后通过 javax.net.ssl.trustStore 系统 属性 或构建您自己的 TrustManager 并将其提供给自定义 SSLContext,如 JSSE 参考指南中所述。