How to use custom truststore?

Hi, I've written a simple ssl client (basing on jakarta commons httpclient project) that connects to IIS with SSL and it works only i f I add ssl certificate from IIS to the jre cacerts (using keytool import). The cacerts are automatically readed somehow (don't know how)

I want to make the whole thing more elastic and be able to provide my client with a path to cacerts / truststore / keystore. Am I doing it OK? I Currently it works...

BUT the loops that print certificates and trustores to screen are empty - for example keystore.getCertificateChain(alias); always returns null....

But IIS cert is inside

C:\\Program Files\\Java\\jre1.5.0_09\\lib\\security\\cacertsbbb

PS. I would like to avoid setting System properties in my code like System.setTruststore etc.

PS. Should be without sockets. Just extension of what i got.

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.InetAddress;

import java.net.InetSocketAddress;

import java.net.MalformedURLException;

import java.net.Socket;

import java.net.SocketAddress;

import java.net.URL;

import java.net.UnknownHostException;

import java.security.GeneralSecurityException;

import java.security.KeyStore;

import java.security.KeyStoreException;

import java.security.NoSuchAlgorithmException;

import java.security.UnrecoverableKeyException;

import java.security.cert.Certificate;

import java.security.cert.CertificateException;

import java.security.cert.X509Certificate;

import java.util.Enumeration;

import javax.net.SocketFactory;

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.SSLSocketFactory;

import javax.net.ssl.TrustManager;

import javax.net.ssl.TrustManagerFactory;

import javax.net.ssl.X509TrustManager;

import org.apache.commons.httpclient.ConnectTimeoutException;

import org.apache.commons.httpclient.params.HttpConnectionParams;

import org.apache.log4j.Logger;

import junit.framework.TestCase;

publicclass SSLSocketClientextends TestCase{

private URL keystoreUrl =null;

private String mockKeystoreUrl ="C:\\Program Files\\Java\\jre1.5.0_09\\lib\\security\\cacertsbbb";

private String keystorePassword ="changeit";

private URL truststoreUrl =null;

private String mockTruststoreUrl ="C:\\Program Files\\Java\\jre1.5.0_09\\lib\\security\\cacertsbbb";

private String truststorePassword =null;

private SSLContext sslcontext =null;

//

publicvoid testSSLSocket(){

try{

SSLSocketClient client =new SSLSocketClient();

// client.createSocket("10.63.29.50", 443);

HttpConnectionParams params =new HttpConnectionParams();

InetAddress ia = InetAddress.getLocalHost();

// params.setParameter(arg0, arg1)

//client.createSocket("10.63.29.50", 443, ia, 444, params);

client.connect("10.63.29.50", 443,"/ssl2/index.html", params);

}catch (ConnectTimeoutException e){

// TODO Auto-generated catch block

e.printStackTrace();

}catch (UnknownHostException e){

// TODO Auto-generated catch block

e.printStackTrace();

}catch (IOException e){

// TODO Auto-generated catch block

e.printStackTrace();

}

}

privatestatic Logger log = Logger.getLogger(SSLSocketClient.class);

/*

* private static KeyStore createKeyStore(final URL url, final String

* password) throws KeyStoreException, NoSuchAlgorithmException,

* CertificateException, IOException { if (url == null) { throw new

* IllegalArgumentException("Keystore url may not be null"); }

*

* KeyStore keystore = KeyStore.getInstance("jks");

* keystore.load(url.openStream(), password != null ? password

* .toCharArray() : null); return keystore; }

*/

private KeyStore mockCreateKeyStore(final String url,final String password)

throws KeyStoreException, NoSuchAlgorithmException,

CertificateException, IOException{

if (url ==null){

thrownew IllegalArgumentException("Keystore url may not be null");

}

InputStream keystoreStream =new FileInputStream(url);

KeyStore keystore = KeyStore.getInstance("jks");

keystore.load(keystoreStream, password !=null ? password.toCharArray()

:null);

return keystore;

}

private KeyManager[] createKeyManagers(final KeyStore keystore,

final String password)throws KeyStoreException,

NoSuchAlgorithmException, UnrecoverableKeyException{

if (keystore ==null){

thrownew IllegalArgumentException("Keystore may not be null");

}

KeyManagerFactory kmfactory = KeyManagerFactory

.getInstance(KeyManagerFactory.getDefaultAlgorithm());

kmfactory.init(keystore, password !=null ? password.toCharArray()

:null);

return kmfactory.getKeyManagers();

}

private TrustManager[] createTrustManagers(final KeyStore keystore)

throws KeyStoreException, NoSuchAlgorithmException{

if (keystore ==null){

thrownew IllegalArgumentException("Keystore may not be null");

}

TrustManagerFactory tmfactory = TrustManagerFactory

.getInstance(TrustManagerFactory.getDefaultAlgorithm());

tmfactory.init(keystore);

TrustManager[] trustmanagers = tmfactory.getTrustManagers();

for (int i = 0; i < trustmanagers.length; i++){

if (trustmanagers[i]instanceof X509TrustManager){

trustmanagers[i] =new AuthSSLX509TrustManager(

(X509TrustManager) trustmanagers[i]);

}

}

return trustmanagers;

}

private SSLContext createSSLContext(){

try{

KeyManager[] keymanagers =null;

TrustManager[] trustmanagers =null;

if (this.mockKeystoreUrl !=null){

KeyStore keystore = mockCreateKeyStore(this.mockKeystoreUrl,

this.keystorePassword);

//if (log.isDebugEnabled()) {

Enumeration aliases = keystore.aliases();

while (aliases.hasMoreElements()){

String alias = (String) aliases.nextElement();

Certificate[] certs = keystore

.getCertificateChain(alias);

if (certs !=null){

log.info("Certificate chain '" + alias +"':");

for (int c = 0; c < certs.length; c++){

if (certs[c]instanceof X509Certificate){

X509Certificate cert = (X509Certificate) certs[c];

log.info(" Certificate " + (c + 1) +":");

log.info(" Subject DN: "

+ cert.getSubjectDN());

log.info(" Signature Algorithm: "

+ cert.getSigAlgName());

log.info(" Valid from: "

+ cert.getNotBefore());

log.info(" Valid until: "

+ cert.getNotAfter());

log

.info(" Issuer: "

+ cert.getIssuerDN());

}

}

}

}

//}

keymanagers = createKeyManagers(keystore, this.keystorePassword);

}

if (this.mockTruststoreUrl !=null){

KeyStore keystore = mockCreateKeyStore(this.mockKeystoreUrl,

this.truststorePassword);

//if (log.isDebugEnabled()) {

Enumeration aliases = keystore.aliases();

while (aliases.hasMoreElements()){

String alias = (String) aliases.nextElement();

log.debug("Trusted certificate '" + alias +"':");

Certificate trustedcert = keystore

.getCertificate(alias);

if (trustedcert !=null

&& trustedcertinstanceof X509Certificate){

X509Certificate cert = (X509Certificate) trustedcert;

log.info(" Subject DN: " + cert.getSubjectDN());

log.info(" Signature Algorithm: "

+ cert.getSigAlgName());

log.info(" Valid from: " + cert.getNotBefore());

log.info(" Valid until: " + cert.getNotAfter());

log.info(" Issuer: " + cert.getIssuerDN());

}

}

//}

trustmanagers = createTrustManagers(keystore);

}

SSLContext sslcontext = SSLContext.getInstance("SSL");

///sslcontext.

sslcontext.init(keymanagers, trustmanagers,null);

return sslcontext;

}catch (NoSuchAlgorithmException e){

log.error(e.getMessage(), e);

thrownew RuntimeException("Unsupported algorithm exception: "

+ e.getMessage());

// throw new AuthSSLInitializationError("Unsupported algorithm

// exception: " + e.getMessage());

}catch (KeyStoreException e){

log.error(e.getMessage(), e);

thrownew RuntimeException("Keystore exception: " + e.getMessage());

// throw new AuthSSLInitializationError("Keystore exception: " +

// e.getMessage());

}catch (GeneralSecurityException e){

log.error(e.getMessage(), e);

thrownew RuntimeException("Key management exception: "

+ e.getMessage());

// throw new AuthSSLInitializationError("Key management exception: "

// + e.getMessage());

}catch (IOException e){

log.error(e.getMessage(), e);

thrownew RuntimeException(

"I/O error reading keystore/truststore file: "

+ e.getMessage());

// throw new AuthSSLInitializationError("I/O error reading

// keystore/truststore file: " + e.getMessage());

}

}

private SSLContext getSSLContext(){

if (this.sslcontext ==null){

this.sslcontext = createSSLContext();

}

return this.sslcontext;

}

/**

* Attempts to get a new socket connection to the given host within the

* given time limit.

*

* To circumvent the limitations of older JREs that do not support connect

* timeout a controller thread is executed. The controller thread attempts

* to create a new socket within the given limit of time. If socket

* constructor does not return until the timeout expires, the controller

* terminates and throws an {@link ConnectTimeoutException}

*

*

* @param host

*the host name/IP

* @param port

*the port on the host

* @param clientHost

*the local host name/IP to bind the socket to

* @param clientPort

*the port on the local machine

* @param params

*{@link HttpConnectionParams Http connection parameters}

*

* @return Socket a new socket

* @throws IOException

* @throws IOException

* if an I/O error occurs while creating the socket

* @throws UnknownHostException

* if the IP address of the host cannot be determined

*/

publicvoid connect(final String host,finalint sport,final String query,

final HttpConnectionParams params)throws IOException{

HostnameVerifier hv =new HostnameVerifier(){

publicboolean verify(String arg0, SSLSession arg1){

System.out.println("Bartek: Hostname is not matched for cert.");

returntrue;

}

};

URL wlsUrl =null;

wlsUrl =new URL("https", host, Integer.valueOf(sport).intValue(),

query);

System.out

.println(" Trying a new HTTPS connection using WLS client classes - "

+ wlsUrl.toString());

HttpsURLConnection sconnection = (HttpsURLConnection) wlsUrl

.openConnection();

SocketFactory socketfactory = getSSLContext().getSocketFactory();

/*

* HttpsURLConnection sconnection = new HttpsURLConnection( wlsUrl);

*/

sconnection.setHostnameVerifier(hv);

//sconnection.setSSLSocketFactory((SSLSocketFactory) socketfactory);

sconnection.setSSLSocketFactory((SSLSocketFactory) socketfactory);

//sconnection.setHostnameVerifier(hv);

tryConnection(sconnection, System.out);

}

publicstaticvoid tryConnection(HttpsURLConnection connection,

OutputStream stream)throws IOException{

connection.connect();

String responseStr ="\t\t" + connection.getResponseCode() +" -- "

+ connection.getResponseMessage() +"\n\t\t"

+ connection.getContent().getClass().getName() +"\n";

connection.disconnect();

System.out.print(responseStr);

}

}

Message was edited by:

herbatniczek

[20936 byte] By [herbatniczeka] at [2007-11-26 19:24:52]
# 1

1- By default, the jre will read the user's cacerts which runs the program.

2- You can specify another cacerts this way :

System.setProperty("javax.net.ssl.trustStore", my_trust);

For the case 1 and 2, you need to put the certificate in the cacerts.. Or,

3- You implement a custom TrustManager which, for example, accepts all certificates :

class X509TrustManagerTrustAll implements X509TrustManager {

public boolean checkClientTrusted(java.security.cert.X509Certificate[] chain){

return true;

}

public boolean isServerTrusted(java.security.cert.X509Certificate[] chain){

return true;

}

public boolean isClientTrusted(java.security.cert.X509Certificate[] chain){

return true;

}

public java.security.cert.X509Certificate[] getAcceptedIssuers() {

return null;

}

public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}

public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {}

}

and you call it in the right place in the code you wrote (SSLContext,..)

Hope it helps and deserves a duke star ;)

NephYliMa at 2007-7-9 21:48:16 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...
# 2
Bear in mind that case 3 above is completely insecure.
ejpa at 2007-7-9 21:48:16 > top of Java-index,Security,Java Secure Socket Extension (JSSE)...