Java HttpsURLConnection building up to Client Certificates

User Rating: 0 / 5

Star InactiveStar InactiveStar InactiveStar InactiveStar Inactive
 

Https Connection

URL url = new URL("https://www.google.com"); HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println(inputLine); } in.close(); 


The java code above successfully creates a https connection and spouts out the returned html in text.

A default system store of certificates is used to check that the remote server is trusted.

When we connect to a server(https://ssl.microexpert.com) which is not trusted by the system store, an exception is thrown:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

To solve this, we can provide our own store of trusted certificates. In my case the CA itself signed my remote HTTPS server.

To use certificates within java, they must be converted to compatible format. You can uses java’s keytool to convert DER formatted files into JKS (Java key Store) files.

I used the following command:

https Connection used alternate trusted certificate store

URL url = new URL("https://ssl.microexpert.com"); HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); //Load Trusted Certs into a KeyStore Object KeyStore ksCACert = KeyStore.getInstance(KeyStore.getDefaultType()); ksCACert.load(new FileInputStream("C:/path/to/myCAStore.jks"), "capass".toCharArray()); //Initialise a TrustManagerFactory with the CA keyStore TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init(ksCACert); //Create new SSLContext using our new TrustManagerFactory SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null); //Get a SSLSocketFactory from our SSLContext SSLSocketFactory sslSocketFactory = context.getSocketFactory(); //Set our custom SSLSocketFactory to be used by our HttpsURLConnection instance urlConnection.setSSLSocketFactory(sslSocketFactory); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println(inputLine); } in.close(); 

SSLContext initialisation takes three parameters, which are:

SSLContext.init(KeyManager[] km, TrustManager[] tm, SecureRandom random)

If null is provided as a parameter a system default is resorted to.

Using a similar process as before, we can make our own KeyManager containing our client certificates and keys used when the server requires client certificate authentication.

https Connection using client certificate & key store

 URL url = new URL("https://ssl.microexpert.com"); HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); KeyStore ksClient = KeyStore.getInstance("pkcs12"); ksClient.load(new FileInputStream("C:/path/to/clientStore.p12"), "p12pass".toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ksClient, "p12pass".toCharArray()); KeyStore ksCACert = KeyStore.getInstance(KeyStore.getDefaultType()); ksCACert.load(new FileInputStream("C:/path/to/myCAStore.jks"), "capass".toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init(ksCACert); SSLContext context = SSLContext.getInstance("TLS"); //We now provide our alternate KeyManager context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); SSLSocketFactory sslSocketFactory = context.getSocketFactory(); urlConnection.setSSLSocketFactory(sslSocketFactory); BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println(inputLine); } in.close(); 

Https Connection on Android

To get the code above to run with a Android project you must use a BKS(Bouncy castle Key Store) file instead of a JKS(Java Key Store) files.

Also the BKS file created with the current release of the Bouncycastle Crypto API(1.47), produced a file that was incompatible with Android ICS. I found a older release (1.46) and placed this library within the same lib\ext\ directory, and was able to produce a compatible BKS file with the following command:

keytool -importcert -v -trustcacerts -file "cacert.pem" -alias ca -keystore "myCAStore.bks" -provider org.bouncycastle2.jce.provider.BouncyCastleProvider -storetype BKS -storepass capass

Other things to remember:

– The Android manifest must be set to allow the internet permission.
– Downloading a webpage should be done within a separate thread to the main.

CONTACT US

  +44 (0) 1903 721 668
  info@microexpert.com

  Microexpert Limited
Gratwicke House
10 East Street
Littlehampton
West Sussex
BN17 6AW, UK
© 2017 Microexpert. Registered number 01755695.

Search