Details
-
Bug
-
Status: Closed
-
P4
-
Resolution: Fixed
-
8, 11, 17
-
b20
-
Not verified
Description
ADDITIONAL SYSTEM INFORMATION :
Ubuntu 20.04, AdoptOpenJDK 11.0.10 and 1.8.0_282
A DESCRIPTION OF THE PROBLEM :
By connecting the SSLEngine with a misbehaving peer SSL implementation, it can get into a state where it calling `wrap` reports getStatus == OK, getHandshakeStatus === NEED_WRAP but still doesn't produce any further output.
If not explicitly guarded against this scenario, this situation can make the driving code run into a spin loop, because it expects the SSLEngine to eventually make progress.
This is also a potential DoS vector against servers.
See https://bugs.openjdk.java.net/browse/JDK-8240071 for a similar bug (the linked duplicate is not publicly accessible so I cannot say if or how it was resolved).
I stepped through the JDK 11.0.10 code and found this:
* engine.getHandshakeStatus() returns NEED_WRAP if !outputRecord.isEmpty (i.e. there's output ready to be sent, that's the case here)
* on the other hand outputRecord.isClosed is also true, which prevents the SSLEngine from actually producing any further output
From what I can see, the problem happens when the server SSLEngine consumes an "unexpected message" alert from the client.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See https://github.com/akka/akka/issues/29922 for the initial bug report against Akka. It contains a reproducer that emulates a broken SSL implementation on the peer by randomly throwing packets away.
This runs into the described spin loop after a few iterations a few seconds after the start.
The exact conditions leading to the condition are unclear.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
SSLEngine should fail eagerly instead of reaching invalid states. (E.g. OutputRecord should guard against being non empty and closed at the same time).
ACTUAL -
wrap does not produce any output.
---------- BEGIN SOURCE ----------
https://github.com/maxcom/akka-http-tls-stress
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Check invariant that if status == OK, handshakeStatus == NEED_WRAP, wrap must have produced some output or fail otherwise.
FREQUENCY : rarely
Ubuntu 20.04, AdoptOpenJDK 11.0.10 and 1.8.0_282
A DESCRIPTION OF THE PROBLEM :
By connecting the SSLEngine with a misbehaving peer SSL implementation, it can get into a state where it calling `wrap` reports getStatus == OK, getHandshakeStatus === NEED_WRAP but still doesn't produce any further output.
If not explicitly guarded against this scenario, this situation can make the driving code run into a spin loop, because it expects the SSLEngine to eventually make progress.
This is also a potential DoS vector against servers.
See https://bugs.openjdk.java.net/browse/JDK-8240071 for a similar bug (the linked duplicate is not publicly accessible so I cannot say if or how it was resolved).
I stepped through the JDK 11.0.10 code and found this:
* engine.getHandshakeStatus() returns NEED_WRAP if !outputRecord.isEmpty (i.e. there's output ready to be sent, that's the case here)
* on the other hand outputRecord.isClosed is also true, which prevents the SSLEngine from actually producing any further output
From what I can see, the problem happens when the server SSLEngine consumes an "unexpected message" alert from the client.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See https://github.com/akka/akka/issues/29922 for the initial bug report against Akka. It contains a reproducer that emulates a broken SSL implementation on the peer by randomly throwing packets away.
This runs into the described spin loop after a few iterations a few seconds after the start.
The exact conditions leading to the condition are unclear.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
SSLEngine should fail eagerly instead of reaching invalid states. (E.g. OutputRecord should guard against being non empty and closed at the same time).
ACTUAL -
wrap does not produce any output.
---------- BEGIN SOURCE ----------
https://github.com/maxcom/akka-http-tls-stress
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Check invariant that if status == OK, handshakeStatus == NEED_WRAP, wrap must have produced some output or fail otherwise.
FREQUENCY : rarely