为什么java在SSL握手时不发送客户端证书?

2022-08-31 12:54:32

我正在尝试连接到安全的 Web 服务。

即使我的密钥库和信任库已正确设置,我还是遇到了握手失败。

经过几天的沮丧,无休止的谷歌搜索和询问周围的每个人,我发现唯一的问题是java选择在握手期间不将客户端证书发送到服务器。

具体说来:

  1. 服务器请求客户端证书 (CN=RootCA) - 即“给我一个由根 CA 签名的证书”
  2. Java查看了密钥库,只找到了我的客户端证书,该证书由“SubCA”签名,而子CA又由“RootCA”颁发。它懒得去查看信任库...嗯,好吧,我猜
  3. 可悲的是,当我尝试将“SubCA”证书添加到密钥库时,这根本没有帮助。我确实检查了证书是否被加载到密钥库中。它们会这样做,但密钥管理器会忽略除客户端证书之外的所有证书。
  4. 以上所有原因都导致Java决定它没有任何满足服务器请求的证书并且不发送任何内容...tadaaa 握手失败 :-(

我的问题:

  1. 我是否有可能以“破坏证书链”或其他方式将“SubCA”证书添加到密钥库,以便KeyManager仅加载客户端证书而忽略其余证书?(Chrome和opensl设法弄清楚了这一点,所以为什么java不能? - 请注意,“SubCA”证书总是单独显示为受信任的颁发机构,因此Chrome显然在握手期间将其与客户端证书一起正确打包)
  2. 这是服务器端的正式“配置问题”吗?服务器是第三方。我希望服务器请求由“SubCA”颁发机构签名的证书,因为这是他们提供给我们的。我怀疑这在Chrome和openssl中工作的事实是因为它们“限制较少”,而java只是“按本就行”并失败。

我确实设法为此制定了一个肮脏的解决方法,但我对此并不满意,所以如果有人能为我澄清这个问题,我会很高兴。


答案 1

您可能已将中间 CA 证书导入密钥库,但未将其与拥有客户机证书及其私钥的条目相关联。您应该能够使用 看到这一点。如果每个别名条目只获得一个证书,则它们不会在一起。keytool -v -list -keystore store.jks

您需要将证书及其链一起导入到具有您的私钥的密钥库别名中。

要找出哪个密钥库别名具有私钥,请使用(我假设此处的 JKS 存储类型)。这将告诉您类似如下的信息:keytool -list -keystore store.jks

Your keystore contains 1 entry

myalias, Feb 15, 2012, PrivateKeyEntry, 
Certificate fingerprint (MD5): xxxxxxxx

此处,别名为 。如果除此项外,还应看到 。myalias-vAlias Name: myalias

如果尚未单独拥有它,请从密钥库中导出客户机证书:

keytool -exportcert -rfc -file clientcert.pem -keystore store.jks -alias myalias

这应该给你一个PEM文件。

使用文本编辑器(或 ),准备文件(我们称之为)与该客户端证书和中间 CA 证书(如果需要,可能还有根 CA 证书本身),以便客户端证书位于开头,其颁发者证书位于正下方。catbundle.pem

这应该看起来像这样:

-----BEGIN CERTIFICATE-----
MIICajCCAdOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJVSzEa
....
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICkjCCAfugAwIBAgIJAKm5bDEMxZd7MA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNV
....
-----END CERTIFICATE-----

现在,将此捆绑包一起导入回您的私钥所在的别名中:

keytool -importcert -keystore store.jks -alias myalias -file bundle.pem

答案 2

作为此处的补充,您可以使用 %> openssl s_client -connect host.example.com:443,并查看转储并检查所有主证书是否对客户端有效。您正在输出底部查找此内容。验证返回代码:0(正常)

如果您添加 -showcerts,它将转储与主机证书一起发送的钥匙串的所有信息,这是您加载到钥匙串中的信息。