Thanks Domien.
First off, thank you so much for the detailed bug report, and how to
reproduce. It made creating a reproducer very easy.
JDK-8221218 and friends were test bugs, but happen to have the same
exceptions that you're seeing here.
This is an unrelated issue. I have filed JDK-8331682 [1] as an possible
usability enhancement (full details there including why this fails on
TLSv1.3 but not 1.2). It's not very high on the priority list.
TLS depends on TCP's reliable ordering (retry/etc.), so about the only
thing we might do if the client abandons the connection with a
close_notify is to retry the inbound message as plaintext if there is a
decryption failure on that flight.
BTW, the plaintext alerts you mention in step 5 are
protocol-independent, so should work in any version of TLS.
Hope this helps.
Brad
[1] https://bugs.openjdk.org/browse/JDK-JDK-8331682
On 5/3/2024 8:28 AM, Domien Nowicki wrote:
Hi everyone,
Recently we've started to use SSLEngine to create our own TLS server.
However we sometimes got the following exception
"SSLHandshakeException: Insufficient buffer remaining for AEAD cipher
fragment (2)." when dealing with client disconnections at server side
during the TLS handshake. This has been tested with latest JDK21.
We started to investigate and traced it down to the following scenario:
- Setup: Standard SSLSocket as client (all defaults) connects to our
TLS server using Java SSLEngine as internal engine. Both client and
server have support for TLSv1.3
1. Client sends hello
"client version" : "TLSv1.2",
"supported_versions (43)": {
"versions": [TLSv1.3, TLSv1.2]
},
2. Server processes the client hello, and attempts to send server hello:
"server version" : "TLSv1.2",
"supported_versions (43)": {
"selected version": [TLSv1.3]
},
3. From this point, server has switched to TLSv1.3 and is using a
GcmReadCipher (from SSLCipher class)
4. However, in this scenario, due to network congestion or server
application being slow, the server hello response is delayed and did
not reach the client yet
5. The client, still assuming it is operating under TLSv1.2, gets a
timeout and decides to close the socket. This produces TLSv1.2 alerts
(user canceled and close notification) and reaches the server
6. Server tries to decrypt the TLSv1.2 alerts, but since TLSv1.2
alerts are not encrypted, gets the "SSLHandshakeException:
Insufficient buffer remaining for AEAD cipher fragment (2)." exception.
If the client did receive the server hello response, it would switch
to TLSv1.3 properly and would encrypt TLSv1.3 alerts from then on as
expected.
Additionally, if we use the same scenario but force TLSv1.2 on the
server side, then the server does not use the GcmReadCipher at this
point, and it can process the TLSv1.2 alerts properly.
So it seems the JDK SSLEngine did not take the above scenario into
account, or are we missing something?
Best regards,
Domien