Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add multiple truststore paths to “java.net.ssl.trustStore”?

I want my Java Code to search for CA certificate of the server in one keystore... if it is unable to find the specific certificate (which I think will be known only when I try to connect via LDAP to Directory Server), it should look for the certificate in another keystore, whose path I know.

I tried this:

System.setProperty("javax.net.ssl.trustStore", System.getProperty("java.home") + "/lib/security/cacerts" + System.getProperty("path.separator") + path/to/second/keystore);

But it didn't seem to work.

Adding only one path (either of them) works, i.e. it runs like charm if certificate is found and fails if not.

So my question is:

  1. Is there a method to add multpile keystore paths to javax.net.ssl.trustStore?

  2. If it is not possible how should I write my code (I am asking for the algorithm) so that it just not throw Exception after first search itself and fail?

P.S. : I am not much familiar with Java.

Below is the relevant section of my code:

if(useSSL)
{
  try 
  {   
    SSLContext se = SSLContext.getInstance("TLS");
    Security.addProvider(se.getProvider());
  }   
  catch(NoSuchAlgorithmException e) { }

  System.setProperty("javax.net.ssl.trustStore", System.getProperty("java.home") + "/lib/security/cacerts");

  com.org.ldap.LDAPSocketFactory ssf = new LDAPJSSESecureSocketFactory();
  LDAPConnection.setSocketFactory(ssf);
}

try 
{   
  lc = new LDAPConnection();
  lc.connect( ldapServer, ldapPort);
  lc.bind( ldapVersion,  ldapUser, (userInfo[1]).getBytes() );
}
catch (LDAPException le)
{
  le.printStackTrace();
}
like image 659
Don't You Worry Child Avatar asked Feb 11 '14 08:02

Don't You Worry Child


People also ask

How does Keystores truststore work?

Keystore is used to store private key and identity certificates that a specific program should present to both parties (server or client) for verification. Truststore is used to store certificates from Certified Authorities (CA) that verify the certificate presented by the server in SSL connection.

How do I add a keystore to truststore?

To Create the Keystore and Trust Store Navigate to the directory that you created, and use the keytool program to create a certificate in a new keystore. Export the certificate to a file. The certificate is stored in the file that you specified. Import the certificate into a new trust store.


3 Answers

You can't have multiple paths for javax.net.ssl.trustStore.

The easiest would be to make a local copy of the JRE's cacerts and import the certificates from your other store into it (effectively merging them). (See keytool -importkeystore.)

Otherwise, if you know in advance that all your LDAP connections will use your second keystore (and you also want to be able to use the default truststore for other, non-related connections), you could configure that trust store for that SSLSocketFactory only. I'm not familiar with com.org.ldap.LDAPSocketFactory, but it might have an option to do so. (Otherwise, you could create your custom SSLContext initialised with your second truststore and get an SSLSocketFactory, as described in this answer).

Another, more complicated way, would be to create a custom X509TrustManager that wraps the default trust manager, catches its exceptions and tries again with another trust manager initialised using your second store. It's feasible, but you'd need to make sure it still throws the exception if neither trust managers accept your certificate (otherwise, there would be a security hole). If you're not familiar with the JSSE API (or Java altogether), it's probably not the best option.

In addition, be careful when you use System.setProperty("javax.net.ssl.trustStore", ...) in your code: it is what's read to initialise the default SSLContext, but the default SSLContext is only initialised once, the first time it's required. Setting this system property afterwards would have no effect (unless of course, other classes from other libraries also rely on this value).


It's also not clear what you're trying to achieve with this, since you'll always ever succeed to add a security provider that's already there:

  try 
  {   
    SSLContext se = SSLContext.getInstance("TLS");
    Security.addProvider(se.getProvider());
  }   
  catch(NoSuchAlgorithmException e) { }
like image 160
Bruno Avatar answered Oct 20 '22 16:10

Bruno


No, just import all the certificates from one truststore into the other, and use the second.

like image 22
user207421 Avatar answered Oct 20 '22 17:10

user207421


Although it is a bit late, I would like to make a remark on the answer which the others have provided. It was nearly impossible indeed and with a lot of custom code it would be possible actually, we have seen it within an answer of a similar question before: Using a custom truststore in java as well as the default one

After encountering the same challenge for multiple projects I thought it would be handy to create a library and also make it publicly available to contribute back to the community. Please have a look here: Github - SSLContext-Kickstart

The usage for your use case would be for loading the jdk truststore and your own truststore:

import nl.altindag.sslcontext.SSLFactory;

import javax.net.ssl.SSLContext;
import java.security.cert.X509Certificate;
import java.util.List;

public class App {

    public static void main(String[] args) {
        String trustStorePath = ...;
        char[] password = "password".toCharArray();


        SSLFactory sslFactory = SSLFactory.builder()
                .withDefaultTrustMaterial()
                .withTrustMaterial(trustStorePath, password)
                .build();

        SSLContext sslContext = sslFactory.getSslContext();
        List<X509Certificate> trustedCertificates = sslFactory.getTrustedCertificates();
    }

}
like image 23
Hakan54 Avatar answered Oct 20 '22 17:10

Hakan54