10

In my java application I need to send POST requests to a server sitting behind https. On the machine where my java application is running there is a java trust store in: /usr/local/comp.jks that contains the certificate for the server I need to interact with (its already imported).

The problem is that I cannot control how the JVM is started that will run my java application - e.g. by adding:

-Djavax.net.ssl.trustStore=/usr/local/comp.jks to the VM arguments.

Is it possible to load the trust store in the above path at runtime from my application after the JVM has started so I can authenticate against the https site?

I have only found guides on how to import certificates at runtime but that I cannot use - also since I don't have the password for /usr/local/comp.jks

Below my current implementation (in groovy):

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.security.KeyManagementException; import java.security.KeyStore import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException import java.security.cert.X509Certificate import java.util.Base64; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class HttpsClientImpl extends AbstractHttpClient { private String username = null; private String password = null; public HttpsClientImpl (String username, String password) { this.username=username; this.password=password; } @Override public String sendRequest(String request, String method) { System.setProperty( "javax.net.ssl.trustStore", "/usr/local/comp.jks" ); URL url = new URL(request); HttpsURLConnection con = (HttpsURLConnection) url.openConnection() // Set auth byte[] name = (username + ":" + password).getBytes(); String authStr = Base64.getEncoder().encodeToString(name); con.setRequestProperty("Authorization", "Basic " + authStr) con.setRequestMethod(method); writeResult(con); return con.getResponseCode(); } private void writeResult(HttpsURLConnection con) throws IOException { if(con!=null){ BufferedReader br = null; if (200 <= con.getResponseCode() && con.getResponseCode() <= 299) { br = new BufferedReader(new InputStreamReader(con.getInputStream())); } else { br = new BufferedReader(new InputStreamReader(con.getErrorStream())); } try { String input; while ((input = br.readLine()) != null){ System.out.println(input); } br.close(); } catch (IOException e) { e.printStackTrace(); } } } } 

When I run that I get:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382) Caused: sun.security.validator.ValidatorException: PKIX path building failed 
2

2 Answers 2

8

Assuming you haven't instantiated any SSL connections yet, you can simply call

System.setProperty( "javax.net.ssl.trustStore", "/usr/local/comp.jks" ); 

You'll probably also need to set javax.net.ssl.trustStorePassword and maybe javax.net.ssl.trustStoreType.

If the default SSL infrastructure has alredy been instantiated, you'll probably have to create your own SSLContext and SSLSocketFactory using your keystore.

Sign up to request clarification or add additional context in comments.

8 Comments

As I wrote in my post I don't have the password for the trust store. So is it only possible to do this if I have the password?
@u123 The site sends you its cert. Get the cert from the site itself: superuser.com/a/641396/441365 Then convert the *.pem file into your own Java keystore: stackoverflow.com/a/13992135/4756299
Ok so there is no way of using the existing trust store: /usr/local/comp.jks that already contains the correct certificates?
@u123 Ok so there is no way of using the existing trust store: ... Not if you don't have the password.
I don't believe you need a trust store password to use it. Trust information is public.
|
4

You can load the truststore in you class. What I would suggest is to use both your truststore and load the JDK truststore and use both. Here I am giving and example regarding how you can do it.

public class TrustManagerComposite implements X509TrustManager { private final List<X509TrustManager> compositeTrustmanager; public TrustManagerComposite() { List<X509TrustManager> trustManagers = new ArrayList<>(); try (InputStream truststoreInput = PATH_TO_YOUR_TRUSTSTORE) { trustManagers.add(getCustomTrustmanager(truststoreInput)); trustManagers.add(getDefaultTrustmanager()); } catch (Exception e) { //log it } compositeTrustmanager = trustManagers; } private static X509TrustManager getCustomTrustmanager(InputStream trustStream) throws Exception { return createTrustManager(trustStream); } private static X509TrustManager getDefaultTrustmanager() throws Exception { return createTrustManager(null); } private static X509TrustManager createTrustManager(InputStream trustStream) throws Exception { // Now get trustStore KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); // load the stream to your store trustStore.load(trustStream, null); // initialize a trust manager factory with the trusted store TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustFactory.init(trustStore); // get the trust managers from the factory TrustManager[] trustManagers = trustFactory.getTrustManagers(); for (TrustManager trustManager : trustManagers) { if (trustManager instanceof X509TrustManager) { return (X509TrustManager) trustManager; } } return null; } @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { for (X509TrustManager trustManager : compositeTrustmanager) { try { trustManager.checkClientTrusted(chain, authType); return; } catch (CertificateException e) { // maybe the next trust manager will trust it, don't break the loop } } throw new CertificateException("None of the TrustManagers trust this certificate chain"); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { for (X509TrustManager trustManager : compositeTrustmanager) { try { trustManager.checkServerTrusted(chain, authType); return; } catch (CertificateException e) { // maybe the next trust manager will trust it, don't break the loop } } throw new CertificateException("None of the TrustManagers trust this certificate chain"); } @Override public X509Certificate[] getAcceptedIssuers() { List<X509Certificate> certs = new ArrayList<>(); for (X509TrustManager trustManager : compositeTrustmanager) { for (X509Certificate cert : trustManager.getAcceptedIssuers()) { certs.add(cert); } } return certs.toArray(new X509Certificate[0]); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.