Friday, August 26, 2011

How did I setup SSL with HTTPClient-4.1.2

I've been struggling to get this working for about 2 days now. I was able to POST a request directly from sockets, but it took me a while to see it working with HTTPClient-4.1.2. There are different variants out there in google for legacy HTTPClient and less than 4.1.x.
The key was to specify TrustManager and KeyManager while initializing SSLContext.

Step-1: First, you have to initialize SSLContext like this:

SSLContext ctx = SSLContext.getInstance("TLS");

Step-2: Getting TrustManager. Java look into its trust managers to check against authorized Certification Authorities(CA). Default trust store in Java is "jks". This is how you can get trust manager:
TrustManager[] getTrustManagers(String trustStoreType, InputStream trustStoreFile, String trustStorePassword) throws Exception {
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
trustStore.load(trustStoreFile, trustStorePassword.toCharArray());
TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
return tmfactory.getTrustManagers();

It should be called as:
TrustManager[] trustManagers = getTrustManagers("jks", new FileInputStream(new File("/Library/Java/Home/lib/security/cacerts")), "changeit");

/Library/Java/Home/lib/security/cacerts is the default path to trust managers in Mac OSX

Step-3: Getting KeyManager: This is where your client certificates are stored. KeyManager in the code can be retrieved as :
KeyManager[] keyManagers = getKeyManagers("pkcs12", new FileInputStream(new File("clientCertificate.p12")), "password");

You have to get KeyManagers using KeyManagerFactory like this:

KeyManager[] getKeyManagers(String keyStoreType, InputStream keyStoreFile, String keyStorePassword) throws Exception {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(keyStoreFile, keyStorePassword.toCharArray());
KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmfactory init(keyStore, keyStorePassword.toCharArray());
return kmfactory.getKeyManagers();

Step-4: Once you have TrustManager and KeyManager ready, pass them in SSLContext:
ctx.init(keyManagers, trustManagers, new SecureRandom());

Step-5: Now create a SSLSocketFactory object using SSLContext object:
SSLSocketFactory sf = new SSLSocketFactory(ctx, new StrictHostnameVerifier());

Step-6: Assign Scheme to the HttpClient:
DefaultHttpClient httpclient = new DefaultHttpClient();
ClientConnectionManager manager = httpclient.getConnectionManager();
manager.getSchemeRegistry().register(new Scheme("https", 443, sf));

Done !
Now use this httpclient in HttpPost, HttpGet ….

1 comment: