I'm experiencing a issue with android 4 devices that receive the following exception connecting to the server:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:410) at okhttp3.internal.connection.RealConnection.connectTls(SourceFile:319) at okhttp3.internal.connection.RealConnection.establishProtocol(SourceFile:283) at okhttp3.internal.connection.RealConnection.connect(SourceFile:168) at okhttp3.internal.connection.StreamAllocation.findConnection(SourceFile:257) at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(SourceFile:135) at okhttp3.internal.connection.StreamAllocation.newStream(SourceFile:114) at okhttp3.internal.connection.ConnectInterceptor.intercept(SourceFile:42) at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:147) at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:121) at okhttp3.internal.cache.CacheInterceptor.intercept(SourceFile:93) at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:147) at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:121) at okhttp3.internal.http.BridgeInterceptor.intercept(SourceFile:93) at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:147) at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(SourceFile:126) at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:147) at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:121) at okhttp3.RealCall.getResponseWithInterceptorChain(SourceFile:254) at okhttp3.RealCall.execute(SourceFile:92)
The server certificate is from Cloudflare, I checked it with several tools like https://www.digicert.com/help/ and it seems ok.
But for some reason I don't understand it started to fail in Android 4 versions.
Tried the solution of trusting all certificates [LINK] and it works but this obviously have security issues like exposing your app to a "man in the middle" attack
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[]{};
}
}
};
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
okHttpBuilder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
How can I implement a TrustManager with a default behaviour but whitelisting only the certificate of the server.
Thanks
Edit: Following the example at OkHttp@CustomTrust (Thanks CommonsWare)
Used the command:
openssl s_client -showcerts -servername www.serverdomain.com -connect www.serverdomain.com:443
At the certificate chain gave me two certificates with format:
-----BEGIN CERTIFICATE-----
....
-----END CERTIFICATE-----
Replaced the url and the certificates in the example with the obtained ones but it is still not working, any ideas?