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

我试图连接到一个安全的web服务。

即使我的密钥库和信任库已经正确设置,我仍然握手失败。

经过几天的沮丧,不停地search,并询问周围的人,我发现唯一的问题是,javaselect不握手握手期间发送客户端证书到服务器。

特别:

  1. 服务器请求客户端证书(CN = RootCA) – 即“给我一个由根CA签名的证书”
  2. Java查看密钥库,只发现我的客户端证书由“SubCA”签名,而“SubCA”则由“RootCA”发布。 它没有费心去查看信任库…呃好吧,我猜
  3. 可悲的是,当我试图将“SubCA”证书添加到密钥库时,根本没有任何帮助。 我没有检查证书是否加载到密钥库中。 他们这样做,但KeyManager忽略除客户端之外的所有证书。
  4. 所有上述导致的事实,即java决定它没有任何证书满足服务器的请求,并发送什么都没有… tadaaa握手失败:-(

我的问题:

  1. 是否有可能以“破坏证书链”的方式将密钥库中的“SubCA”证书添加到密钥库中,以便KeyManager只加载客户端证书而忽略其他证书? (Chrome和opensslpipe理弄清楚,为什么不能java? – 请注意,“SubCA”证书总是作为受信任的权威机构单独提出,所以Chrome在握手期间显然正确地将其与客户端证书一起打包)
  2. 这是服务器端的一个正式的“configuration问题”吗? 服务器是第三方。 我希望服务器能够申请由“SubCA”机构签署的证书,因为这是他们提供给我们的。 我怀疑,这在Chrome和openssl中起作用的事实是因为它们“较less限制”,而java只是“靠本书”而失败。

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

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

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

要找出哪个密钥库别名具有私钥,请使用keytool -list -keystore store.jks (我假设这里是JKS存储types)。 这会告诉你这样的事情:

 Your keystore contains 1 entry myalias, Feb 15, 2012, PrivateKeyEntry, Certificate fingerprint (MD5): xxxxxxxx 

在这里,别名是myalias 。 如果除此之外还使用-v ,则应该看到Alias Name: myalias

如果您还没有单独购买,请从密钥库导出您的客户端证书:

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

这应该给你一个PEM文件。

使用文本编辑器(或cat ),使用该客户端证书和中间CA证书(如果需要的话可能还有根CA证书本身)准备文件(我们称之为bundle.pem ),以便客户端证书位于刚开始时,其发行人证书就在其中。

这应该看起来像:

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

现在,将这个包一起导入到您的私钥所在的别名中:

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

布鲁诺,这解释了很多 – 谢谢你!

作为一个补充,您可以使用%> openssl s_client -connect host.example.com:443并查看转储,并检查所有主要证书是否对客户端有效。 您正在输出的底部寻找这个。 validation返回码:0(ok)

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

再次,谢谢!