Some time ago our customer has decided to implement a more secure way of transmitting form data from an Android app to a webservice. Previously we used a simple HTTPS connection to send form data via webservice. In updated version customer wanted to use TLS/SSL to authenticate server and clients. The basic operations in TLS/SSL connection are: validation of the identity of the HTTPS server against a list of trusted certificates and client authentication to the HTTPS server using a private key.
We got a client certificate in form of *.p12 file to authenticate to the HTTPS server using a private key. The identity of the HTTPS server was not validated, we trusted to all servers. *.p12 file format is commonly used to store X.509 private keys with accompanying public key certificates, protected with a password-based symmetric key.
In Android development SSLSocketFactory is used to validate the identity of the HTTPS server and to authenticate client to the HTTPS server using a private key. SSLSocketFactory will enable server authentication when supplied with a truststore file containg one or several trusted certificates but in our case we trust to all servers. SSLSocketFactory will enable client authentication when supplied with a keystore file containg a private key/public certificate pair. The client secure socket will use the private key to authenticate itself to the target HTTPS server during the SSL session handshake if requested to do so by the server. The target HTTPS server will in its turn verify the certificate presented by the client in order to establish client’s authenticity. Therefore, the solution for our problem was to create custom SSLSocketFactory . The custom SSLSocketFactory was then used to construct HttpClient that executes HTTP(S) requests.
Custom SSLSocketFactory class:
1/**
2 * Custom SSLSocketFactory class.
3 */
4public class CustomSSLSocketFactory extends SSLSocketFactory {
5
6 SSLContext sslContext = SSLContext.getInstance("TLS");
7 Context context;
8
9 /**
10 * Constructor.
11 */
12 public CustomSSLSocketFactory(Context context, KeyStore keystore, String keyStorePassword, KeyStore truststore)
13 throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
14
15 super(keystore, keyStorePassword, truststore);
16 this.context = context;
17
18 // custom TrustManager,trusts all servers
19 TrustManager tm = new X509TrustManager() {
20 @Override
21 public void checkClientTrusted(X509Certificate[] chain,
22 String authType) throws CertificateException {
23 }
24
25 @Override
26 public void checkServerTrusted(X509Certificate[] chain,
27 String authType) throws CertificateException {
28 }
29
30 @Override
31 public X509Certificate[] getAcceptedIssuers() {
32 return null;
33 }
34 };
35
36 Log.i("CLIENT CERTIFICATES", "Loaded client certificates: " + keystore.size());
37
38 // initialize key manager factory with the client certificate
39 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
40 keyManagerFactory.init(keystore,"mypassword".toCharArray());
41
42 sslContext.init(keyManagerFactory.getKeyManagers(), new TrustManager[] { tm }, null);
43 }
44
45 @Override
46 public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
47 return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
48 }
49
50 @Override
51 public Socket createSocket() throws IOException {
52 return sslContext.getSocketFactory().createSocket();
53 }
54
55 /**
56 * Create new HttpClient with CustomSSLSocketFactory.
57 */
58 public static HttpClient getNewHttpClient(Context context) {
59 try {
60 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
61 trustStore.load(null, null);
62
63 // client certificate is stored in android's resource folder (raw)
64 InputStream keyStoreStream = context.getResources().openRawResource(R.raw.p12_file);
65 KeyStore keyStore = KeyStore.getInstance("PKCS12");
66
67 try {
68 keyStore.load(keyStoreStream, "mypassword".toCharArray());
69 } catch (CertificateException e) {
70 e.printStackTrace();
71 } catch (IOException e) {
72 e.printStackTrace();
73 }
74
75 SSLSocketFactory sf = new CustomSSLSocketFactory(context,keyStore, "mypassword", trustStore);
76 sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
77
78 HttpParams params = new BasicHttpParams();
79 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
80 HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
81
82 SchemeRegistry registry = new SchemeRegistry();
83 registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
84 registry.register(new Scheme("https", sf, 443));
85
86 ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
87
88 return new DefaultHttpClient(ccm, params);
89
90 } catch (Exception e) {
91 return new DefaultHttpClient();
92 }
93 }
94}
After that we can easily execute HTTP(S) post:
1HttpClient client = CustomSSLSocketFactory.getNewHttpClient(MyActivity.this); 2String formDataServiceUrl = getString(R.string.form_data_service_url); 3HttpPost post = new HttpPost(formDataServiceUrl); 4post.setEntity(getMultipartEntityForPost()); 5 6HttpResponse result = client.execute(post);
More articles
fromMihal Celovski
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog author
Mihal Celovski
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.