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();
}
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.
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.
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.
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With