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:
Is there a method to add multpile keystore paths to javax.net.ssl.trustStore?
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();
}
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) { }
No, just import all the certificates from one truststore into the other, and use the second.