【问题标题】:Java client certificates and keystoresJava 客户端证书和密钥库
【发布时间】:2015-06-16 17:53:15
【问题描述】:

我们正在尝试建立一种 MUTUAL/2WAY 身份验证机制。

因为我们访问了两个不同的主机,所以我们在客户端密钥库容器中以两个不同的别名存储了相同的客户端证书(请注意相同的指纹):

root@perf-golem-4:/opt/golem# keytool -list -keystore ./client.keystore -storepass ________

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 2 entries

i.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 28:94:45:A1:78:C0:BD:D6:82:7E:09:66:15:11:8D:A5:56:0B:99:39
r.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 28:94:45:A1:78:C0:BD:D6:82:7E:09:66:15:11:8D:A5:56:0B:99:39

现在,在受信任的容器下,我们拥有目标域证书(请注意它们之间的指纹有何不同,并与上面的密钥库进行比较):

root@perf-golem-4:/opt/golem# keytool -list -keystore ./trusted.keystore -storepass _______

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 2 entries

i.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 73:F5:96:68:89:56:5E:50:9C:06:69:67:AC:8E:18:D2:D9:C1:33:71
r.domain.io, Jun 16, 2015, trustedCertEntry,
Certificate fingerprint (SHA1): 12:93:C8:41:3F:68:22:8F:40:F8:3C:B9:B6:C4:90:C0:60:49:D0:50

我的理解是,如果您必须存储具有与目标域名匹配的别名的证书(在我们的例子中为 i.domain.io 或 r.domain.io),那么 java 可以在以下情况下提供关联的证书作为客户端证书您正在尝试与该域建立 SSL 连接,例如https://r.domain.io

我们正在像这样启动我们的应用程序:

java    -Djavax.net.debug=all \
        -Djavax.net.ssl.keyStore=/opt/golem/client.keystore \
        -Djavax.net.ssl.keyStorePassword=_____ \
        -Djavax.net.ssl.trustStore=/opt/golem/trusted.keystore \
        -Djavax.net.ssl.trustStorePassword=_____ \

我们的问题是没有客户端证书被提供或从客户端使用,所以,最大的问题是 java 是否提供与目标域名(或目标 SSL 证书中的主题行)匹配的别名关联的客户端证书) 或者证书的名称应该从代码中删除?

【问题讨论】:

  • 别名与目标域无关。您不需要同一证书的多个副本。

标签: java ssl https ssl-certificate


【解决方案1】:

我的理解是,如果您必须存储具有与目标域名匹配的别名的证书(在我们的例子中为 i.domain.io 或 r.domain.io),那么 java 可以在以下情况下提供关联的证书作为客户端证书您正在尝试与该域建立 SSL 连接,例如https://r.domain.io

根本不是这样的。

匹配基于certificate_authorities list sent by the server in its TLS CertificateRequest message(颁发者)和密钥类型(例如 RSA 或 DSA)。如果属性不完全符合预期,则可以选择一些不完全匹配(请参阅this answer),但您至少希望让您的客户端证书由服务器宣传的 CA 颁发(这通常在服务器上自动完成当您配置它愿意接受的 CA 证书时,除非您在此处明确更改配置)。

如果需要中间证书,您一定要确保您拥有imported the full chain

基本上,在您的密钥库中拥有两次相同的证书是没有意义的。

(您可以尝试通过扩展自己的X509KeyManager 来强制使用特定别名,但这还不够;尤其是,这不会使服务器请求它,也不会使链有效。)

您需要确保服务器已配置为请求证书。这有时可以通过重新协商来完成,因此CertificateRequest TLS 消息可能不一定在使用 Wireshark 时可见。但是,您应该可以使用-Djavax.net.debug=ssl(或all)从客户端看到它:如果您在页面上搜索CertificateRequestofficial documentation for Debugging SSL/TLS Connections 有一个示例。

然后,您需要确保您的证书(或客户端链的顶部,如果有中间证书)是由 CertificateRequest 消息中公布的 CA 之一(颁发者 DN必须匹配)。

(如果CertificateRequest 中的证书颁发机构列表为空,但CertificateRequest 消息仍然发送,客户端将默认发送它在其密钥库中找到的第一个证书。这种情况是非典型的,因为它通常需要在服务器端进行自定义配置。)

【讨论】:

  • 这里还有一个问题。 If Cert Authorities: 无论如何你可以通过客户端证书吗?
  • 是的,这就是我在最后一句中所说的:它将发送它找到的第一个证书(如果密钥库中只有一个证书,这应该不是问题)。服务器仍然需要发送该证书请求,证书是否被接受取决于服务器的实现和配置。它肯定需要一种方法来以一种或另一种方式验证该证书。
  • Bruno,还有一个问题:在服务器回复 CertificateRequest 后,客户端是否有必要使用/提供私钥?
  • 客户端确实向服务器提供了私钥,但它确实需要使用它来完成握手(对Certificate Verify消息的内容进行签名)。没有它,就没有身份验证(否则证书是相当公开的)。
  • @Bruno 你的意思是客户端确实向服务器提供私钥。
猜你喜欢
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
相关资源
最近更新 更多