【问题标题】:Java SSL picks wrong cert, ignores key usageJava SSL 选择错误的证书,忽略密钥使用
【发布时间】:2014-05-06 15:57:44
【问题描述】:

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

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

  1. 一个证书有KU=keyEncipherment,digitalSignature, EKU=clientAuth
  2. 一个证书有KU=nonRepudiation,digitalSignature

当我使用它运行时,它会选择第一个(正确!)。如果我从 JKS 中删除第一个证书,它会在连接到服务器时选择带有 nonRepudiation 的证书(错误!?)。

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

那么,我能做些什么来解决这个问题,我怎样才能让 Java SSL 只选择具有合理密钥使用的证书?

顺便说一句,Windows 上的 JDK1.70_21。我使用的代码是标准的东西。只是获取默认的密钥管理器等

【问题讨论】:

  • 您采用什么 Java 运行时(制造商、平台和版本)?
  • JDK1.70_21 在 Windows 上。

标签: java ssl certificate


【解决方案1】:

首先,您的第二个证书可能具有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) 在所有情况下都由服务器检查密钥使用情况。

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

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

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

供参考:

【讨论】:

  • 谢谢!拥有一个包含两个证书的密钥库只是为了让用户更容易。只需处理一个文件,然后根据 keyUsage/extKeyUsage(或别名)选择正确的文件。
  • 顺便说一句,X509KeyManagerImpl 评论很棒!鉴于 Java 中有大量与加密相关的类,我有点假设有一种更简单的方法来配置/构建管理器,而无需使用内部类或从头开始编写它(由于显而易见的原因,这有点可怕)。
  • 您的主要问题是我认为这两个证书都对客户端证书的使用有效。我建议让用户明确指定别名(您可能需要编写一个小的 X509KeyManager 只返回配置的别名,但这应该不会太难)。
  • 从证书 2 中删除 digitalSignature 使这项工作如我所愿。谷歌搜索 NR 和 DS,我觉得这是推荐的。对于instance
猜你喜欢
  • 2012-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-02
  • 2012-01-31
  • 2015-04-22
相关资源
最近更新 更多