Android java.security.cert.CertPathValidatorException: Trust anchor for certification path not found
I am answering to this to give an idea about the scenario and solution as per the android developer site for others benefit. I have solved this using custom trust manager.
The problem was with the server certificate, it misses intermediate certificate authority. However with the first flow certificate path is completed somehow and result was successful certificate path validation.
There is a solution for this in android developer site. it suggest to use custom trust manager that trusts this server certificate or it suggest to 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 solved after intermediate certificate authority added to the certificate chain from the server side. It is the best solution, Bundling the certificate with the app requires app to be updated on certificate expiring or any other issues related with certificate management.
UPDATE:03/09/2017 Easiest way to load certificate file I found is use of raw resource.
InputStream caInput = new BufferedInputStream(context
.getResources().openRawResource(R.raw.certfilename));
where certfilename is the certificate file placed in resources/raw folder. Also okhttp's sslSocketFactory(SSLSocketFactory sslSocketFactory)
has been deprecated and suggested approach in the okhttp api doc can be used.
Also when getting the certificate from the server it is better to use openssl.
openssl s_client -connect {server-address}:{port} -showcerts
Because I used to grab that from firefox and faced situation where it was altered by the virus guard.