Using self signed certificates with Android

When using https on Android it is required that the server certificate has been signed by trusted third party vendor. In some cases this requirement might lead to a situation where a https connection fails because a test server has a self signed certificate.

Luckily in Android, and in Java, it’s easy to circumvent the requirement. This is something you should only do in development code and it should be removed when the application is published.

Basics

To use self signed certificates you need to create a trust manager. The trust manager handles the validation of certificates and that’s the part of the program that throws SSLHandshakeException when your server certificate is not signed by a trusted party. Using a custom trust manager you have the ability choose which certificates are trusted and which are not, i.e. you can choose to trust or not to trust any certificate you like.

The example below shows how to create a dummy TrustManager instance which trusts all certificates.

As noted earlier this should only be used for testing and development and never in production!

Example

public class SelfSignedCertActivity extends Activity {

    private static final String TAG = "SelfSignedCertActivity";

    // Verifier that verifies all hosts
    private static final HostnameVerifier DUMMY_VERIFIER = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_self_signed_cert);
    }

    public void onOpenConnectionClick(View view) {

        new OpenConnectionTask().execute();
    }

    private class OpenConnectionTask extends AsyncTask<Void, Void, Boolean> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            // Dummy trust manager that trusts all certificates
            TrustManager localTrustmanager = new X509TrustManager() {

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain,
                        String authType) throws CertificateException {
                }

                @Override
                public void checkClientTrusted(X509Certificate[] chain,
                        String authType) throws CertificateException {
                }
            };

            // Create SSLContext and set the socket factory as default
            try {
                SSLContext sslc = SSLContext.getInstance("TLS");
                sslc.init(null, new TrustManager[] { localTrustmanager },
                        new SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sslc
                        .getSocketFactory());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
        }

        @Override
        protected Boolean doInBackground(Void... params) {

            try {

                URL url = new URL("https://caphal.com/");

                HttpsURLConnection connection = (HttpsURLConnection) url
                        .openConnection();
                connection.setHostnameVerifier(DUMMY_VERIFIER);

                // Log the server response code
                int responseCode = connection.getResponseCode();
                Log.i(TAG, "Server responded with: " + responseCode);

                // And if the code was HTTP_OK then return true
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    return true;
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return false;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);

            // Hide progressbar
            setProgressBarIndeterminateVisibility(false);

            if (result != null) {

                // Create a dialog
                Builder builder = new Builder(SelfSignedCertActivity.this);
                if (result) {
                    builder.setMessage("Connection was opened successfully");
                } else {
                    builder.setMessage("Connection failed");
                }
                builder.setPositiveButton("OK", null);

                // and show it
                builder.create().show();
            }
        }
    }
}

Screenshots

Initial view Successful connection Failed connection

Source code

Source code for the whole example project is available here

Further reading

Comments

comments powered by Disqus