Solution for java.net.ConnectException: General SSLEngine problem

Recently I faced below error in my play application. My play application was trying to hit a server over https.

{"errors":[{"code":"General SSLEngine problem","message":"java.net.ConnectException: General SSLEngine problem\n\tat org.asynchttpclient.netty.channel.NettyConnectListener.onFailure(NettyConnectListener.java:162)\n\tat org.asynchttpclient.netty.channel.NettyConnectListener$1.onFailure

This exception occurred because the keystore used by play application did not have server’s certificate loaded.
The server’s certificate in keystore tells the client (here my play application) to trust the https connection. Since server’s certificate was missing in keystore used by client, the above exception occurred.
This problem can be fixed by adding server’s certificate in the keystore used by your play application. By default play application uses keystore ${java.home}/lib/security/cacerts . Following steps can be performed to add a certificate in a keystore:

Fetch the Server’s SSL certificate:

openssl s_client -connect ${SERVERHOST}:${SERVERPORT} </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ${SERVERHOST}.cert

Load certificate to keystore:

keytool -import -noprompt -trustcacerts -alias ${SERVERHOST} -file ${SERVERHOST}.cert -keystore ${KEYSTORE} -storepass ${KEYSTOREPASSWORD}

To verify server’s certificate is added into your keystore, you can use keytool -list command.

keytool -list -v -keystore ${KEYSTORE} -storepass ${KEYSTOREPASSWORD} -alias ${SERVERHOST}

Alternatively, you can fire a curl command with cacert option.

Let’s say your SERVERHOST is example.com , SERVERPORT is 8090, KEYSTORE file is /usr/lib/jvm/java/jre/lib/security/cacerts and KEYSTOREPASSWORD is changeit (changeit is the default password for ${java.home}/lib/security/cacerts ). The above commands will look like as below:

openssl s_client -connect example.com:8090 </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > example.com.certkeytool -import -noprompt -trustcacerts -alias example.com -file example.com.cert -keystore /usr/lib/jvm/java/jre/lib/security/cacerts -storepass changeitkeytool -list -v -keystore /usr/lib/jvm/java/jre/lib/security/cacerts -storepass changeit -alias example.com

Once the above steps are done, your play application should not throw sslengine problem exception.

${java.home}/lib/security/cacerts is the default keystore used by a play app. But you can also configure your play app to use any keystore. If your keystore path is ${store.directory}/truststore, put the below line in application.conf:

ws.ssl {
trustManager = {
stores = [
{ path: ${store.directory}/truststore}
{ path: ${java.home}/lib/security/cacerts }
]
}
}

Here each each keystore will be tried in order.

I think this much information is enough to solve sslengine problem exception. More info about configuring keystore of a play app can be found on play official documentation.