Java SSL选择错误的证书,忽略密钥用法

时间:2014-03-27 15:07:21

标签: java ssl certificate

我有一个使用SSL进行通信的客户端/服务器。

客户端中的密钥库JKS包含具有不同密钥用法的两个证书。 Cert 1用于SSL通信,cert 2用于签名数据:

  1. 一个证书有KU=keyEncipherment,digitalSignature, EKU=clientAuth
  2. 一个证书有KU=nonRepudiation,digitalSignature
  3. 当我使用它时,它会选择第一个(正确!)。如果我从JKS中删除第一个证书,它会在连接到服务器时选择nonRepudiation证书(错误!?)。

    这对我来说毫无意义,因为nonRep永远不应该像afaik一样使用。

    那么,我该怎么做才能解决这个问题,如何让Java SSL选择具有合理密钥用途的证书?

    Btw,Windows上的JDK1.70_21。我使用的代码是标准的东西。只是获得默认密钥管理器等

1 个答案:

答案 0 :(得分:4)

首先,您的第二个证书可能具有nonRepudiation密钥使用扩展名,但据我所知,这并不会使其对客户端证书的使用无效。 TLS规范并没有真正说明客户端的密钥使用情况,尽管从技术上讲,它使用数字签名(因此您的证书都可能有效)。假设确实需要digitalSignature(实际上,据我所知),你的证书都有,所以你的证书都是合适的。一个人也有其他关键用法的事实是另一回事。

此外,clientAuth不是关键用法扩展,而是扩展密钥用法扩展(或Netscape扩展)。您的第二个证书缺少任何扩展密钥用法扩展,可以使任何扩展密钥使用成为可能。

其次,JSSE中默认X509KeyManager实现的作者选择在缺少完美匹配时返回不完美匹配。见code comments

/*
* Return the best alias that fits the given parameters.
* The algorithm we use is:
* . scan through all the aliases in all builders in order
* . as soon as we find a perfect match, return
* (i.e. a match with a cert that has appropriate key usage
* and is not expired).
* . if we do not find a perfect match, keep looping and remember
* the imperfect matches
* . at the end, sort the imperfect matches. we prefer expired certs
* with appropriate key usage to certs with the wrong key usage.
* return the first one of them.
*/
private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers,

因此,当缺少keyEncipherment,digitalSignature,clientAuth的证书时,它将退回到另一个证书上。

这是一个有争议的选择,但它并不一定是坏事。有些实现和部署不一定是100%标准兼容的,并且无论您的CA提供什么,它都能够发送一些东西。在一天结束时,它不是一个巨大的风险,因为(a)你真的由你来选择你放在你的密钥库中的东西和(b)它取决于服务器检查所有情况下的密钥使用情况。

在您使用javax.net.ssl.keyStore属性设置的密钥库中放置一个您不想用于SSL / TLS使用的证书,或者构建一个SSLContext,这似乎很奇怪它

我不确定您为什么要将它放在此密钥库中,但如果您需要其他证书可用于您的应用程序中的其他内容,则通常更容易将其放在不同的密钥库中

或者,您可以实现自己的X509KeyManager并根据需要覆盖其chooseClientAlias方法。在这种情况下,我会创建一个类,将所有调用委托给默认的X509KeyManager(使用默认算法从KeyManagerFactory获得并使用您的密钥库初始化),除了chooseClientAlias #39; d在返回别名之前检查密钥用法类型。它确实可行,但比使用两个密钥库要多一些工作。

供参考: