Trusting all certificates with okHttp
Just in case anyone falls here, the (only) solution that worked for me is creating the OkHttpClient
like explained here.
Here is the code:
private 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);
}
}
Implementation of trust in all certificates with okhttp
Try to use OkHttpClient.Builder instead of direct OkHttpClient. Then you can setup sslSocketFactory and hostnameVerifier described https://stackoverflow.com/a/25992879/3816129
Okhttp3 - Accept all certificates and use a certificatePinner
The TrustManager, CertificatePinner and Hostname verification all do different but important things. If you want to use self-signed certificates but still have security, as opposed to self-signed certificates purely for ease of local development then you probably want to create a valid TrustManager.
e.g. https://github.com/yschimke/oksocial/blob/3757196cde420b9d0fe37cf385b66f4cdafb1ae1/src/main/java/com/baulsupp/oksocial/security/CertificateUtils.java#L19
public static X509TrustManager load(List<File> serverCerts)
throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException {
return trustManagerForKeyStore(keyStoreForCerts(serverCerts));
}
public static X509TrustManager trustManagerForKeyStore(KeyStore ks)
throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
return (X509TrustManager) tmf.getTrustManagers()[0];
}
public static KeyStore keyStoreForCerts(List<File> serverCerts)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
for (int i = 0; i < serverCerts.size(); i++) {
try (InputStream is = new FileInputStream(serverCerts.get(i))) {
X509Certificate caCert = (X509Certificate) cf.generateCertificate(is);
ks.setCertificateEntry("cacrt." + i, caCert);
}
}
return ks;
}
This will start off with the system certificates loaded, so your client can still be used to load externally hosted images etc.
Then on top of that you can use CertificatePinner to require that only your trusted self-signed certificates are used for your domain.
OkHttp trusting certificate
Let's assume your server app is hosting inside a server machine which has a server certificate in which "Issued to"
is "localhost"
, for example. Then, inside verify
method you can verify "localhost"
.
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv =
HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify("localhost", session);
}
};
You can read more at the following links:
HostnameVerifier
It is to be used during a handshake if the URL's hostname does not match the peer's identification hostname.
Common Problems with Hostname Verification
One reason this can happen is due to a server configuration error. The
server is configured with a certificate that does not have a subject
or subject alternative name fields that match the server you are
trying to reach...
Then, you can use the hostname verifier in your app, by calling client.setHostnameVerifier(hostnameVerifier);
. Hope this helps!
P/S: another temporary workaround is return true;
inside verify
method, however, it's not recommended.
Does OkHttp support accepting self-signed SSL certs?
Yes, It does.
Retrofit allows you to set your custom HTTP client, that is configured to your needs.
As for self-signed SSL certs there is a discussion here. The link contains code samples to add self-signed SSL to Android's DefaultHttpClient
and to load this client to Retrofit.
If you need OkHttpClient
to accept self signed SSL, you need to pass it custom javax.net.ssl.SSLSocketFactory
instance via setSslSocketFactory(SSLSocketFactory sslSocketFactory)
method.
The easiest method to get a socket factory is to get one from javax.net.ssl.SSLContext
as discussed here.
Here is a sample for configuring OkHttpClient:
OkHttpClient client = new OkHttpClient();
KeyStore keyStore = readKeyStore(); //your method to obtain KeyStore
SSLContext sslContext = SSLContext.getInstance("SSL");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "keystore_pass".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(),trustManagerFactory.getTrustManagers(), new SecureRandom());
client.setSslSocketFactory(sslContext.getSocketFactory());
Updated code for okhttp3 (using builder):
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory())
.build();
the client
here is now configured to use certificates from your KeyStore
. However it will only trust the certificates in your KeyStore
and will not trust anything else, even if your system trust them by default. (If you have only self signed certs in your KeyStore
and try to connect to Google main page via HTTPS you will get SSLHandshakeException
).
You can obtain KeyStore
instance from file as seen in docs:
KeyStore readKeyStore() {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// get user password and file input stream
char[] password = getPassword();
java.io.FileInputStream fis = null;
try {
fis = new java.io.FileInputStream("keyStoreName");
ks.load(fis, password);
} finally {
if (fis != null) {
fis.close();
}
}
return ks;
}
If you are on android you can put it in res/raw
folder and get it from a Context
instance using
fis = context.getResources().openRawResource(R.raw.your_keystore_filename);
There are several discussions on how to create your keystore. For example here
How to ignore SSL error in Okhttp?
OkHttpClient.Builder
allows you to add your own SSLContext
and TrustManager
. Here is the code from this gist which ignore all errors:
private 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 X509Certificate[0];
}
}
};
// 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();
return new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}).build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Note: This is an unsafe solution. Use it for debugging stuff.
OKhttp Self sign certificate in Kotlin Android
The following code works for me when I put these few lines of code before building my Client connection.
//set self sign certificate
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {
}
override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
}
override fun getAcceptedIssuers() = arrayOf<X509Certificate>()
})
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory = sslContext.socketFactory
// connect to server
val client = OkHttpClient.Builder().sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager).hostnameVerifier{ _, _ -> true }.build()
Related Topics
How to Retrieve the Android Sdk Version
Extending Application to Share Variables Globally
Bitmap Recycle with Largeheap Enabled
Updating Progress Dialog in Activity from Asynctask
Android - Out of Memory Exception When Creating Bitmap
Marking Sms Messages as Read/Unread or Deleting Messages Not Working in Kitkat
How to Install Android Sdk Build Tools on the Command Line
How to Make Sticky Headers in Recyclerview? (Without External Lib)
Background Listview Becomes Black When Scrolling
Scale Image to Fill Imageview Width and Keep Aspect Ratio
Any Way to Run Shell Commands on Android Programmatically
How to Get an Android Wakelock to Work
React Native Android Fetch Failing on Connection to Local API
How to Add a Line Break in an Android Textview
Android: Viewpager and Horizontalscrollview
How Do Detect Android Tablets in General. Useragent
Programmatically Change the Value of a Color Resource Obtained from API Response