Connect to server with self-signed certificate in Android Retrofit (or OKHTTP)

Problem:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

When to occur:

Connect to the server with self-signed certificate.

 

Solution:

There are two solutions here, one is to download the untrusted cert, and load it when connect to the server. The other one is to trust any website with any certificate which is not recommended BTW.

Solution one:

  1. Save CERT from the server, and put it to the <raw> directory:
    echo -n | openssl s_client -connect slrclub.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > <target_directory>/slrclub_cert.crt
  2. Load CERT for the OKHTTPClient:
        public static OkHttpClient getSlrClubClient(Context context) throws Exception {
            // loading CAs from an InputStream
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream cert = context.getResources().openRawResource(R.raw.slrclub_cert);
            Certificate ca;
            try {
                ca = cf.generateCertificate(cert);
            } finally { cert.close(); }
    
            // creating a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
    
            // creating a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);
    
            // creating an SSLSocketFactory that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);
    
    //        okHttpClient.sslSocketFactory(sslContext.getSocketFactory());
    
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslContext.getSocketFactory());
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
    
            OkHttpClient okHttpClient = builder.build();
    
            // creating a RestAdapter using the custom client
            return okHttpClient;
        }

    AND use it when create the Retrofit:

            SlrClubService slrClubService = null;
            try {
                slrClubService = new Retrofit.Builder()
                        .baseUrl(SlrClubService.ENDPOINT)
                        .client(getUnsafeOkHttpClient())
                        .build()
                        .create(SlrClubService.class);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            Call<ResponseBody> slrResult = slrClubService.getMainPage();
    //        Call<ResponseBody> result = service.getMainPage();
            slrResult.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                    try {
                        Log.e("ckdlee-onResponse", response.body().string());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    Log.e("ckdlee-onFailure", "Error");
                    Log.e("ckdlee", call.toString());
                    Log.e("ckdlee", t.toString());
                }
            });

Solution two:

  1. Create a unsafeOkHttpClient:
    private static OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[] {
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }
    
                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }
    
                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };
    
            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
    
            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
  2. use it for Retrofit.

 

 

Ref:

  1. http://stackoverflow.com/questions/25509296/trusting-all-certificates-with-okhttp
  2. http://stackoverflow.com/questions/29273387/certpathvalidatorexception-trust-anchor-for-certificate-path-not-found-retro/31436459#31436459

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s