Search code examples
sslssl-certificaterheltomcat9jks

Invalid Certificate (HTTPS) while deploy in apache tomcat but work perfectly in Intelij (local)


I have application that using https to send data, to doing that , i implement https certificate that i grab from destination website. certificate destination website

i take 2 certificate (GeoTrust & Digicert) from website and save it to jks file using keystore explorer look like jks file

and upload it server to specific directory

In java application, i add some code to read jks file in specific path and implement certificate from application

import javax.net.ssl.HttpsURLConnection;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SSLUtils {


    @Value("${ssl.keyStore.file}")
    private String sslKeyStoreFile;

    @Value("${ssl.keyStore.pass}")
    private String sslKeyStorePass;

    @Value("${ssl.trustStore.file}")
    private String sslTrustStoreFile;

    @Value("${ssl.trustStore.pass}")
    private String sslTrustStorePass;

    @Value("${ssl.host}")
    private String sslHost;


    /**
     * Setting configuration for SSL certificate
     *
     */

    @Bean
    public void setKeySSL(){
        HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equals(sslHost));
        System.setProperty("javax.net.ssl.trustStore", sslTrustStoreFile);
        System.setProperty("javax.net.ssl.trustStorePassword", sslTrustStorePass);
        System.setProperty("javax.net.ssl.keyStore", sslKeyStoreFile);
        System.setProperty("javax.net.ssl.keyStorePassword", sslKeyStorePass);
    }

}

Properties for ssl

#ssl client config
ssl.keyStore.file=/opt/ssl/keystore.jks
ssl.keyStore.pass=admin
ssl.trustStore.file=/opt/ssl/keystore.jks
ssl.trustStore.pass=admin
ssl.host=https://devapi.***********.co.id

After deploy to apache tomcat 9.0.37 , i got error "PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target".

But when i run application locally with intelijj, the application running well and got response from destination , same result while run application in war file form with command java -jar which mean code for implement ssl running well too.

I am pretty sure , there is no problem with path of ssl file. I assume cause of this problem is jks file cannot read in tomcat , not invalid certification (because in local , i using same certification and its valid)

The Question is : How that can be happen ?

FYI : i also have another microservices that using same code to implement ssl and its working fine in same apache tomcat.

Some solution that i already done and its not working :

  1. Running apache tomcat in root mode same as owner of directory and file at ssl file (opt/ssl/)
  2. import certificate to jvm certificate
  3. import certificate to jvm certificate and in code read cacerts file in /usr/java/jdk1.8.0_261/jre/lib/security/cacerts

Solution

  • Finally, after a week struggling with this issue, i solve this problem. The problem is keystore server (destination server) contain just server certificate without root CA certificate and intermediate certificate. Thats why while handshake process made, its make failure connection. Because while connection made, server send all certificate (chain certifcate).

    Please watch this lectures about SSL process made : SSL and HTTPS Lecture

    Step to solve :

    1. In Client server, get certificate from server

    https://github.com/escline/InstallCert

    To do that, use InstallCert.java and run

    java -Djavax.net.debug=ssl:handshake InstallCert host:port

    Note : if all chain-certificate not complete (without CA certificate and intermediate) , please contact administrator server to add all certificate in server keystore.

    1. In Client server, Check connection with trustore that just made with InstallCert.java

    https://github.com/gebi/sslpoke

    To do that, use SSLPoke.java and run

    java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=jssecacerts SSLPoke host port

    Note : If connection success, that trustore ready to use.

    If it not solve your problem, you can debug your tomcat by add command in startup.sh

    https://medium.com/@anuruddha.thennakoon/enable-ssl-debug-logs-in-tomcat-f9d7e0d1fd67