Android java.security.cert.CertPathValidatorException: trust binding for certification path not found

There are three hosts that the android application performs authentication and authorization. The final host is the REST API. For the first time using Oauth authentication and authorization, it works without problems.

But if the user kills the application after logging in and accessing the services provided by the REST API, and then reopens the application, this problem occurs. At this time, the authentication and authorization process is not performed, only the REST API. This caused a java.security.cert.CertPathValidatorException , but it worked during the first use (logging in and using this application).

Can someone explain the scenario of this exception and what is wrong with this application. This works if certification exceptions are ignored according to this SO response .

 SSLSocketFactory sslSocketFactory = null; try { TrustManagerFactory tmf = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); // Initialise the TMF as you normally would, for example: try { tmf.init((KeyStore)null); } catch(KeyStoreException e) { e.printStackTrace(); } TrustManager[] trustManagers = tmf.getTrustManagers(); final X509TrustManager origTrustmanager = (X509TrustManager)trustManagers[0]; // Create a trust manager that does not validate certificate chains TrustManager[] wrappedTrustManagers = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return origTrustmanager.getAcceptedIssuers(); } public void checkClientTrusted(X509Certificate[] certs, String authType) { try { origTrustmanager.checkClientTrusted(certs, authType); } catch(CertificateException e) { e.printStackTrace(); } } public void checkServerTrusted(X509Certificate[] certs, String authType) { try { origTrustmanager.checkServerTrusted(certs, authType); } catch(CertificateException e) { e.printStackTrace(); } } } }; //TrustManager[] trustAllCerts = TrustManagerFactory.getInstance("SSL").getTrustManagers(); // Install the all-trusting trust manager final SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, wrappedTrustManagers, new java.security.SecureRandom()); // Create an ssl socket factory with our all-trusting manager sslSocketFactory = sslContext.getSocketFactory(); } catch (NoSuchAlgorithmException | KeyManagementException e) { e.printStackTrace(); } return sslSocketFactory; 

I am using Okhttp 3 for http requests. Any suggestion will help solve the problem. And please let me know if I use a code snippet, is this a security breach? will it affect application security?

+7
java android security ssl
source share
2 answers

I answer this to give an idea of ​​the scenario and solution according to the Android developers site for others. I solved this with a custom trust manager.

The problem was a server certificate that is missing an intermediate certification authority. However, when the first path of the certificate certificate was completed somehow, and the result was a successful verification of the certificate path.

There is a solution for the Android developer site for this. he suggests using a custom trust manager that trusts this server certificate or offers the server to include the intermediate CA in the server chain.

custom trust manager. source: https://developer.android.com/training/articles/security-ssl.html#UnknownCa

 // Load CAs from an InputStream // (could be from a resource or ByteArrayInputStream or ...) CertificateFactory cf = CertificateFactory.getInstance("X.509"); // From https://www.washington.edu/itconnect/security/ca/load-der.crt InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt")); Certificate ca; try { ca = cf.generateCertificate(caInput); System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); } finally { caInput.close(); } // Create a KeyStore containing our trusted CAs String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca); // Create a TrustManager that trusts the CAs in our KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore); // Create an SSLContext that uses our TrustManager SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null); // Tell the okhttp to use a SocketFactory from our SSLContext OkHttpClient okHttpClient client = new OkHttpClient.Builder().sslSocketFactory(context.getSocketFactory()).build(); 

UPDATE: My problem was resolved after adding an intermediate certificate authority to the certificate chain on the server side. This is the best solution. Combining the certificate with the application requires updating the application after the certificate expires or any other problems associated with certificate management.

UPDATE: 09/03/2017 The easiest way to upload a certificate file I found is to use the original resource.

 InputStream caInput = new BufferedInputStream(context .getResources().openRawResource(R.raw.certfilename)); 

where certfilename is the certificate file placed in the / raw resources folder. Also okhttp sslSocketFactory(SSLSocketFactory sslSocketFactory) deprecated, and the proposed approach in okhttp api doc can be used.

Also, when receiving a certificate from the server, it is better to use openssl.

 openssl s_client -connect {server-address}:{port} -showcerts 

Because I used to grab this from firefox and ran into a situation where it was modified by virus protection.

+12
source share

This problem may also occur if the date and time settings of the phone are not synchronized. I tested an Android device when I came across this problem.

Restoring date and time to current values ​​resolved this issue for me.

+1
source share

All Articles