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). (Seekeytool -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 withcom.org.ldap.LDAPSocketFactory
, but it might have an option to do so. (Otherwise, you could create your customSSLContext
initialised with your second truststore and get anSSLSocketFactory
, 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 defaultSSLContext
, but the defaultSSLContext
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:
No, just import all the certificates from one truststore into the other, and use the second.