how to check SSL certificate expiration date programmatically in Java - java

I need to extract expiration date from SSL certificate on web site in Java,should support both
trusted and self-signed certificate,such as:
1.trusted
https://github.com
2.self-signed
https://mms.nw.ru/
I already copy some code as:
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLTest {
public static void main(String [] args) throws Exception {
// configure the SSLContext with a TrustManager
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
SSLContext.setDefault(ctx);
URL url = new URL("https://github.com");//https://mms.nw.ru
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
System.out.println(conn.getResponseCode());
Certificate[] certs = conn.getServerCertificates();
for (Certificate cert :certs){
System.out.println(cert.getType());
System.out.println(cert);
}
conn.disconnect();
}
private static class DefaultTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
}
The questions are:
How to parse the expiration date from the certificate, in my code the toString() did output the date,but it is hard to parse.
How to determine the certificate chain, eg, the github certificate with chains 3, how did i know which certificate to get the expiration date from?

How to parse the expiration date from the certificate
Cast it to an X509Certificate and call getNotAfter().
How to determine the certificate chain, eg, the github certificate with chains
You've got it. That's what the Certificate[] array is, as it says in the Javadoc.
How did i know which certificate to get the expiration date from?
Read the Javadoc. "The peer's own certificate first followed by any certificate authorities".
However I don't know why you're doing any of this. Java should already do it all for you.
And please throw away that insecure and incorrect TrustManager implementation. The correct way to handle self-signed certificates is to import them into the client truststore. Please also throw away your insecure HostnameVerifier, and use the default one, or a secure one. Why use HTTPS at all if you don't want it to be secure?

Make sure you append Begin/End lines to PEM format otherwise java does not understand it.
public class CertTest {
public static final String cert = "-----BEGIN CERTIFICATE-----\n<CERT_DATA>\n-----END CERTIFICATE-----";
public static void main(String[] args){
try {
X509Certificate myCert = (X509Certificate)CertificateFactory
.getInstance("X509")
.generateCertificate(
// string encoded with default charset
new ByteArrayInputStream(cert.getBytes())
);
System.out.println(myCert.getNotAfter());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

In Kotlin way, it should look something like this:
fun certInformation(aURL: String) {
val destinationURL = URL(aURL)
val conn = destinationURL.openConnection() as HttpsURLConnection
conn.connect()
val certs = conn.serverCertificates
for (cert in certs) {
println("Certificate is: $cert")
if (cert is X509Certificate) {
println(cert.issuerDN.name)
println(cert.notAfter)
println(cert.notBefore)
}
}
}

Related

Is it possible to disable SSL certificate verification in Apache Kafka Java client?

If I have a self-signed certificate, as a good citizen, I will import it to my keystore and configure Kafka client with "ssl.truststore.location" and "ssl.truststore.type" in order to use it.
If expect that a Common Name from certificate's subject can differ from the host's address that presented it, I can turn off the endpoint validation with "ssl.endpoint.identification.algorithm".
What if I wanted to skip the SSL validation altogether, not just for the hostname, so that I no longer need to copy the certificates around? Analogous to the "-k" or "--insecure" setting in curl. Can I do it with a default Java client for Kafka?
There is one way to accomplish it however it's not so straightforward.
The idea is to implement the interface org.apache.kafka.common.security.auth.SslEngineFactory that will ignore the certificate validation. When you use it as a client it should be enough to implement just the createClientSslEngine method in a way similar to this:
import org.apache.kafka.common.security.auth.SslEngineFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;
public class InsecureSslEngineFactory implements SslEngineFactory {
private final TrustManager INSECURE_TRUST_MANAGER = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// empty
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// empty
}
};
#Override
public SSLEngine createClientSslEngine(String peerHost, int peerPort, String endpointIdentification) {
TrustManager[] trustManagers = new TrustManager[]{ INSECURE_TRUST_MANAGER };
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new SecureRandom());
SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort);
sslEngine.setUseClientMode(true);
return sslEngine;
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException(e);
}
}
#Override
public SSLEngine createServerSslEngine(String peerHost, int peerPort) {
return null;
}
#Override
public boolean shouldBeRebuilt(Map<String, Object> nextConfigs) {
return false;
}
#Override
public Set<String> reconfigurableConfigs() {
return null;
}
#Override
public KeyStore keystore() {
return null;
}
#Override
public KeyStore truststore() {
return null;
}
#Override
public void close() {
}
#Override
public void configure(Map<String, ?> configs) {
}
}
After having this class finished you just configure it as a SSL_ENGINE_FACTORY_CLASS in kafka (producer or consumer) properties:
props.put(SslConfigs.SSL_ENGINE_FACTORY_CLASS, InsecureSslEngineFactory.class);
or if you don't want to use the constant:
props.put("ssl.engine.factory.class", InsecureSslEngineFactory.class);
Make sure you don't use this setup in production!

Use of RestTemplate together with SSL

I use SSL security in my Spring Boot application. While calling the address
final UriComponents uriComponents
= uriComponentsBuilder.path("/api/v1.0/register/token/{token}").buildAndExpand(token);
ResponseEntity<Boolean> response;
try {
response = restTemplate
.exchange(uriComponents.toUri(),
HttpMethod.PUT,
entity,
Boolean.class);
throw away me https://pastebin.com/A4Vb69hT carefully
I/O error on PUT request for "https://localhost:8443/api/v1.0/register/token/PBe3AzJ245W0sNyeg": java.security.cert.CertificateException: No name matching localhost found; nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
I found on the Internet on the website http://java.globinch.com/enterprise-java/security/fix-java-security-certificate-exception-no-matching-localhost-found/
static {
//for localhost testing only
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
(hostname, sslSession) -> hostname.equals("localhost"));
}
after adding it, it receives further errors https://pastebin.com/kJZCqJ6K carefully
I/O error on PUT request for "https://localhost:8443/api/v1.0/register/token/EMNy7W9jJgsMWEn0z6hFOIHoB96zzSaeHWUs": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
What should I do now?
I have two SSL files https://github.com/JonkiPro/REST-Web-Services/tree/master/src/main/resources/keystore
This answer is some kind of hack to run locally though enabling in actual environment will still work with certificates.
Just call SSLContextHelper.disable() before restTemplate.exchange
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import javax.security.cert.X509Certificate;
import org.apache.log4j.Logger;
public class SSLContextHelper {
private static final String KEY_STORE_TYPE="JKS";
private static final String CLASS_NAME=SSLContextHelper.class.getName();
private static final String TRANSPORT_SECURITY_PROTOCOL="TLS";
private static final Logger logger=Logger.getLogger(SSLContextHelper.class);
public static void enable(){
String keystoreType = "JKS";
InputStream keystoreLocation = null;
char [] keystorePassword = null;
char [] keyPassword = null;
try {
KeyStore keystore = KeyStore.getInstance(keystoreType);
keystore.load(keystoreLocation, keystorePassword);
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keystore, keyPassword);
InputStream truststoreLocation = null;
char [] truststorePassword = null;
String truststoreType = KEY_STORE_TYPE;
KeyStore truststore = KeyStore.getInstance(truststoreType);
truststore.load(truststoreLocation, truststorePassword);
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyManager [] keymanagers = kmfactory.getKeyManagers();
TrustManager [] trustmanagers = tmfactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance(TRANSPORT_SECURITY_PROTOCOL);
sslContext.init(keymanagers, trustmanagers, new SecureRandom());
SSLContext.setDefault(sslContext);
} catch (Exception e) {
logger.error(CLASS_NAME+"Exception in SSL "+e.getMessage());
e.printStackTrace();
}
}
public static void disable() {
try {
SSLContext sslc = SSLContext.getInstance("TLS");
TrustManager[] trustManagerArray = { (TrustManager) new NullX509TrustManager() };
sslc.init(null, trustManagerArray, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostnameVerifier());
} catch(Exception e) {
e.printStackTrace();
}
}
private static class NullX509TrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
System.out.println();
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
System.out.println();
}
}
private static class NullHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
The certificate of server is not a valid certificate chain or is probably self signed. Add the certificate to your trust store as trusted certificate ( do it only if you know it's a testing local certificate) and then try.
For details you can see https://eclipse-ee4j.github.io/mail/InstallCert
Certificate does not match the hostname, in this case localhost. please check that your self-signed certificate is using the right CN and if not recreate it.
Good article how to fix error :
http://java.globinch.com/enterprise-java/security/fix-java-security-certificate-exception-no-matching-localhost-found/

KeyStore.load(InputStream stream, char[] password); How do I know the password on the client side?

I know that to load a certificate to use, I need to call KeyStore.load(InputStream, char[]);. How could I load the certificate on the client side if I need the password? I don't need this when connecting to Google, but I want to use Trust Managers to validate Google certificates. I also cannot make a SSLServerSocket and connect to it without loading a certificate.
EDIT: Added code:
package testing;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLClientTest {
public static void main(String[] args) {
int port = 443;
String host = "google.com";
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
KeyStore ks = KeyStore.getInstance("JKS");
InputStream ksIs = new FileInputStream("securecert.certificate");
try {
ks.load(ksIs, "pwdpwdpwd".toCharArray());
} finally {
if (ksIs != null) {
ksIs.close();
}
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "pwdpwdpwd".toCharArray());
sc.init(kmf.getKeyManagers(),
new TrustManager[] { new MyTrustManager() }, null);
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.startHandshake();
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
System.out.println(in.readLine());
in.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static final class MyTrustManager implements X509TrustManager {
#Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
}
Note that I have to load the certificate, securecert.certificate, at the like of code ks.load(InputStream, char[]); I of course know the password, but what if I don't? Then how could I validate the certificate with a trust manager? This code simply locks. Please answer. Thanks!
Seems that you need a client authentication through SSL and you want let the user enter the password for his keystore. Based on your explanation I suppose that each installed client has its own keystore from a local path (If not the question has nonsense because if the keystore is always the same you don't need to pass a different password each time... however if this is the case you've to check if this client it's secure).
So to let the user enter a password you can instantiate the keystore in a different way instead of using KeyStore.getInstance(InputStream, Char[]), you can use KeyStore.Builder.newInstance and KeyStore.CallbackHandlerProtection methods, and you have to create a class which implements javax.security.auth.callback.CallbackHandler, this class have to override handle() method for example using swing or awt panel to let the user introduce the password. Below I show you some sample code to guide you through this steps:
Load the keystore
import java.io.File;
import java.security.KeyStore;
import java.security.Provider;
import java.util.Enumeration;
public class KeyStoreCallbackSample {
public static void main(String args[]) throws Exception {
// instantiate a keystore to get the provider for specific type
KeyStore ks = KeyStore.getInstance("JKS");
// create the callback handler to get the password
KeyStore.CallbackHandlerProtection cbhp = new KeyStore.CallbackHandlerProtection(new YourImplementationCallbackHander());
// create the builder passing keystoreType, provider, keystore file, and callbackhandler
KeyStore.Builder builder = KeyStore.Builder.newInstance("JKS", ks.getProvider(), new File("/path/YourKeyStore.jks"), cbhp);
// create the keystore
ks = builder.getKeyStore();
// print the keystores alias to check if all it's load correctly
Enumeration<String> aliases = ks.aliases();
while(aliases.hasMoreElements()){
System.out.println(aliases.nextElement());
}
}
}
CallbackHandler implementation
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
/**
* PIN handler for keystores
*/
public class PinInputHandler implements CallbackHandler {
private char[] lastPassword;
public PinInputHandler(){}
// implement this method to handle the callback
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback cb : callbacks) {
if (cb instanceof javax.security.auth.callback.PasswordCallback) {
javax.security.auth.callback.PasswordCallback pcb = (javax.security.auth.callback.PasswordCallback) cb;
try {
this.lastPassword = // HERE YOUR SWING OR AWT OR ANOTHER WAY TO GET THE PASSWORD FROM THE CLIENT
} catch (Exception e) {}
pcb.setPassword(this.lastPassword);
}
}
}
}
If you need more info you can check at KeyStore, KeyStore.Builder, KeyStore.CallbackHandlerProtection and CallbackHandlerdocumentation.
Hope this helps,

How to make stealth ssl handshake in Java

I need to make an ssl handshake in a program in order to get some information about the remote server like the public key and cipher suits. I am aware of something called stealth handshake which does not complete the handshake but get the needed information like what I have mentioned. Can any body give explanation on how to do this in Java. I tried to search but not able to find exact concrete method.
Stealth? Never heard of this.
You could register a javax.net.ssl.HandShakeCompletedListener to your ssl client socket to get the certificate etc. but after the handshake has been completed
javax.net.ssl.HandShakeCompletedListener is an interface implemented
by any class which wants to receive notification of the completion of
an SSL protocol handshake on a given SSLSocket connection.
And you can also process handshaking data via SSLEngine.
Study JSSE Ref guide
Stelath mode not sure about this but I used to do some thing like below to retrieve the certificate chains from the server
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class GetCertificates {
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, IOException{
String host="google.com";
int port = 443;
SSLContext ssl = SSLContext.getInstance("TLS");
ssl.init(null, new TrustManager[]{new SimpleX509TrustManager()}, null);
SSLSocketFactory factory = ssl.getSocketFactory();
SSLSocket socket = (SSLSocket) factory.createSocket(host,port);
SSLSession session = socket.getSession();
javax.security.cert.X509Certificate[] certs = session.getPeerCertificateChain();
System.out.println(certs[certs.length-1].getSubjectDN());
// you can display certificates info here and also cipher suites
session.getCipherSuite();
session.invalidate();
}
}
class SimpleX509TrustManager implements X509TrustManager {
public void checkClientTrusted(
X509Certificate[] cert, String a)
throws CertificateException {
}
public void checkServerTrusted(
X509Certificate[] cert, String a)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}

could not work ssl connection properly when keystore file changed dynamically through web application

am trying to change the truststore path dynamically using java web application.
am developing struts application and login is based on ldap through secure socket layer (ssl) connection.
To connect with ssl i have created .cer file using java keytool option.
Now i able to connect with ldap and i can retieve user information from ldap.
when i change the ssl certificate(invalid certificate for testing) dynamically it could not give any exceptions. but it works when i restart the tomcat
server.
following is the code that i am trying
try{
java.io.InputStream in = new java.io.FileInputStream("C:\\test.cer");
java.security.cert.Certificate c = java.security.cert.CertificateFactory.getInstance("X.509").generateCertificate(in);
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
ks.load(null);
if (!ks.containsAlias("alias ldap")) {
ks.setCertificateEntry("alias ldap", c);
}
java.io.OutputStream out = new java.io.FileOutputStream("C:\\ldap.jks");
char[] kspass = "changeit".toCharArray();
ks.store(out, kspass);
out.close();
System.setProperty("javax.net.ssl.trustStore", "C:\\ldap.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
}catch(Exception e){
e.printStackTrace();
}
is there any mistake that i made with the code?
does any new code that i need to put to connect dynamically?
Note :
instead of c:\ldap.jks file i gave invalid file dynamically. it does not give any exception.
Edited (checked with custom TrustManager) :
i also implemented TrustManager and ssl context is initialized with custom trust manager.
but i am not able to get the expected behaviour
could u please help me. the code that i tried is
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.UUID;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class TestDynamicSSLCert {
public static void main(String[] args)throws NamingException,IOException {
DataInputStream din = new DataInputStream (System.in);
String yes = "yes";
String certpath = "C:\\cert.cer";
String ldappath1 = "C:\\ldap.jks";
String ldappath2 = "C:\\ldap.jks"; // setting valid key store path
while("yes".equalsIgnoreCase(yes.trim())){
System.out.println(" ldappath2 : "+ldappath2);
Hashtable env = new Hashtable();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL,"uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://172.16.12.4:636/ou=system");
try {
java.io.InputStream in = new java.io.FileInputStream(certpath);
java.security.cert.Certificate c = java.security.cert.CertificateFactory.getInstance("X.509").generateCertificate(in);
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
ks.load(null);
if (!ks.containsAlias("alias ldap")) {
ks.setCertificateEntry("alias ldap", c);
}
java.io.OutputStream out = new java.io.FileOutputStream(ldappath1);
char[] kspass = "changeit".toCharArray();
ks.store(out, kspass);
out.close();
System.setProperty("javax.net.ssl.trustStore", ldappath2);
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
// Custorm trust manager
MyX509TrustManager reload = new MyX509TrustManager(ldappath2,c);
TrustManager[] tms = new TrustManager[] { reload };
javax.net.ssl.SSLContext sslCtx = javax.net.ssl.SSLContext.getInstance("SSL");
sslCtx.init(null, tms, null);
// Custom trust manager
} catch (Exception e) {
e.printStackTrace();
}
DirContext ctx = new InitialDirContext(env);
NamingEnumeration enm = ctx.list("");
while (enm.hasMore()) {
System.out.println(enm.next());
}
ctx.close();
System.out.println(" Go again by yes/no :");
yes = din.readLine();
ldappath2 = "C:\\invalidldap.jks"; // setting invalid keystore path
}
}
}
class MyX509TrustManager implements X509TrustManager {
private final String trustStorePath;
private X509TrustManager trustManager;
private List<Certificate> tempCertList = new ArrayList<Certificate>();
public MyX509TrustManager(String tspath,Certificate cert)throws Exception{
this.trustStorePath = tspath;
tempCertList.add(cert);
reloadTrustManager();
}
public MyX509TrustManager(String tspath)
throws Exception {
this.trustStorePath = tspath;
reloadTrustManager();
}
#Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
trustManager.checkClientTrusted(chain, authType);
}
#Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
try {
trustManager.checkServerTrusted(chain, authType);
} catch (CertificateException cx) {
addServerCertAndReload(chain[0], true);
trustManager.checkServerTrusted(chain, authType);
}
}
#Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] issuers = trustManager.getAcceptedIssuers();
return issuers;
}
private void reloadTrustManager() throws Exception {
// load keystore from specified cert store (or default)
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = new FileInputStream(trustStorePath);
try {
ts.load(in, null);
} finally {
in.close();
}
// add all temporary certs to KeyStore (ts)
for (Certificate cert : tempCertList) {
ts.setCertificateEntry(UUID.randomUUID().toString(), cert);
}
// initialize a new TMF with the ts we just loaded
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
// acquire X509 trust manager from factory
TrustManager tms[] = tmf.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
trustManager = (X509TrustManager) tms[i];
return;
}
}
throw new NoSuchAlgorithmException("No X509TrustManager in TrustManagerFactory");
}
private void addServerCertAndReload(Certificate cert,
boolean permanent) {
try {
if (permanent) {
// import the cert into file trust store
// Google "java keytool source" or just ...
Runtime.getRuntime().exec("keytool -importcert ...");
} else {
tempCertList.add(cert);
}
reloadTrustManager();
} catch (Exception ex) { /* ... */ }
}
}
Expected Behaviour :
ldap connection should be successfull with valid keystore file (during first loop ).
if user give yes then invalid keystore is assigned and need to produce exception and should not connect to ldap
Actual Behaviour:
for both valid keystore file i able to retrieve information from ldap.
Note :
if i set String ldappath2 = "C:\invalidldap.jks"; at begining, it gives exception.
Why am doing this ?
#EJP, because, i need to develope module which is based on ldap authentication securely. module should support multiple ldap servers. ldap settings can be inserted from the UI (webpage that has the ui to get the details like ldaphost, port, basedn, and ssl certificate) and this details should go to database. at the same time certificate also present in database. work for module is just retrieve the users from ldap and store it to another table. so if we change the new ldap server setting with new certificate means, System.setProperty("javax.net.ssl.trustStore","truststorepath") will fail. are you okay with my explanation?
You are correct. You have to restart Tomcat when you change the keystore or truststore. You don't need to write code to load client certificates, you just need to make sure you are dealing with servers whose certificates are signed by a CA that you trust. Adding new certificates at runtime is radically insecure.
Is there any other way to connect ldap securely with out using above
steps?
Yes, but why do you think you need to know?
Does the application (tomcat or single java file) should be restarted
whenever trustStore property is updated ?
Yes.

Categories