I have a .p12 certificate file, and I use the SSL Converter to convert it to a .pem certificate file. Then I use that pem certificate file in my android code like this:
OkHttpClient okHttpClient = new OkHttpClient();
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream instream = context.getResources().openRawResource(R.raw.pem_certificate);
Certificate ca;
ca = cf.generateCertificate(instream);
KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType());
kStore.load(null, null);
kStore.setCertificateEntry("ca", ca);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(kStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (CertificateException
| KeyStoreException
| NoSuchAlgorithmException
| IOException
| KeyManagementException e) {
e.printStackTrace();
}
baseURL = endpoint;
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(baseURL)
.setClient(new OkClient(okHttpClient))
.build();
service = restAdapter.create(DishService.class);
But this code doesn't work. It was failed at the line "ca = cf.generateCertificate(instream);" with CertificateException message.
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 sertificate https://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.
Guys lots of research & finally found the heart of this solution.
Step 1. Create a new java class like below
public class UnsafeOkHttpClient {
public 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, (X509TrustManager) trustAllCerts[0]);
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);
}
}
}
Step 2. Add above class method getUnsafeOkHttpClient()
into your API Client.
OkHttpClient clients = UnsafeOkHttpClient.getUnsafeOkHttpClient();
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.client(clients)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
PS: it works for me, Please add the functionality properly. damn sure it will work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With