How to make https request with ssl certificate in Retrofit How to make https request with ssl certificate in Retrofit android android

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/