I am creating an android application which uses https
for communication with the server. I am using retrofit
and OkHttp
for making req
Retrofit 2.3.0
// Load CAs from an InputStream
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
InputStream inputStream = context.getResources().openRawResource(R.raw.ssl_certificate); //(.crt)
Certificate certificate = certificateFactory.generateCertificate(inputStream);
inputStream.close();
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", certificate);
// Create a TrustManager that trusts the CAs in our KeyStore.
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm);
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
X509TrustManager x509TrustManager = (X509TrustManager) trustManagers[0];
// Create an SSLSocketFactory that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{x509TrustManager}, null);
sslSocketFactory = sslContext.getSocketFactory();
//create Okhttp client
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory,x509TrustManager)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
If you have a certificate then you can provide but few webservices will not have the certificate for them please follow below.
// creating a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
// 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.setSslSocketFactory(sslContext.getSocketFactory());
// creating a RestAdapter using the custom client
return new RestAdapter.Builder()
.setEndpoint(UrlRepository.API_BASE)
.setClient(new OkClient(okHttpClient))
.build();
I don't use Retrofit and for OkHttp here is the only solution for self-signed certificate that worked for me:
Get a certificate from our site like in Gowtham's question and put it into res/raw dir of the project:
echo -n | openssl s_client -connect elkews.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./res/raw/elkews_cert.crt
Use Paulo answer to set ssl factory (nowadays using OkHttpClient.Builder()) but without RestAdapter creation.
Then add the following solution to fix: SSLPeerUnverifiedException: Hostname not verified
So the end of Paulo's code (after sslContext initialization) that is working for me looks like the following:
...
OkHttpClient.Builder builder = new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory());
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return "secure.elkews.com".equalsIgnoreCase(hostname);
});
OkHttpClient okHttpClient = builder.build();