Jump to Navigation

Me on Twitter

  • "How standards proliferate" - probably old but makes me laugh since it's #sotrue https://t.co/6ygxIBf7Lh #xkcd 2 weeks 2 days ago
  • RT @Numerama: Enquête : comment les apps Figaro, L'Équipe ou Closer participent au pistage de 10 millions de Français - https://t.co/GBcnT0… 4 weeks 1 day ago
  • When industry meets open source... https://t.co/uJbhJhZFyK Subscribe here https://t.co/NAOLqb4AL9 4 weeks 5 days ago
  • @Fyrd Do you know of a tool to list features used on a given website in order to obtain the minimum browsers requirements to make it work ? 24 weeks 7 hours ago
  • Quelqu'un aurait une place disponible pour #devoxx pour un collègue ? 31 weeks 1 day ago
  • Favorite tool of the day : https://t.co/1wGUhgh5rc @AtomEditor It also displays @PlantUML diagrams ! 39 weeks 1 day ago
  • With typeset you can do weird things like : myvar=hello echo $myvar # prints 'HELLO' in caps https://t.co/bLNDQrmokn 42 weeks 1 day ago
  • I've just stared at a 22mn intro to this #game ! Zachtronics | TIS-100 - https://t.co/36Tlp5HBB6 43 weeks 2 days ago
  • RT @nicoespeon: Six Tiny But Awesome #ES6 Features by @davidwalshblog https://t.co/kYNcYMrhVe 44 weeks 4 days ago
  • If u ever build Jenkins jobs with maven use the following delimiters 2 avoid variable clash : @maven_var@ + $jenkins_var vs ${var} for both 48 weeks 1 day ago

HttpClient 3.x : a portable SSL Socket Factory implementation

I*M Hell

I was just trying to implement client and server authentication over SSL on IBM Websphere 6 (JRE 1.4.2)...

Problems started to happen with a :

java.io.IOException: Error in loading the keystore: Private key decryption error: (java.lang.SecurityException: Unsupported keysize or algorithm parameters)
    at com.ibm.crypto.provider.PKCS12KeyStore.engineLoad(Unknown Source)
    at java.security.KeyStore.load(KeyStore.java:695)
    ... 30 more

... easily solved by replacing the JRE's policy files (local_policy.jar and US_export_policy.jar) with an unlimited version of them (ah, policy, policy...). If you are looking for this, I used Websphere ones (you will need an IBM.com account).

I was far from having a working solution (see this thread), but apart from the fact that I would have to provide strong reasons for this change to the architecture and production teams, this led me to another challenge : I would have to implement HTTPS access with client authentication !

A SSL socket factory implemented for you

It may sound awkward in 2012, but if you wish the HTTPS server to identify your Java client (versus : only the server is identified), you will have to write your own implementation of a socket factory.

The Java Runtime Environment doesn't provide ready-to-use classes to do this. Yes : there is javax.net.ssl.SSLSocketFactory.getDefault() but it requires to set some system (therefore global) properties to point to the certificates files !!!

Even with Apache's HttpClient (at least version 3.x), you have to use a custom SSLProtocolSocketFactory.

The HttpClient SSL Guide provides sample code to implement mutual client and server authentication ; unfortunately the latest stable release of it (contrib 3.1) is bound to Sun's API with imports such as com.sun.net.ssl.KeyManagerFactory. Needless to say that this will not work on an IBM Websphere JRE...

Note : There was some change in the latest trunk revisions but it looks like they are made for HttpClient 4.x...

Well, we finally come to the purpose of this article : a cleaned-up version of a SSLProtocolSocketFactory for HttpClient 3.1 that you can use with any JRE.

Just get the 2 classes from the next chapter and use as in the following code.
Parameters are self-explanatory : URL, password and type of both the keystore and the truststore (see the Javadoc)...

HttpClient hc = new HttpClient();
SecureProtocolSocketFactory protoSocketFactory = new ClientAndServerSSLSocketFactory(crtClient, crtClientPwd, crtClientType, crtServer, crtServerPwd, crtServerType);
Protocol authhttps = new Protocol("https", protoSocketFactory, port);
hc.getHostConfiguration().setHost(host, port, authhttps);


Although IBM now follows the general JSSE rules, you should notice that the previous "IBMJSSE" JSSE implementation (not "IBMJSSE2") uses javax.net.debug=true instead of javax.net.debug=all to display all traces (it took me some time to figure it out).

See http://www.ibm.com/developerworks/java/jdk/security/142/secguides/jsse2d... and http://docs.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuid... for more details.


Get the classes at github :


Or here :

package nicobo.ssl;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 * From "Apache commons HttpClient contrib"
 * @see <a
 *      href="http://hc.apache.org/httpclient-3.x/sslguide.html">http://hc.apache.org/httpclient-3.x/sslguide.html</a>
 * @see <a href="http://svn.apache.org/viewvc/httpcomponents/oac.hc3x/trunk/
 * src/contrib/org/apache/commons/httpclient/contrib/ssl/AuthSSLProtocolSocketFactory.java?
 * view=markup">AuthSSLProtocolSocketFactory.java</a>
public class ClientAndServerAuthSSLSocketFactory implements
		SecureProtocolSocketFactory {
	private static final Log LOG = LogFactory
	private URL keystoreUrl = null;
	private String keystorePassword = null;
	private String keystoreType;
	private URL truststoreUrl = null;
	private String truststorePassword = null;
	private String truststoreType;
	private SSLContext sslcontext = null;
	public KeyManager[] keymanagers;
	public TrustManager[] trustmanagers;
	 * Either a keystore or truststore file must be given. Otherwise SSL context
	 * initialization error will result.
	 * @param keystoreUrl
	 *            URL of the keystore file. May be <tt>null</tt> if HTTPS client
	 *            authentication is not to be used.
	 * @param keystorePassword
	 *            Password to unlock the keystore. IMPORTANT: this
	 *            implementation assumes that the same password is used to
	 *            protect the key and the keystore itself.
	 * @param keystoreType
	 *            Keystore type (format) (e.g. : "JKS", "PKCS12")
	 * @param truststoreUrl
	 *            URL of the truststore file. May be <tt>null</tt> if HTTPS
	 *            server authentication is not to be used.
	 * @param truststoreType
	 *            Password to unlock the truststore.
	 * @param keyStoreType
	 *            Truststore type (format) (e.g. : "JKS", "PKCS12")
	public ClientAndServerAuthSSLSocketFactory(final URL keystoreUrl,
			final String keystorePassword, final String keystoreType,
			final URL truststoreUrl, final String truststorePassword,
			final String truststoreType) {
		this.keystoreUrl = keystoreUrl;
		this.keystorePassword = keystorePassword;
		this.keystoreType = keystoreType;
		this.truststoreUrl = truststoreUrl;
		this.truststorePassword = truststorePassword;
		this.truststoreType = truststoreType;
	private SSLContext getSSLContext() throws IOException,
			UnsupportedOperationException {
		if (this.sslcontext == null) {
			this.sslcontext = createSSLContext();
		return this.sslcontext;
	private SSLContext createSSLContext() throws IOException,
			UnsupportedOperationException {
		try {
			KeyManager[] keymanagers = null;
			TrustManager[] trustmanagers = null;
			if (this.keystoreUrl != null) {
				KeyStore keystore = SSLHelper.createKeyStore(this.keystoreUrl,
						this.keystorePassword, this.keystoreType);
				if (LOG.isDebugEnabled()) {
					Enumeration aliases = keystore.aliases();
					while (aliases.hasMoreElements()) {
						String alias = (String) aliases.nextElement();
						Certificate[] certs = keystore
						if (certs != null) {
							LOG.debug("Certificate chain '" + alias + "':");
							for (int c = 0; c < certs.length; c++) {
								if (certs[c] instanceof X509Certificate) {
									X509Certificate cert = (X509Certificate) certs[c];
									LOG.debug(" Certificate " + (c + 1) + ":");
									LOG.debug("  Subject DN: "
											+ cert.getSubjectDN());
									LOG.debug("  Signature Algorithm: "
											+ cert.getSigAlgName());
									LOG.debug("  Valid from: "
											+ cert.getNotBefore());
									LOG.debug("  Valid until: "
											+ cert.getNotAfter());
									LOG.debug("  Issuer: " + cert.getIssuerDN());
				keymanagers = SSLHelper.createKeyManagers(keystore,
				this.keymanagers = keymanagers;
			if (this.truststoreUrl != null) {
				KeyStore keystore = SSLHelper.createKeyStore(
						this.truststoreUrl, 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
						if (trustedcert != null
								&& trustedcert instanceof X509Certificate) {
							X509Certificate cert = (X509Certificate) trustedcert;
							LOG.debug("  Subject DN: " + cert.getSubjectDN());
							LOG.debug("  Signature Algorithm: "
									+ cert.getSigAlgName());
							LOG.debug("  Valid from: " + cert.getNotBefore());
							LOG.debug("  Valid until: " + cert.getNotAfter());
							LOG.debug("  Issuer: " + cert.getIssuerDN());
				trustmanagers = SSLHelper.createTrustManagers(keystore);
				this.trustmanagers = trustmanagers;
			SSLContext sslcontext = SSLContext.getInstance("TLS");
			sslcontext.init(keymanagers, trustmanagers, null);
			return sslcontext;
		} catch (IOException e) {
			LOG.error("An I/O error occured while reading a keystore", e);
			throw e;
		} catch (Exception e) {
			LOG.error("Could not initialize a SSL context", e);
			throw new UnsupportedOperationException(e);
	 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
	public Socket createSocket(String host, int port, InetAddress clientHost,
			int clientPort) throws IOException, UnknownHostException,
			UnsupportedOperationException {
		return getSSLContext().getSocketFactory().createSocket(host, port,
				clientHost, clientPort);
	 * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
	public Socket createSocket(String host, int port) throws IOException,
			UnknownHostException, UnsupportedOperationException {
		return getSSLContext().getSocketFactory().createSocket(host, port);
	 * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
	public Socket createSocket(Socket socket, String host, int port,
			boolean autoClose) throws IOException, UnknownHostException,
			UnsupportedOperationException {
		return getSSLContext().getSocketFactory().createSocket(socket, host,
				port, autoClose);
	public Socket createSocket(final String host, final int port,
			final InetAddress localAddress, final int localPort,
			final HttpConnectionParams params) throws IOException,
			UnknownHostException, ConnectTimeoutException,
			UnsupportedOperationException {
		// TODO ? use HttpConnectionParams ?
		return getSSLContext().getSocketFactory().createSocket(host, port,
				localAddress, localPort);


package nicobo.ssl;
import java.io.IOException;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
 * SSL connections utilities
public class SSLHelper {
	private static final Log log = LogFactory.getLog(SSLHelper.class);
	 * Builds a keystore from a file.
	 * @param url
	 *            URL to the keystore file
	 * @param password
	 *            Keystore password
	 * @param keystoreType
	 *            Keystore type (cf <a href=
	 *            "http://docs.oracle.com/javase/1.4.2/docs/guide/security/CryptoSpec.html#AppA"
	 *            >Appendix A in the Java Cryptography Architecture API
	 *            Specification & Reference</a>)
	public static KeyStore createKeyStore(final URL url, final String password,
			final String keystoreType) throws KeyStoreException,
			NoSuchAlgorithmException, CertificateException, IOException {
		if (url == null) {
			throw new IllegalArgumentException("Keystore url may not be null");
		log.debug("Initializing key store : " + url + " (type " + keystoreType
				+ ")");
		KeyStore keystore = KeyStore.getInstance(keystoreType);
				password != null ? password.toCharArray() : null);
		return keystore;
	 * Builds a list of {@link KeyManager} from the default
	 * {@link KeyManagerFactory}.
	 * @param keystore
	 *            The keystore that holds certificats
	 * @param password
	 *            Keystore password
	 * @see KeyManagerFactory#getKeyManagers()
	 * @see KeyManagerFactory#getInstance(String)
	 * @see KeyManagerFactory#getDefaultAlgorithm()
	public static KeyManager[] createKeyManagers(final KeyStore keystore,
			final String password) throws KeyStoreException,
			NoSuchAlgorithmException, UnrecoverableKeyException {
		if (keystore == null) {
			throw new IllegalArgumentException("Keystore may not be null");
		log.debug("Initializing key manager");
		KeyManagerFactory kmfactory = KeyManagerFactory
		kmfactory.init(keystore, password != null ? password.toCharArray()
				: null);
		return kmfactory.getKeyManagers();
	 * Builds a list of {@link TrustManager} from the default
	 * {@link TrustManagerFactory}.
	 * @param keystore
	 *            Le keystore contenant les certificats
	 * @see TrustManagerFactory#getInstance(String)
	 * @see TrustManagerFactory#getTrustManagers()
	public static TrustManager[] createTrustManagers(final KeyStore keystore)
			throws KeyStoreException, NoSuchAlgorithmException {
		if (keystore == null) {
			throw new IllegalArgumentException("Keystore may not be null");
		log.debug("Initializing trust manager");
		TrustManagerFactory tmfactory = TrustManagerFactory
		TrustManager[] trustmanagers = tmfactory.getTrustManagers();
		for (int i = 0; i < trustmanagers.length; i++) {
			if (trustmanagers[i] instanceof X509TrustManager) {
				trustmanagers[i] = (X509TrustManager) trustmanagers[i];
		return trustmanagers;

Related links


Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • E-Mail addresses are hidden with reCAPTCHA Mailhide.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>. The supported tag styles are: <foo>, [foo].
  • Twitter-style #hashtags are linked to search.twitter.com.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.