in Code

Solving “Received fatal alert: handshake_failure” error when performing HTTPS connections on a custom made JRE with jlink

TL; Tell me already what to do:
Add the jdk.crypto.cryptoki module to the list of --add-modules parameter to your jlink command invocation


If you’re reading this you’re one of the few developers out there that wanted to distribute a java 9+ app (using either jdk 9, jdk 10, jdk 11 or jdk 12, as of this writing) with a smaller version of the jdk, to build your custom jre, you used the jlink tool.

When you run your app using the full JRE that comes with the OpenJDK, your app is working fine when it comes to making https requests, but when you run your app using your custom jre you get the following error when opening https connections

[pastacode lang=”bash” manual=”Received%20fatal%20alert%3A%20handshake_failure” message=”” highlight=”” provider=”manual”/]

This issue occurs because your JRE is missing lots of Cipher Suites that come with the full JDK.

With your JDK, you can try to check the list of supported ciphers with this one liner using the jrunscript tool:

[pastacode lang=”bash” manual=”jrunscript%20-e%20%22print(java.util.Arrays.toString(javax.net.ssl.SSLServerSocketFactory.getDefault().getSupportedCipherSuites()))%22%0A” message=”” highlight=”” provider=”manual”/]

however that might not work for your custom JRE if you haven’t included the scripting module, so here’s a Java program I made that prints all the available Ciphers of your JRE

[pastacode lang=”java” manual=”public%20class%20PrintCiphers%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09var%20sslSocketFactory%20%3D%20javax.net.ssl.SSLServerSocketFactory.getDefault()%3B%0A%09System.out.println(%22SSLServerSocketFactory%20-%3E%20%22%20%2B%20sslSocketFactory.getClass().getName())%3B%0A%09try%20%7B%0A%20%20%09%20%20%20%20var%20getSupportedCipherSuitesMethod%20%3D%20sslSocketFactory.getClass().getMethod(%22getSupportedCipherSuites%22)%3B%0A%09%20%20%20%20String%5B%5D%20ciphers%20%3D%20(String%5B%5D)%20getSupportedCipherSuitesMethod.invoke(sslSocketFactory)%3B%0A%09%20%20%20%20int%20i%3D1%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(String%20c%20%3A%20ciphers)%20%7B%0A%09%09System.out.println(i%2B%2B%20%2B%20%22%20%22%20%2B%20c)%3B%0A%09%20%20%20%20%7D%0A%09%7D%20catch(Throwable%20t)%20%7B%0A%09%20%20%20%20t.printStackTrace()%3B%0A%09%7D%0A%20%20%20%20%7D%0A%7D%0A” message=”” highlight=”” provider=”manual”/]

If you run PrintCiphers on your OpenJDK’s full JRE, you will see almost 50 Cipher Suites available:

[pastacode lang=”bash” manual=”%24%20java%20PrintCiphers%3B%0A1%20TLS_AES_128_GCM_SHA256%0A2%20TLS_AES_256_GCM_SHA384%0A3%20TLS_CHACHA20_POLY1305_SHA256%0A4%20TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384%0A5%20TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256%0A6%20TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256%0A7%20TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384%0A8%20TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256%0A9%20TLS_RSA_WITH_AES_256_GCM_SHA384%0A10%20TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384%0A11%20TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384%0A12%20TLS_DHE_RSA_WITH_AES_256_GCM_SHA384%0A13%20TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256%0A14%20TLS_DHE_DSS_WITH_AES_256_GCM_SHA384%0A15%20TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256%0A16%20TLS_RSA_WITH_AES_128_GCM_SHA256%0A17%20TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256%0A18%20TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256%0A19%20TLS_DHE_RSA_WITH_AES_128_GCM_SHA256%0A20%20TLS_DHE_DSS_WITH_AES_128_GCM_SHA256%0A21%20TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384%0A22%20TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384%0A23%20TLS_RSA_WITH_AES_256_CBC_SHA256%0A24%20TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384%0A25%20TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384%0A26%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA256%0A27%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA256%0A28%20TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA%0A29%20TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA%0A30%20TLS_RSA_WITH_AES_256_CBC_SHA%0A31%20TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA%0A32%20TLS_ECDH_RSA_WITH_AES_256_CBC_SHA%0A33%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA%0A34%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA%0A35%20TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256%0A36%20TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256%0A37%20TLS_RSA_WITH_AES_128_CBC_SHA256%0A38%20TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256%0A39%20TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256%0A40%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA256%0A41%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA256%0A42%20TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA%0A43%20TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA%0A44%20TLS_RSA_WITH_AES_128_CBC_SHA%0A45%20TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA%0A46%20TLS_ECDH_RSA_WITH_AES_128_CBC_SHA%0A47%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA%0A48%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA%0A49%20TLS_EMPTY_RENEGOTIATION_INFO_SCSV%0A” message=”” highlight=”” provider=”manual”/]

but if you use your custom JRE to run PrintCiphers you will see only 23 Cipher Suites available:

[pastacode lang=”bash” manual=”%24%20jre%2Fbin%2Fjava%20PrintCiphers%0A1%20TLS_AES_128_GCM_SHA256%0A2%20TLS_AES_256_GCM_SHA384%0A3%20TLS_CHACHA20_POLY1305_SHA256%0A4%20TLS_RSA_WITH_AES_256_GCM_SHA384%0A5%20TLS_DHE_RSA_WITH_AES_256_GCM_SHA384%0A6%20TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256%0A7%20TLS_DHE_DSS_WITH_AES_256_GCM_SHA384%0A8%20TLS_RSA_WITH_AES_128_GCM_SHA256%0A9%20TLS_DHE_RSA_WITH_AES_128_GCM_SHA256%0A10%20TLS_DHE_DSS_WITH_AES_128_GCM_SHA256%0A11%20TLS_RSA_WITH_AES_256_CBC_SHA256%0A12%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA256%0A13%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA256%0A14%20TLS_RSA_WITH_AES_256_CBC_SHA%0A15%20TLS_DHE_RSA_WITH_AES_256_CBC_SHA%0A16%20TLS_DHE_DSS_WITH_AES_256_CBC_SHA%0A17%20TLS_RSA_WITH_AES_128_CBC_SHA256%0A18%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA256%0A19%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA256%0A20%20TLS_RSA_WITH_AES_128_CBC_SHA%0A21%20TLS_DHE_RSA_WITH_AES_128_CBC_SHA%0A22%20TLS_DHE_DSS_WITH_AES_128_CBC_SHA%0A23%20TLS_EMPTY_RENEGOTIATION_INFO_SCSV%0A” message=”” highlight=”” provider=”manual”/]

To solve the problem you must add the jdk.crypto.cryptoki module to the list of --add-modules parameter to your jlink command invocation, next time your run PrintCiphers you should see the full list of Cipher Suites and your SSL handshake issues should be gone.

Write a Comment

Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Webmentions

  • How to enable ECDHE ciphers with openjdk 14 on an Alpine docker container? - Sarkari Job Alert

    […] actually has nothing to do with Alpine or OpenJDK 14. I found the solution at http://www.gubatron.com/blog/2019/04/25/solving-received-fatal-alert-handshake_failure-error-when-pe… , just add jdk.crypto.cryptoki to the list of modules to add with […]

  • 如何在Alpine Docker容器上使用openjdk 14启用ECDHE密码? – FIXBBS

    […] 实际上,这与Alpine或OpenJDK 14无关。我在http://www.gubatron.com/blog/2019/04/25/solving-received-fatal-alert-handshake_failure-error-when-pe…找到了解决方案,只需将jdk.crypto.cryptoki添加到要使用jlink添加的模块列表中 […]