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
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)