升级到 TLSv1.3 时 SSLEngine 使用的变化

Changes in SSLEngine usage when going up to TLSv1.3

Java 11 已发布 TLSv1.3 支持,默认使用。

它在 HTTPS 和 SSL 套接字的上下文中工作正常,但似乎在使用 SSLEngine 时由于 TLSv1.3 行为的变化而存在额外的障碍。

因此,使用 SSLEngine 通过 NIO 进行通信的稳健实现在启用 TLSv1.3 时不再有效。没有明显的错误,以异常或 SSL 错误的形式,两个节点只会来回发送 wrap/unwrap 消息并最终超时。

我对使用 TLSv1.2 的 SSLEngine 和使用 TLSv1.3 的 SSLEngine 之间行为变化的确切列表感兴趣,如果可能的话,我还想知道它们之间的迁移清单。不幸的是,Java 11 的 SSLEngine javadoc 没有此信息 - Java 11 中没有新方法,也没有对 TLSv1.3 的引用。

JDK11 的 Javadoc 中确实没有明确提及 TLS 1.3 对 SSLEngine 的影响,其方法也没有变化。

但是 the fifth item (closure) in the list of phases of SSLEngine 在 JDK 11 的 Javadoc 开头的一般描述中进行了更新:

Closure - When the connection is no longer needed, the client and the server applications should each close both sides of their respective connections. For SSLEngine objects, an application should call closeOutbound() and send any remaining messages to the peer. Likewise, an application should receive any remaining messages from the peer before calling closeInbound(). The underlying transport mechanism can then be closed after both sides of the SSLEngine have been closed. If the connection is not closed in an orderly manner (for example closeInbound() is called before the peer's write closure notification has been received), exceptions will be raised to indicate that an error has occurred. Once an engine is closed, it is not reusable: a new SSLEngine must be created.

Oracle's Release Notes for JDK 11 中也讨论了更改:

TLS 1.3 Half-Close Policy
A new system property, jdk.tls.acknowledgeCloseNotify, has been added. The default value of the system property is false. If the system property is set to true, a corresponding close_notify alert will be sent when receiving a close_notify alert, and the connection will be duplex closed.

TLS 1.2 and prior versions use a duplex-close policy, while TLS 1.3 uses a half-close policy. The inbound and the outbound close_notify alerts for TLS 1.3 are independent. When upgrading to TLS 1.3, unexpected behavior can occur if your application shuts down the (D)TLS connection by using only one of the SSLEngine.closeInbound() or SSLEngine.closeOutbound() APIs, but not both in each side of the connection. If your application exhibits unexpected hangs or timeouts when the underlying (D)TLS transportation is not duplex closed, you may need to set this property to true.

Note that when a TLS/DTLS connection is no longer needed, the client and server applications should each close both sides of their respective connection.

因此,将 jdk.tls.acknowledgeCloseNotify 设置为 true 可能会解决您在将 SSlEngine 与 TLS 1.3 一起使用时对超时的具体担忧:

If your application exhibits unexpected hangs or timeouts when the underlying (D)TLS transportation is not duplex closed, you may need to set this property to true.

发行说明文档还链接到已关闭的 JDK 错误 JDK-8208526 : TLS 1.3 half-close and synchronization issues,其中更详细地讨论了更改。

相关的(已关闭的)错误 JDK-8207009 : TLS 1.3 half-close and synchronization issues 也可能令人感兴趣。

其他参考资料:

  • 请参阅 RFC 8446 的“附录 D. 向后兼容性”:“传输层安全 (TLS) 协议版本 1.3”(第 138-141 页)。
  • 2:53:37 和 2:56:35 之间的 Oracle 视频“Monday Technical Sessions: Moscone West 2004”中简要讨论了 TLS 1.3 和早期版本之间的兼容性。

最后我们需要在握手完成后从buffer中读取剩余的数据,解包并更新握手状态。看起来像是我们之前没有处理的边缘情况。

相关提交:IGNITE-11298 Fixes to support TLSv1.3 in Communication