Android - Obtain self-signed server certificate and add to trusted keystore

android, okhttp, ssl

Solution

The simple solution

Here's a code example of a trust manager callback. From the callback you can either store the self-signed certificates or just accept them right away. But you SHOULD NOT do neither. By accepting self-signed certs, you are subject to connecting to fake or malicious servers which can steal personal data, install malware, and do other nasty things.

The better-than-simple solution

If a server offers a self-signed certificate that you, the developer, trust at compile time, you can bundle the cert into the app like you're already doing. It would be much better if the server had a CA-signed certificate, but if you really need to connect to a server that offers a self-signed cert, this will (have to) do.

A nicer solution

Never accept self-signed certificates in runtime. If you want to allow your users to connect to these kind of servers, you can show a warning message like "proceed at your own risk" before accepting the self-signed cert.

Problem

My android application connects to an URL provided by the user. In case of HTTPS connections, if the server's certificate is issued by a CA that already exists in the Android's TrustManager, everything is fine. But if the server uses a self-signed certificate how can I obtain that certificate and store it in the TrustManager on first connection? I am using `OkHttp` library for performing network tasks. The solution that I have currently forces me to add the certificate in the application's `raw` folder during development but this will not work for the above mentioned scenario. The code that I am using currently is as below: ``` private KeyStore readKeyStore() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); String password = "testPass"; InputStream is = null; try { is = activity.getApplicationContext().getResources().openRawResource(R.raw.server_key); ks.load(is, password.toCharArray()); } finally { if (is != null) is.close(); } return ks; } private OkHttpClient getOkHttpClient() throws CertificateException, IOException, KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException { SSLContext sslContext = SSLContext.getInstance("SSL"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(readKeyStore()); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(readKeyStore(), "testPass".toCharArray()); sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom()); return new OkHttpClient().setSslSocketFactory(sslContext.getSocketFactory()); } ```

Original source

Related problems