Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can my library with built in ssl certificate also allow use with default certs

I am distributing a library jar for internal clients, and the library includes a certificate which it uses to call a service that is also internal to our network.

The trust manager is set up as follows

    TrustManagerFactory trustManagerFactory = 
      TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore keystore = KeyStore.getInstance("JKS");
    InputStream keystoreStream = 
      clazz.getClassLoader().getResourceAsStream("certs.keystore"); // (on classpath)
    keystore.load(keystoreStream, "pa55w0rd".toCharArray());
    trustManagerFactory.init(keystore);
    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
    SSLContext context = SSLContext.getInstance("SSL");
    context.init(null, trustManagers, null);

    SSLSocketFactory socketFact = context.getSocketFactory();
    connection.setSSLSocketFactory(socketFact);

All of this works fine except in cases where users need other certificates or the default certificate.

I tried this Registering multiple keystores in JVM with no luck (I am having trouble generalizing it for my case)

How can I use my cert and still allow user libraries to use their own certs as well?

like image 974
Victor Grazi Avatar asked May 15 '18 21:05

Victor Grazi


People also ask

Which file is used for SSL by default?

By default, the Application Server stores its certificate information in two files in the domain-dir /config directory: Keystore file, keystore. jks, contains the Application Server's certificate, including its private key.


1 Answers

You are configuring a connection with a custom keystore acting as a truststore ( a certificate of your server that you trust). You are not overriding the default JVM behaviour, so the rest of the connection that other applications that include your library can make will not be affected.

Therefore you do not need a multiple keystore manager, in fact, your code works perfectly.

I've attached a full example below using a keystore google.jks which includes Google's root CA, and a connection using the default JVM truststore. This is the output

request("https://www.google.com/", "test/google.jks", "pa55w0rd"); //OK 
request("https://www.aragon.es/", "test/google.jks", "pa55w0rd");  // FAIL sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
request("https://www.aragon.es/", null, null); //OK

The problem is not in the code you have attached, so check the following in your code:

  • The truststore certs.keystore is really found in your classpath

  • Truststore settings are not set at JVM level using -Djavax.net.ssl.trustStore

  • The errors found (please include it in your question) are really related to the SSL connection


package test;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;


public class HTTPSCustomTruststore {

    public final static void main (String argv[]) throws Exception{
        request("https://www.google.com/", "test/google.jks", "pa55w0rd"); //Expected OK 
        request("https://www.aragon.es/","test/google.jks","pa55w0rd");  // Expected  FAIL
        request("https://www.aragon.es/",null,null); //using default truststore. OK 
    }

    public static void configureCustom(HttpsURLConnection connection, String truststore, String pwd)throws Exception{
        TrustManagerFactory trustManagerFactory = 
                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        KeyStore keystore = KeyStore.getInstance("JKS");
        InputStream keystoreStream = HTTPSCustomTruststore.class.getClassLoader().getResourceAsStream(truststore);
        keystore.load(keystoreStream, pwd.toCharArray());
        trustManagerFactory.init(keystore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        SSLContext context = SSLContext.getInstance("SSL");
        context.init(null, trustManagers,  new java.security.SecureRandom());

        SSLSocketFactory socketFact = context.getSocketFactory();
        connection.setSSLSocketFactory(socketFact);
    }


    public static void request(String urlS, String truststore, String pwd) {
        try {
            URL url = new URL(urlS);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            if (truststore != null) {
                configureCustom((HttpsURLConnection) conn, truststore, pwd);
            }   
            conn.connect();

            int statusCode = conn.getResponseCode();
            if (statusCode != 200) {
                System.out.println(urlS + " FAIL");
            } else {
                System.out.println(urlS + " OK");
            }
        } catch (Exception e) {
            System.out.println(urlS + " FAIL " + e.getMessage());
        }
    }
}
like image 143
pedrofb Avatar answered Oct 03 '22 02:10

pedrofb