Java 客户端证书和密钥库
Java client certificates and keystores
我们正在尝试构建 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 证书中的行)或证书的名称应该从代码中删除?
My understanding is that if you have to store a certificate with an alias matching the target domain name (in our case i.domain.io or r.domain.io) so java can provide the associated certificate as a client certificate when you are attempting a SSL connection to that domain e.g. https://r.domain.io
完全不是这样。
匹配基于 certificate_authorities
list sent by the server in its TLS CertificateRequest
message (the issuers), and on the type of key (e.g. RSA or DSA). Some imperfect matches can be chosen if the attributes are not quite as expected (see this answer),但您至少希望您的客户端证书由服务器宣传的 CA 颁发(这通常在您配置时在服务器端自动完成它愿意接受的 CA 证书,除非您明确更改那里的配置)。
如果需要中间证书,您当然要确保您已经 imported the full chain。
本质上,在您的密钥库中拥有两次相同的证书是没有意义的。
(您可以尝试通过扩展自己的 X509KeyManager
来强制使用特定的别名,但这还不够;特别是,这不会让服务器请求它,也不会使链有效。)
您需要确保服务器配置为请求证书。这有时可以通过重新协商来完成,因此 CertificateRequest
TLS 消息可能不一定使用 Wireshark 可见。但是,您应该能够使用 -Djavax.net.debug=ssl
(或 all
)从客户端看到它:如果您在页面上搜索 CertificateRequest
,official documentation for Debugging SSL/TLS Connections 有一个示例。
然后,您需要确保您的证书(或客户端链的顶部,如果有中间证书)是由 CertificateRequest
消息中通告的 CA 之一颁发的(发行者 DN 必须匹配)。
(如果CertificateRequest
中的证书颁发机构列表为空,但CertificateRequest
消息仍然发送,客户端将默认发送它在其密钥库中找到的第一个证书。那种场景不典型,因为它通常需要在服务器端进行自定义配置。)
我们正在尝试构建 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 证书中的行)或证书的名称应该从代码中删除?
My understanding is that if you have to store a certificate with an alias matching the target domain name (in our case i.domain.io or r.domain.io) so java can provide the associated certificate as a client certificate when you are attempting a SSL connection to that domain e.g.
https://r.domain.io
完全不是这样。
匹配基于 certificate_authorities
list sent by the server in its TLS CertificateRequest
message (the issuers), and on the type of key (e.g. RSA or DSA). Some imperfect matches can be chosen if the attributes are not quite as expected (see this answer),但您至少希望您的客户端证书由服务器宣传的 CA 颁发(这通常在您配置时在服务器端自动完成它愿意接受的 CA 证书,除非您明确更改那里的配置)。
如果需要中间证书,您当然要确保您已经 imported the full chain。
本质上,在您的密钥库中拥有两次相同的证书是没有意义的。
(您可以尝试通过扩展自己的 X509KeyManager
来强制使用特定的别名,但这还不够;特别是,这不会让服务器请求它,也不会使链有效。)
您需要确保服务器配置为请求证书。这有时可以通过重新协商来完成,因此 CertificateRequest
TLS 消息可能不一定使用 Wireshark 可见。但是,您应该能够使用 -Djavax.net.debug=ssl
(或 all
)从客户端看到它:如果您在页面上搜索 CertificateRequest
,official documentation for Debugging SSL/TLS Connections 有一个示例。
然后,您需要确保您的证书(或客户端链的顶部,如果有中间证书)是由 CertificateRequest
消息中通告的 CA 之一颁发的(发行者 DN 必须匹配)。
(如果CertificateRequest
中的证书颁发机构列表为空,但CertificateRequest
消息仍然发送,客户端将默认发送它在其密钥库中找到的第一个证书。那种场景不典型,因为它通常需要在服务器端进行自定义配置。)