How to make https request with ssl certificate in Retrofit
public class RetrofitBuilder {private static Retrofit retrofit = null;private static final String BASE_URL = BuildConfig.BASE_URL;private static final String API_VERSION = BuildConfig.VERSION;private static OkHttpClient.Builder httpClientBuilder = null;public static Retrofit getInstance(Context context) { if (retrofit == null) { httpClientBuilder = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS); initHttpLogging(); initSSL(context); Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(BASE_URL + API_VERSION) .addConverterFactory(GsonConverterFactory.create()) .client(httpClientBuilder.build()); retrofit = builder.build(); } return retrofit;}private static void initHttpLogging() { HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); if (BuildConfig.DEBUG) httpClientBuilder.addInterceptor(logging);}private static void initSSL(Context context) { SSLContext sslContext = null; try { sslContext = createCertificate(context.getResources().openRawResource(R.raw.cert)); } catch (CertificateException | IOException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) { e.printStackTrace(); } if(sslContext!=null){ httpClientBuilder.sslSocketFactory(sslContext.getSocketFactory(), systemDefaultTrustManager()); }}private static SSLContext createCertificate(InputStream trustedCertificateIS) throws CertificateException, IOException, KeyStoreException, KeyManagementException, NoSuchAlgorithmException{ CertificateFactory cf = CertificateFactory.getInstance("X.509"); Certificate ca; try { ca = cf.generateCertificate(trustedCertificateIS); } finally { trustedCertificateIS.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); return sslContext;}private static X509TrustManager systemDefaultTrustManager() { try { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init((KeyStore) null); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); } return (X509TrustManager) trustManagers[0]; } catch (GeneralSecurityException e) { throw new AssertionError(); // The system has no TLS. Just give up. }}}
After reading lots of post, blogs and gist I finally found a way. This works for me.
Maybe you have a problem in R.raw.pem_certificate...
1) Try to get a raw public certificate from server using openssl :openssl s_client -connect {HOSTNAME}:{PORT} -showcerts
(please look here for details: https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file)
2) How to setup Retrofit2 with a custom SSL sertificatehttps://adiyatmubarak.wordpress.com/tag/add-ssl-certificate-in-retrofit-2/
or Retrofit1:https://number1.co.za/use-retrofit-self-signed-unknown-ssl-certificate-android/
PS: it works for me, please don't convert PEM file to BKS.
The answer from Jay got me started, but I got this error: Trust anchor for certification path not found
I managed to import the p12 certificate I had into a keystore using the KeyTool command.
More specifically:
Step 1. Generate a new keystore with a default certificate and then delete it
keytool -genkey -alias mycert -keyalg RSA -keysize 2048 -keystore mykeystorekeytool -delete -alias mycert -keystore mykeystorekeytool -v -list -keystore mykeystore
Step 2. Import the certificate
keytool -v -importkeystore -srckeystore <path to certificate> -srcstoretype PKCS12 -destkeystore mykeystore -deststoretype PKCS12keytool -v -list -keystore mykeystore
Step 3: I then used the following code to load the SSLContext:
// open the keystore KeyStore keyStore = KeyStore.getInstance(type); try { keyStore.load(keystoreInputStream, password.toCharArray()); } finally { try { keystoreInputStream.close(); } catch (IOException e) { // swallow this } } // create and initialise a key manager factory KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509"); if (password != null && !password.trim().equals("")) { kmf.init(keyStore, password.toCharArray()); } else { kmf.init(keyStore, null); } // build an SSL context KeyManager[] keyManagers = kmf.getKeyManagers(); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagers, null, null);
Thanks to the code here: https://chariotsolutions.com/blog/post/https-with-client-certificates-on/