Sunday, 24 April 2016

Implementing Android KeyChain to utilise stored user certificates.

Implementing Android KeyChain to utilise stored user certificates.

A friend of mine recently asked me to set up a proof of concept application in order to connect to an HTTPS web service and provide a user certificate from Android. After some searching, I found I could quite easily provide a user certificate from a PFX file using the Android KeyStore class. The stumbling block here was that I needed to use a certificate that had been pre-installed on the device.

The KeyChain class allows you to do just this. My initial implementation took advantage of the AOSP SSLUtils class from the ICS email application.

Essentially you need to do 3 things:

Ask the user to select a certificate

 KeyChain.choosePrivateKeyAlias(this, this,  
     new String[]{}, null, null, -1, null);  


Display the integrated Android certificate picker dialog.

Implement the KeyChainAliasCallback in your activity and override the alias method. inside this method you will be given an alias to the certificate that the user selected. It's possible to save this alias so that you don't need to ask the user every time. The SSLUtils.KeyChainKeyManager class is in the above SSLUtils class from the ICS email application.

This must be done on a background thread.

 KeyManager keyManager = SSLUtils.KeyChainKeyManager.    
   fromAlias(getApplicationContext(), alias);  
 mSslContext = SSLContext.getInstance("TLS");   
 mSslContext.init(new KeyManager[]{keyManager}, null, null);   


Once you have the certificate keys in the SSLContext object, you can then pass this to an HTTPS connection which should then use the user selected client certificate.

 URL requestedUrl = new URL(url);  
 urlConnection = (HttpURLConnection) requestedUrl.openConnection();  
 if(urlConnection instanceof HttpsURLConnection) {  
   ((HttpsURLConnection)urlConnection)  
       .setSSLSocketFactory(mSslContext.getSocketFactory());  
 }  
 urlConnection.setRequestMethod("GET");  
 urlConnection.setConnectTimeout(1500);  
 urlConnection.setReadTimeout(1500);  
 int lastResponseCode = urlConnection.getResponseCode();  
 result = "HTTP:" + lastResponseCode + ", "  
     + streamToString(urlConnection.getInputStream());  

Again the above needs to be done on a different thread to the UI. I'll upload the whole code when I've had chance to clean it up and just implement the KeyChain part.

For completeness, here is my streamToString function


   private String streamToString(InputStream is) throws IOException {  
     StringBuilder sb = new StringBuilder();  
     BufferedReader rd = new BufferedReader(new InputStreamReader(is));  
     String line;  
     while ((line = rd.readLine()) != null) {  
       sb.append(line);  
     }  
     return sb.toString();  
   }  


1 comment:

Please be nice! :)

Nutanix CE 2.0 on ESXi AOS Upgrade Hangs

AOS Upgrade on ESXi from 6.5.2 to 6.5.3.6 hangs. Issue I have tried to upgrade my Nutanix CE 2.0 based on ESXi to a newer AOS version for ...