Java SSL debugging

  • SSL: ValidatorException

Exception Message: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

This is possibly because the server uses a certificate that is little known to java, which means when java try to verify the SSL, it realize it is not trustable.
Another explanation: It is because incomplete trust path for the server certificate; the server’s certificate is probably not trusted by the client.

Solution
Commonly, the fix is to import the server’s certificate authority (CA) into the client’s trust store (add the root CA, not server CA, to your cacerts file).

Here are the step:

  1. Identify the root CA using SSL Checker.
  2. Find out the root cert. from server side.
  3. Create the .pem file. e.g., DSTRootCAX3.pem
  4. Update the cacerts file of your java. Normally, it is located in (Mac) /Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/security or
    (Linux) /home/omega/java/jre/lib/security
  • SSL: HandshakeException

After the CA import, it man still have error like handshake_failure.

Read the detailed log by using -Djavax.net.debug=all

Exception Message:

Cipher Suites: […Long list of ciphers…]
Compression Methods: { 0 }
Extension elliptic_curves, curve names: {…}
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: HOST]
***
main, WRITE: TLSv1 Handshake, length = 168
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException:
Received fatal alert: handshake_failure

One possible reason is the JRE Library lacks of supported algorithm. (The server side is using some high security encryption algorithms) .

Solution
This problem can be solved by updating the JRE Library with adding stronger algorithms: JCE Unlimited Strength.

In a high security environment, one way of strengthening algorithms in the JDK is through the JCE Unlimited Strength policy files. In this particular case, replacing those policy files allows it to use the stronger variants of existing algorithms and connect successfully.

JCE Unlimited Strength downloads: JDK 8, JDK 7, or JDK 6.

Installation: unzip the dowload file and copy local_policy.jar and US-export_policy.jar to <JAVA_HOME>/lib/security

NOTES:

  1. Some cases might be related to TLS protocols, e.g., JDK 8 using TLSv1.2 by default, while JDK 7 has TLSv1 by default. To make the TLS protocols being compliant with each other, try debugging in java with command -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2.

  2. Someone mentioned that using http: instead of https:. It certainly works without errors, but that is not the reasonable solution.

  3. Some cases may refer to server name indication (SNI). If the server requires SNI, trying to setup a connection without SNI will fail. All modern browsers support SNI, but not all SSL stacks in programming languages support SNI or use it by default.
    To avoid SNI: -Djsse.enableSNIExtension=false,
    To check SNI with a server,

    # without SNI
    $ openssl s_client -connect www.google.com:443
    CONNECTED(00000003)
    140612985652896:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:770:
    ....
    New, (NONE), Cipher is (NONE)

Ref. links:
Debugging SSL/TLS Connections from docs.Oracle
Diagnosing TLS, SSL, and HTTPS from blog.Oracle
Received fatal alert: handshake_failure through SSLHandshakeException from stackOverfLow
SSL handshake alert: unrecognized_name error from stackOverflow