Using client/server certificates for two way authentication SSL socket on Android
Android supports certificates in the BKS, P12 and other formats.
For BKS format:Use portecle to convert your certificates (.p12 and .crt) to .bks.
You need 2 files in your /res/raw
folder: truststore.bks
trust certificate for the server (converted from .cer file)
client.bks/client.p12
- the client certificate (converted from a .p12 file that contains the client certificate and the client key)
import java.io.*;import java.security.KeyStore;import javax.net.ssl.*;import org.apache.http.*;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.params.HttpClientParams;import org.apache.http.conn.ClientConnectionManager;import org.apache.http.conn.params.*;import org.apache.http.conn.scheme.*;import org.apache.http.conn.ssl.SSLSocketFactory;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;import org.apache.http.params.*;import android.app.Activity;import android.os.Bundle;public class SslTestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); try { // setup truststore to provide trust for the server certificate // load truststore certificate InputStream clientTruststoreIs = getResources().openRawResource(R.raw.truststore); KeyStore trustStore = null; trustStore = KeyStore.getInstance("BKS"); trustStore.load(clientTruststoreIs, "MyPassword".toCharArray()); System.out.println("Loaded server certificates: " + trustStore.size()); // initialize trust manager factory with the read truststore TrustManagerFactory trustManagerFactory = null; trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); // setup client certificate // load client certificate InputStream keyStoreStream = getResources().openRawResource(R.raw.client); KeyStore keyStore = null; keyStore = KeyStore.getInstance("BKS"); keyStore.load(keyStoreStream, "MyPassword".toCharArray()); System.out.println("Loaded client certificates: " + keyStore.size()); // initialize key manager factory with the read client certificate KeyManagerFactory keyManagerFactory = null; keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "MyPassword".toCharArray()); // initialize SSLSocketFactory to use the certificates SSLSocketFactory socketFactory = null; socketFactory = new SSLSocketFactory(SSLSocketFactory.TLS, keyStore, "MyTestPassword2010", trustStore, null, null); // Set basic data HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, "UTF-8"); HttpProtocolParams.setUseExpectContinue(params, true); HttpProtocolParams.setUserAgent(params, "Android app/1.0.0"); // Make pool ConnPerRoute connPerRoute = new ConnPerRouteBean(12); ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute); ConnManagerParams.setMaxTotalConnections(params, 20); // Set timeout HttpConnectionParams.setStaleCheckingEnabled(params, false); HttpConnectionParams.setConnectionTimeout(params, 20 * 1000); HttpConnectionParams.setSoTimeout(params, 20 * 1000); HttpConnectionParams.setSocketBufferSize(params, 8192); // Some client params HttpClientParams.setRedirecting(params, false); // Register http/s shemas! SchemeRegistry schReg = new SchemeRegistry(); schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schReg.register(new Scheme("https", socketFactory, 443)); ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg); DefaultHttpClient sClient = new DefaultHttpClient(conMgr, params); HttpGet httpGet = new HttpGet("https://server/path/service.wsdl"); HttpResponse response = sClient.execute(httpGet); HttpEntity httpEntity = response.getEntity(); InputStream is = httpEntity.getContent(); BufferedReader read = new BufferedReader(new InputStreamReader(is)); String query = null; while ((query = read.readLine()) != null) System.out.println(query); } catch (Exception e) { e.printStackTrace(); } }}
Update:
You can also load .crt files for the trust store directly without converting them to BKS:
private static KeyStore loadTrustStore(String[] certificateFilenames) { AssetManager assetsManager = GirdersApp.getInstance().getAssets(); int length = certificateFilenames.length; List<Certificate> certificates = new ArrayList<Certificate>(length); for (String certificateFilename : certificateFilenames) { InputStream is; try { is = assetsManager.open(certificateFilename, AssetManager.ACCESS_BUFFER); Certificate certificate = KeyStoreManager.loadX509Certificate(is); certificates.add(certificate); } catch (Exception e) { throw new RuntimeException(e); } } Certificate[] certificatesArray = certificates.toArray(new Certificate[certificates.size()]); return new generateKeystore(certificatesArray); } /** * Generates keystore congaing the specified certificates. * * @param certificates certificates to add in keystore * @return keystore with the specified certificates * @throws KeyStoreException if keystore can not be generated. */ public KeyStore generateKeystore(Certificate[] certificates) throws RuntimeException { // construct empty keystore KeyStore keyStore = KeyStore.getInstance(keyStoreType); // initialize keystore keyStore.load(null, null); // load certificates into keystore int length = certificates.length; for (int i = 0; i < length; i++) { Certificate certificate = certificates[i]; keyStore.setEntry(String.valueOf(i), new KeyStore.TrustedCertificateEntry(certificate), null); } return keyStore; }
Same goes for the KeyStore with the client certificate, you can use the .p12 file directly without converting it to BKS.