11

My Java program sends requests by java.net.http.HttpClient (Java 11).

It works when I am running it in Eclipse on OpenJDK 11's JRE.

On custom jlinked JRE, I get an error:

java.io.IOException: Received fatal alert: handshake_failure

I suppose the problem is with my custom JRE.

Timisorean
  • 1,388
  • 7
  • 20
  • 30
janzdanowski
  • 111
  • 1
  • 4
  • Without information on the JRE that you're using - e.g. version, we have no way of helping you. If you can set some jre flags, then [this blog post](https://blogs.oracle.com/java-platform-group/diagnosing-tls,-ssl,-and-https) has some tips for diagnosing the problem. – Anya Shenanigans Feb 19 '19 at 17:08
  • This is jlinked JRE created with OpenJDK 11.0.1. I think my JRE has missing something, but i do not know what. – janzdanowski Feb 20 '19 at 09:02
  • I have updated OpenJDK to 11.0.2 version but after generate custom JRE there is the same error. My program sends requests to API with HTTPS and required TLS 1.1+. – janzdanowski Feb 20 '19 at 10:37

1 Answers1

21

TL;DR jlink without jdk.crypto.ec cannot talk to a server that has an elliptic curve certificate. You get a handshake_failure error when trying to talk to a server running with this.

When you build a deployable jre, if you do not include the jdk.crypto.ec module, then it will be unable to talk to servers that only have an elliptic curve certificate. I mocked up one using:

out_dom=localhost
subj="/C=IE/CN=localhost"
openssl ecparam -name secp384r1 -genkey \
    -out $out_dom.key
openssl req -new \
    -subj "$subj" \
    -key $out_dom.key \
    -out $out_dom.csr
openssl req -x509 -nodes \
    -days 365 \
    -key $out_dom.key \
    -in $out_dom.csr \
    -out $out_dom.crt

When I talk to this server with the standard JRE, I get the error about PKIX path building failed - i.e. the cert isn't in the cacerts file.

When I created a jlink jre using:

jlink --module-path . --add-modules java.base --output jlinked

and ran: jlinked/bin/java with a test TLS app, I got the error: Received fatal alert: handshake_failure, which is the same as the OP's problem.

When I added:

jlink --module-path . \
    --add-modules java.base \
    --add-modules jdk.crypto.ec \
    --output jlinked

and re-ran, I experienced the PKIX path building failed error, which indicates that it's working properly.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • Thanks for explanation of the problem. When I run my program on OpenJDK 11.0.2 JRE then everything is ok. So I have copied cacerts file from that to jlinked JRE, but I see the same error. – janzdanowski Feb 20 '19 at 14:49
  • Using the `-Djavax.net.debug=all`, make sure that you copied the correct `cacerts` to the jlinked JRE - the cacerts file being used is mentioned at the start of the debugging output. It is possible that the JRE being used by Eclipse isn't the system provided one, and so is using a different `cacerts` file. – Anya Shenanigans Feb 21 '19 at 15:02
  • OpenJDK 11.0.2 JRE (running from Eclipse) uses cacerts file from C:\Java\jdk-11.0.2\lib\security\cacerts. My JRE uses cacerts file from C:\[...]\jlinked-jre-name\lib\security\cacerts. Both JREs - `Reloaded 93 trust certs`. I have copied cacerts file from OpenJDK JRE to my JRE again but it nothing changed. – janzdanowski Feb 21 '19 at 17:23
  • From the run in the eclipse JRE, it should indicate the cert signer that was used that was considered trusted. You should check for the presence of that signer in the list of certs as reported loaded by the JRE in the second case. the API that's being talked to - I presume it's signed by a CA that's listed in the cacerts file. – Anya Shenanigans Feb 21 '19 at 17:38
  • I have compared two cacerts files (by diffchecker.com) and they are identical. After `-Djavax.net.debug=all` in jlinked JRE's console, in the bottom part, is: `javax.net.ssl|WARNING|0D|HttpClient-1-Worker-0|2019-02-21 20:42:55.003 CET|SignatureScheme.java:282|Signature algorithm, SHA256withECDSA, is not supported by the underlying providers`. The same warning is for `SHA384withECDSA`, `SHA512withECDSA`, `SHA224withECDSA`, `SHA1withECDSA`. After that there is a lot of white space (when in OpenJDK JRE's console in the same part is a block of such lines `07F0: 15 80 7F 01 FF 09 [...]`). – janzdanowski Feb 21 '19 at 20:08
  • Oh, then it sounds like you need to add the module `jdk.crypto.ec` to the list of modules to create with the jlink. – Anya Shenanigans Feb 21 '19 at 20:39
  • Adding `jdk.crypto.ec` to `--add-modules` cause `java.lang.IllegalAccessError` because org.json module doesn't export itself to my main class' module, but it isn't truth. So I have removed it from `--add-modules`. – janzdanowski Feb 22 '19 at 14:33
  • I have tested my program with jlinked JRE from Oracle JDK 11.0.2 - the same error. It looks like the problem is with missing modules in jlinked JRE. I have created that JRE by `jlink --module-path C:\Java\jdk-11.0.2\jmods;C:\Users\janek\my-app.jar;C:\Users\janek\json-20180813.jar --add-modules my.app --output C:\Users\janek\MyApp` and my app requires only `java.desktop`, `java.net.http` and `org.json` modules in module-info file. – janzdanowski Feb 22 '19 at 14:34
  • I've completely replaced my answer. The issue is that you're missing the `jdk.crypto.ec` module, which is necessary to talk to servers that only have elliptic curve based certificates. – Anya Shenanigans Feb 25 '19 at 11:28
  • Awesome thanks! I just added the class to the module-info and everything is sorted now. – Jp Silver Jul 12 '22 at 07:57