0

I am getting the following error when trying to connect to IBM's Watson API:

java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at com.ibm.watson.developer_cloud.service.security.IamTokenManager.callIamApi(IamTokenManager.java:190)
        at com.ibm.watson.developer_cloud.service.security.IamTokenManager.requestToken(IamTokenManager.java:108)
        at com.ibm.watson.developer_cloud.service.security.IamTokenManager.getToken(IamTokenManager.java:78)
        at com.ibm.watson.developer_cloud.service.WatsonService.setAuthentication(WatsonService.java:375)
        at com.ibm.watson.developer_cloud.service.WatsonService.createCall(WatsonService.java:206)
        at com.ibm.watson.developer_cloud.service.WatsonService.createServiceCall(WatsonService.java:240)
        at com.ibm.watson.developer_cloud.assistant.v2.Assistant.createSession(Assistant.java:107)
        [...]
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:128)
        at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
        at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:308)
        at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Alert.java:279)
        at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:181)
        at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
        at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
        at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063)
        at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
        at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:318)
        at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:282)
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:167)
        at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
        at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)

[...]

This is the Java code which tries to initiate the API call:

// Init assistant
IamOptions imaOptions = new IamOptions.Builder()
    .apiKey(API_KEY)
    .build();

assistant = new Assistant("2019-03-13", imaOptions);
assistant.setEndPoint(END_POINT_FRA);

// Create session
CreateSessionOptions options = new CreateSessionOptions.Builder(ASSISTANT_ID).build();
ServiceCall<SessionResponse> session = assistant.createSession(options);

The exception is thrown in the last line. Interestingly, I am able to connect perfectly fine when I run this through a stand-alone unit test. It is only when I try to connect from a server application that I get this SSL error.

I have already tried the following:

  • import all required SSL certificates into the applications's truststore

  • set system property to support TLS 1.2 prior to TLS 1.1

  • verified that JCE full policy files are installed (as part of Java 11, which is the version I am on)

  • used nmap to verify the server's cipher suites and check that they are supported by the JDK ( nmap -sV --script ssl-enum-ciphers -p 443 wildcard.bluemix.net )

I have also read through and followed these here articles:

Received fatal alert: handshake_failure through SSLHandshakeException

https://confluence.atlassian.com/jirakb/sslhandshakeexception-received-fatal-alert-handshake_failure-due-to-no-overlap-in-cipher-suite-943544397.html

I am a bit lost now. Any ideas what might be cuasing the SSL handshake problem or how I could diagnose it further?

==== Update ====

After digging around this topic, I think I have managed to isolate it. It seems to be an actual bug in Java 11.0.1, which is also still present in 11.0.2. Root cause is that Java 11 (OpenJDK) does not play nice with TLSv1.3, as described here: https://webtide.com/openjdk-11-and-tls-1-3-issues/ and in a bug report here https://bugs.openjdk.java.net/browse/JDK-8213202

Now the issue is how to disable TLSv1.3. I have already tried the solutions provided here https://blogs.oracle.com/java-platform-group/jdk-8-will-use-tls-12-as-default and here https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html (protocols and properties), but for some reason this disabling does not take effect in my case. My code is using the org.apache.http.impl.client.ClosableHttpClient and the Builder does not allow me access to the underlying SSLConnectionSocketFactory (where I might be able to disable TLSv1.3). So, the question remains: How can I disable TLSv1.3 in this particular setting?

(PS: The problem also occures when trying to access the Google NL and Vision APIs - language.googleapis.com and vision.googleapis.com)

martin_wun
  • 1,599
  • 1
  • 15
  • 33
  • Are you running the server app on your own machine, in a docker image, in the cloud? Does the server app have self-signed certificates? – chughts Mar 19 '19 at 13:36
  • The server is running locally on my dev machine in the company network. It doesn't self-signed certificates and I have imported the required ones into the truststore used by the system. – martin_wun Mar 20 '19 at 15:55
  • Problem solved by disabling TLSv.1.3: "-Djdk.tls.client.protocols=TLSv1.1,TLSv1.2" – martin_wun Apr 01 '19 at 10:46

1 Answers1

0

There is a bug in JDK 11.0.1 and 11.0.2 related to TLSv1.3. This version of the TLS protocol needs to be disabled by setting the following system property:

-Djdk.tls.client.protocols=TLSv1.1,TLSv1.2

Presumably, this bug will be fixed with the release of JDK 11.0.3., which is due mid-April '19.

martin_wun
  • 1,599
  • 1
  • 15
  • 33