2

To prepare for Java 11 and later releases, I am currently working on migrating our application from Java 8 to Java 10. I have encountered a problem in one of our tests where we are expecting a SSLHandshakeException as a result of sending a bad certificate. Instead of receiving mentioned exception, the application instead throws a SocketException.

The stack trace of the unexpected SocketException:

java.lang.Exception: Unexpected exception, expected<javax.net.ssl.SSLHandshakeException> but was<java.net.SocketException>

Caused by: java.net.SocketException: Datenübergabe unterbrochen (broken pipe) (Write failed)
at java.base/java.net.SocketOutputStream.socketWrite0(Native Method)
at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:155)
at java.base/sun.security.ssl.SSLSocketOutputRecord.flush(SSLSocketOutputRecord.java:236)
at java.base/sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:79)
at java.base/sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1208)
at java.base/sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1408)
at java.base/sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1312)
at java.base/sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:418)
at java.base/sun.security.ssl.Handshaker.processLoop(Handshaker.java:1098)
at java.base/sun.security.ssl.Handshaker.processRecord(Handshaker.java:1026)
at java.base/sun.security.ssl.SSLSocketImpl.processInputRecord(SSLSocketImpl.java:1137)
at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1074)
at java.base/sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
at java.base/sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1402)
at java.base/sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:733)
at java.base/sun.security.ssl.AppOutputStream.write(AppOutputStream.java:67)
at java.base/sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:233)
at java.base/sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:312)
at java.base/sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:316)
at java.base/sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:153)
at java.base/java.io.OutputStreamWriter.flush(OutputStreamWriter.java:254)
at java.base/java.io.BufferedWriter.flush(BufferedWriter.java:257)
at de.sourcepark.security.cryptolib.ssl.DefaultSSLContextProviderTest.testMutualAuthFail(DefaultSSLContextProviderTest.java:203)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:21)
... 23 more

The stack trace of expected SSLHandshakeException would look like this:

javax.net.ssl.SSLHandshakeException

Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2038)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1135)
at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1779)
at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:124)
at sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1156)
at sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1266)
at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1178)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:348)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1052)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:987)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1072)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:757)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
at java.io.BufferedWriter.flush(BufferedWriter.java:254)
at de.sourcepark.security.cryptolib.ssl.DefaultSSLContextProviderTest.testMutualAuthFail(DefaultSSLContextProviderTest.java:204)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:21)
... 23 more

From reading the release notes for Java 9 and 10 I already gathered that they changed a bunch of stuff regarding SSL/TLS but I haven't found anything mentioning this particular behavior.

Is receiving a SocketException after sending a bad certificate now expected behavior? If not, what could have gone wrong? If so, why was this change made? I know they are planning to integrate TLS 1.3 into Java 11 as of JEP 332. Is this maybe the reason?

I am at a loss and would appreciate any help, thank you all in advance.

P. Wolf
  • 21
  • 3
  • The server appears to have changed its behaviour. Investigate. – user207421 Jun 20 '18 at 08:48
  • The following sounds related: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8172163 – Thorsten Schöning Jan 15 '19 at 21:04
  • Running into a similar problem with Apache HttpComponents Core, Oracle JDK 8 192 and Windows. They implemented a workaround: https://github.com/apache/httpcomponents-core/commit/c36d0f9f3c197f80fe6e67d2f6f64d51cc351e1b I'm pretty sure this worked on Windows with former versions of the JDK 7 as well, regardless what they say in their commit message. – Thorsten Schöning Jan 16 '19 at 15:45

0 Answers0