Debugging yet another SSL/TLS error: the trustAnchors parameter must be non-empty

Debugging yet another SSL/TLS error: the trustAnchors parameter must be non-empty

So, as I am finally looking to document/share more I?ll start with this ?little? SSL error and nonetheless pain in the ass one that I had to troubleshoot a couple weeks ago with a customer.

Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

If you are lazy or in a hurry just go to the TLDR part in the end.

Actually there is a lot of information in the Web about this error and other SSL/TLS errors. My aim here is to explain how you can debug TLS connections at a lower level to see what is happening.

I work at Datasystems btw, an IT solutions company based in Paraguay, as a tech consultant.

So, this error appears in a Java environment. In my (customer) case, there was a service trying to communicate to another one. As the services are behind load balancers with HTTPS, the clients, in this case JBoss EAP needs to trust the endpoint that is connecting to. The client needs to have in its Truststore the CA Root certificate that signed the Certificate or the Intermediate Certificate that the client is connecting to.

A common practice, for intra company connections, is using certificates signed by local CA Roots. So the client then uses a Truststore that includes the CA Root certificate of the company and therefore can trust and connect to endpoints that uses certificates signed by the CA Root.

And when does this trustAnchors parameter must be non-empty appears? It does when the Java cannot read for whatever reason the Truststore that was specified for it [1]. Take into account that if no Truststore was specified then it will default to the one in the JRE security dir.

But, how can I certify if and what Truststore is my Java process using? That is the correct questions. There is a way to debug SSL connections by adding this property javax.net.debug [2][3] to the Java Process with the values listed in [2] or simply with All. Just take into account that it will print a lot.

Let me show you how with an example. I wanna verify that I am using a specific Truststore who has the correct CA Root certificate of where I want to connect. I will use a Java client that my coworker Hctor Alfonso helped me built [4].

First I remove the cacerts Truststore file:

Image for post

Then I test a simple web server with a cert that was issued by a local CA Root.

java -jar test_get_https-0.0.1-SNAPSHOT-jar-with-dependencies.jar https://www.calca.com.py

As the Java cannot find/open the TrustStore file it gives the error:

Image for postImage for post

So, to see at a more low level what is happening in the TLS/SSL exchange, I will add the javax.net.debug property:

# java -Djavax.net.debug=all -jar test_get_https-0.0.1-SNAPSHOT-jar-with-dependencies.jar https://www.calca.com.py 2>&1| grep -i truststore | grep -e ?Inaccessible trust store? -e ?No available key store? -e ?Reloaded?

Image for post

I can even specify a specific Truststore with the javax.net.ssl.trustStore property:

# java -Djavax.net.debug=all -Djavax.net.ssl.trustStore=/Another/path/to/cacerts -jar test_get_https-0.0.1-SNAPSHOT-jar-with-dependencies.jar https://www.calca.com.py 2>&1| grep -i truststore | grep -e ?Inaccessible trust store? -e ?No available key store? -e ?Reloaded?

Image for post

So, I will rename correctly again the Truststore and test again:

Image for post

# java -Djavax.net.debug=all -jar test_get_https-0.0.1-SNAPSHOT-jar-with-dependencies.jar https://www.calca.com.py 2>&1| grep -i truststore

Image for post

And it works:

# java -jar test_get_https-0.0.1-SNAPSHOT-jar-with-dependencies.jar https://www.calca.com.py

Image for post

FTR, for anyone (as me) who wants to know where is pointing the symbolic link of the cacerts of the JVM:

Image for post

The TL;DR then:

The error trustAnchors parameter must be non-empty means the Java cannot find or read the client Truststore [1]. Use the properties javax.net.debug=all and javax.net.ssl.trustStore=/path/to/Truststore to debug the issue.

[1] https://stackoverflow.com/a/6788682

[2] https://docs.oracle.com/javase/8/docs/technotessecurity/JSSERefGuide.html#Debug

[3] https://access.redhat.com/solutions/973783

[4] https://github.com/gcalcaterra/http_client

16