We were hesitant to write this tutorial, but due to the many, many requests: in this tutorial you will learn how to ignore the connection's security handshake and let Retrofit accept any, even bad SSL certificates. This includes revoked, expired or self-signed SSL certificates.
Warning: ignoring SSL certificate validity is incredibly dangerous and opens up your app and users for all kinds of security problems.
If you are aware of what you're doing, keep reading.
Retrofit Series Overview
- Getting Started and Creating an Android Client
- Basics of API Description
- Creating a Sustainable Android Client
- URL Handling, Resolution and Parsing
- How to Change API Base Url at Runtime
- Multiple Server Environments (Develop, Staging, Production)
- Share OkHttp Client and Converters between Retrofit Instances
- Upgrade Guide from 1.9
- Beyond Android: Retrofit for Java Projects
- How to use OkHttp 3 with Retrofit 1
- Synchronous and Asynchronous Requests
- Send Objects in Request Body
- Add Custom Request Header
- Manage Request Headers in OkHttp Interceptor
- Dynamic Request Headers with @HeaderMap
- Multiple Query Parameters of Same Name
- Optional Query Parameters
- Send Data Form-Urlencoded
- Send Data Form-Urlencoded Using FieldMap
- How to Add Query Parameters to Every Request
- Add Multiple Query Parameter With QueryMap
- How to Use Dynamic Urls for Requests
- Constant, Default and Logic Values for POST and PUT Requests
- Cancel Requests
- Reuse and Analyze Requests
- Optional Path Parameters
- How to Send Plain Text Request Body
- Customize Network Timeouts
- How to Trust Unsafe SSL certificates (Self-signed, Expired)
- Dynamic Endpoint-Dependent Interceptor Actions
- How to Update Objects on the Server (PUT vs. PATCH)
- How to Delete Objects on the Server
- Introduction to (Multiple) Converters
- Adding & Customizing the Gson Converter
- Implementing Custom Converters
- How to Integrate XML Converter
- Access Mapped Objects and Raw Response Payload
- Supporting JSON and XML Responses Concurrently
- Handling of Empty Server Responses with Custom Converter
- Send JSON Requests and Receive XML Responses (or vice versa)
- Unwrapping Envelope Responses with Custom Converter
- Wrapping Requests in Envelope with Custom Converter
- Define a Custom Response Converter
Accept Any SSL Certificate
In the next few minutes, we'll use BadSSL.com for our testing purposes. It gives us a wide variety of SSL certificates that no client should accept. By default, Retrofit will not connect to the subdomains (e.g., https://expired.badssl.com/ with bad SSL certificates.
Retrofit Call
Let's see if we change this behavior. Because the SSL certificate check is in the network layer, we'll need to change the OkHttp client instance. The rest of the Retrofit call will stay the same:
OkHttpClient okHttpClient = UnsafeOkHttpClient.getUnsafeOkHttpClient();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://10.0.2.2:3000/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
UserService userClient = retrofit.create(UserService.class);
Call<ResponseBody> call = userClient.profilePicture("https://revoked.badssl.com/");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Toast.makeText(BadSSLActivity.this, "got response" , Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(BadSSLActivity.this, "SSL error?" , Toast.LENGTH_SHORT).show();
}
});
Unsafe OkHttp Client
Next, it's time to look at the heart of this solution, the getUnsafeOkHttpClient()
method, which offers us an OkHttp client that completely ignores any SSL certificate issues:
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);
}
}
}
This code snippet is based on sonxurxo's answer on stackoverflow. It basically creates a new OkHttp client instance with custom SSL verification, which accepts every certificate.
Using this unsafe OkHttp client allows us to connect to the dangerous subdomains of BadSSL.com.
Better Solution: Accept Only Your Certificate
Again, accepting all SSL certificates is usually not the ideal scenario. Slightly better is to only accept your specific SSL certificate using a custom trust.
Summary
In this tutorial you've seen how you can disengage all connection security with a custom OkHttp client. If you really need to implement this, use caution!
Do you have further questions on this topic or about Retrofit in general? Just let us know on Twitter @futurestud_io or leave a comment below.
Enjoy coding & make it rock!