如果您想要详细的文档,请查看JSSE 参考指南,更具体地说是其SSLContext 部分。
默认值(如果您传递null
给SSLContext.init(...)
)默认情况下是合理的,但您可能想了解这些默认值是什么(请参阅自定义部分)。
密钥库没有默认值(只有信任库,如果您想要客户端证书身份验证,您几乎肯定会想要自定义它)。
SSLContext
通常,您可以按如下方式初始化 a :
KeyStore ks = KeyStore.getInstance(...); // Load the keystore
ks.load(...); // Load as required from the inputstream of your choice, for example.
KeyStore ts = KeyStore.getInstance(...); // Load the truststore
ts.load(...);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, <the key password>);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
对于密钥库和信任库之间的区别,您可能也对这个答案感兴趣。简而言之,两者都是存储意义上的“密钥库”,但密钥库是您存储证书(+链)和相关私钥(即服务器上的服务器证书和私钥以及客户端证书和私钥)的地方在客户端上),并且信任库是您在远程方提供其证书时存储您愿意信任的 CA 证书或远程证书(没有私钥,因为它们不是您的证书)的地方。
关于如何处理您的密钥/证书文件,最简单的方法当然是使用 type 的密钥库,您可以按照此答案PCKS12
中的描述构建它。
编辑:(以下评论)
那么,如果我是服务器并且尚未进行 SSL 客户端身份验证,是否可以正确理解我可以使用 null TrustManager 侥幸?
是的。
但是,如果我要进行客户身份验证,我需要提供一个 TrustManager,其中包含应该能够连接的每个客户端的公钥?
通常不会。您将为颁发这些客户端证书的 CA 提供 CA 证书。如果您没有此基础架构(或者如果您正在构建它并且还没有任何客户端证书),您应该考虑创建自己的 PKI,或者可能从知名 CA 购买客户端证书。
您还可以构建一个 TrustManager 接受自签名证书(独立于任何 CA)并使用预定义列表中的指纹验证它们,但这会带来许多问题(特别是服务器如何要求正确的证书),您最终可能会复制 PKI 的部分用途。除非您对自己的工作有更多了解,否则我不建议这样做。
这有点令人沮丧。我曾希望我可以等到获得请求 URL,然后才需要为授权客户端检索指纹,然后才能与实际客户端进行身份验证的指纹进行比较。
在这里,您谈论的是完全不同的方面。如果您想先获取请求的 URL,在请求证书之前,您需要使用重新协商。HTTP 层必须与SSLEngine
for 对话,请求它触发新的握手(现在设置为请求客户端证书)。
SSLEngine
一般来说,在 Java 中通向 SSL/TLS 并不容易,但异步重新协商可能会变得非常棘手。事实上,它的语义在应用层还不是很清楚。您很可能在收到 HTTP 请求后触发重新协商,但同时正在发送响应(因为您可能有异步请求/响应,可能是流水线的)。从技术上讲,新的握手会影响两个管道。
总体而言,无论是否重新协商,这与检查您如何信任客户端证书完全无关。如果你真的想让你的应用程序层(而不是 SSL/TLS 层)进行证书验证,你必须编写一个X509TrustManager
信任任何东西(绕过 SSL/TLS 层的验证)和让您的应用程序从SSLSession
(对等证书)获取证书并在那里进行验证。总的来说,这与接受自签名证书并更手动地验证它们非常相似。可以这样做,但是您将退出 PKI 模型,并且您需要一些自定义代码来执行此操作(而不是仅使用默认使用的 API)。
如果你对这一切都不熟悉,我会避免这种方法。尝试设置一个测试 CA 并首先了解它是如何工作的。关于使用 CA 或进行手动指纹验证的整个问题最终更多的是一个管理问题:它由您将如何在相关各方之间分发证书来定义。
另外,<the key password>
这里在做什么?这应该在某处托管设施的无人值守服务器上运行;我们不能等待有人在启动过程中输入密码(例如,停电后)。
您需要设置密码。如果需要,大多数服务器会从配置文件中读取它(或者更糟糕的是,您可以对其进行硬编码)。