Java 7 使用 TLSv1.2 连接到 LDAPS 握手失败

Java 7 with TLSv1.2 connect to LDAPS handshake failure

目前我正在使用 Java 7,但我无法连接到 LDAPS。我尝试了下面的代码,但我仍然无法连接:

SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(null, null, null);
SSLContext.setDefault(ctx);

下面是我从程序中得到的错误:

2018-04-10 15:21:23,446 INFO [stdout] (EJB default - 1) EJB default - 1, WRITE: TLSv1.2 Handshake, length = 221

2018-04-10 15:21:23,446 INFO [stdout] (EJB default - 1) EJB default - 1, READ: TLSv1.2 Alert, length = 2

2018-04-10 15:21:23,446 INFO [stdout] (EJB default - 1) EJB default - 1, RECV TLSv1 ALERT: fatal, handshake_failure

2018-04-10 15:21:23,446 INFO [stdout] (EJB default - 1) EJB default - 1, called closeSocket()

2018-04-10 15:21:23,446 INFO [stdout] (EJB default - 1) EJB default - 1, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure


之后,我尝试 运行 协议测试来检查支持的协议:

Supported Protocols: 5
  SSLv2Hello
  SSLv3
  TLSv1
  TLSv1.1
  TLSv1.2
Enabled Protocols: 1
  TLSv1

我在 java.security 中添加了以下行以禁用 TLSv1 并启用 TLSv1.2:

jdk.tls.disabledAlgorithms= SSLv3, SSLv2Hello, TLSv1, TLSv1.1

并且 运行 再次进行协议测试,结果是:

Supported Protocols: 5
  SSLv2Hello
  SSLv3
  TLSv1
  TLSv1.1
  TLSv1.2
Enabled Protocols: 0

我已确认我的 LDAPS 服务器受支持并使用 TLSv1.2。我还在 Java 控制面板中启用了 TLS1.2,因为每当我尝试使用 TLSv1 时它都会导致 protocol_version 错误


我的问题是:

  1. 什么是 RECV TLSv1 ALERT: fatal, handshake_failure
  2. 如何在支持的协议中启用 TLSv1.2?
  3. 编辑 Java 7 或 8 是否支持密码套件:ECDHE-ECDSA-AES256-GCM-SHA384?

我正在使用 Java 1.7_80.

  1. What is RECV TLSv1 ALERT: fatal, handshake_failure ?

这意味着我们收到(在 Java SSL/TLS 代码中,JSSE)来自服务器的警告,严重程度为致命,类型为 handshake_failure。由于它在发送一个握手消息后立即发生,如果您没有从您发布的日志提取中遗漏其他相关信息,我们可能会收到此警报以响应 ClientHello 消息,这是发送的第一个握手消息。

这里的'TLSv1'可能会产生误导。它是 SSLSocketImpl 对象中的一个变量,它被初始化为 TLSv1,并且在握手完成之前不会更新,因此此时它不能准确指示正在使用的协议版本。 preceding 日志条目 'READ: TLSv1.2 Alert, length = 2' 确实 显示收到的实际版本并确认服务器至少正在尝试执行 TLS1.2。

是什么导致了handshake_failure?很多很多的事情。从这个警报中几乎不可能分辨出问题是什么。

  • 你最好的选择是查看服务器日志并找出为什么说它发送了警报。

  • 你最糟糕的选择是查看我们发送的 ClientHello——其中大部分应该在你发布的行之前已经被 JSSE 记录——并考虑服务器可能不喜欢其中或不在那里的所有内容,并尝试更改它们中的每一个。有些比较容易更改,有些则非常困难,因此这可能需要数小时到数周的时间。

  • 如果您有任何其他客户端成功连接到同一服务器,一个中间选项是查看 ClientHello 中有效和无效的差异' t,并考虑那些。作为这种情况的一个例子,如果您拥有或获得 OpenSSL,命令行 openssl s_client 可以快速且相当简单地用于测试 SSL/TLS 握手的一些但不是全部变体。

你可能猜到我推荐第一个。

  1. How to enable TLSv1.2 in supported Protocols?

您不需要在支持中启用它;您需要在 enabled 协议中启用它,您已经这样做了。使用 SSLContext.getInstance("TLSv1.2") 是一种方法。在 Java 8 但不是(编辑)7 的免费 Oracle 更新中,使用 sysprop jdk.tls.client.protocols 是另一种方式。 (7u95 向上实现此 sysprop,但对于 Oracle 7,7u80 以上的更新需要付费。如果 OpenJDK 在您的平台上可用,它通常是免费的。)在 SSLSocket 上调用 .setEnabledProtocols,一旦您拥有它,是其它的办法。

  1. Edit Does Java 7 or 8 support cipher suite: ECDHE-ECDSA-AES256-GCM-SHA384? I'm using Java 1.7_80.

Oracle/Sun 和 OpenJDK 7 不支持 GCM 密码套件。或者确切地说,它们中的标准 JSSE 提供程序没有,而且您没有说任何关于更改提供程序的事情。 (IBM Java 使用不同的提供商,我不知道他们,但他们大多使用不同的命名格式。)

Oracle 和 OpenJDK 8 支持 GCM 套件。但是,较旧的 Oracle 更新不支持 256 位 AES,除非您下载并安装 'Unlimited Jurisdiction Policy' 文件;您可以找到很多关于此的其他问题。这是最近修复的; 8u151/152 只需要文本编辑而不需要下载文件,而 8u161/162 和更高版本根本不需要任何更改。 Oracle 9 或任何 OpenJDK 都没有。