Tuesday, November 16, 2010

HttpClient: Use Self-Signed Certificates

Lately I've been implementing SSL support between a Java Server and another production server. In my development environment I needed to use self-signed certificates and be able to use them with Jakarta HttpClient 4.x.

Looking through internet I found quite a lot information about how to add SSL support to HttpClient 3.x but not too much about HttpClient 4.x

Lets start with the code

private static DefaultHttpClient createHttpClient(int port) {
  try {
   java.lang.System.setProperty(
     "sun.security.ssl.allowUnsafeRenegotiation", "true");

   // First create a trust manager that won't care.
   X509TrustManager trustManager = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] chain,
      String authType) throws CertificateException {
     // Don't do anything.
    }

    public void checkServerTrusted(X509Certificate[] chain,
      String authType) throws CertificateException {
     // Don't do anything.
    }

    public X509Certificate[] getAcceptedIssuers() {
     // Don't do anything.
     return null;
    }
   };

   // Now put the trust manager into an SSLContext.
   // Supported: SSL, SSLv2, SSLv3, TLS, TLSv1, TLSv1.1
   SSLContext sslContext = SSLContext.getInstance("SSL");
   sslContext.init(null, new TrustManager[] { trustManager },
     new SecureRandom());

   // Use the above SSLContext to create your socket factory
   SSLSocketFactory sf = new SSLSocketFactory(sslContext);
   // Accept any hostname, so the self-signed certificates don't fail
   sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

   // Register our new socket factory with the typical SSL port and the
   // correct protocol name.
   Scheme httpsScheme = new Scheme("https", sf, port);
   SchemeRegistry schemeRegistry = new SchemeRegistry();
   schemeRegistry.register(httpsScheme);

   HttpParams params = new BasicHttpParams();
   ClientConnectionManager cm = new SingleClientConnManager(params,
     schemeRegistry);

   return new DefaultHttpClient(cm, params);
  } catch (Exception ex) {
   Log.error("ERROR Creating SSL Connection: " + ex.getMessage());

   return null;
  }
 }

The code is quite documented, so I will not add too much. Anyway I want to clarify somethings.

This code is not secure. This code accepts any certificate from any host, so don't use it in production code (or use it if you're really sure you known what you're doing)

In case you've any problem, there's a command that will really help you to debug the whole process.

System.setProperty("javax.net.debug", "all");

I really hope it will help you to save sometime.

1 comment: