I am using Retrofit to access my REST API. However, when I put my API behind ssl and access it by http://myhost/myapi
then I get this error:
Do I need t
The reason this occur is the JVM/Dalvik haven't not confidence in the CA certificates in the system or in the user certificate stores.
To fix this with Retrofit, If you are used okhttp, with another client it's very similar.
You've to do:
A). Create a cert store contain public Key of CA. To do this you need to launch next script for *nix. You need openssl install in your machine, and download from https://www.bouncycastle.org/ the jar bcprov-jdk16-1.46.jar. Download this version not other, the version 1.5x is not compatible with android 4.0.4.
#!/bin/bash
if [ -z $1 ]; then
echo "Usage: cert2Android<CA cert PEM file>"
exit 1
fi
CACERT=$1
BCJAR=bcprov-jdk16-1.46.jar
TRUSTSTORE=mytruststore.bks
ALIAS=`openssl x509 -inform PEM -subject_hash -noout -in $CACERT`
if [ -f $TRUSTSTORE ]; then
rm $TRUSTSTORE || exit 1
fi
echo "Adding certificate to $TRUSTSTORE..."
keytool -import -v -trustcacerts -alias $ALIAS \
-file $CACERT \
-keystore $TRUSTSTORE -storetype BKS \
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
-providerpath $BCJAR \
-storepass secret
echo ""
echo "Added '$CACERT' with alias '$ALIAS' to $TRUSTSTORE..."
B). Copy the file truststore mytruststore.bks in res/raw of your project
C). Setting SSLContext of the connection:
.............
okHttpClient = new OkHttpClient();
try {
KeyStore ksTrust = KeyStore.getInstance("BKS");
InputStream instream = context.getResources().openRawResource(R.raw.mytruststore);
ksTrust.load(instream, "secret".toCharArray());
// TrustManager decides which certificate authorities to use.
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ksTrust);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException | KeyManagementException e) {
e.printStackTrace();
}
.................
After a some research i found the way to bypass ssl error Trust anchor for certification path not found. This might be not a good way to do but you can use it for a testing purpose.
private HttpsURLConnection httpsUrlConnection( URL urlDownload) throws Exception {
HttpsURLConnection connection=null;
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@SuppressLint("TrustAllX509TrustManager")
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@SuppressLint("TrustAllX509TrustManager")
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL"); // Add in try catch block if you get error.
sc.init(null, trustAllCerts, new java.security.SecureRandom()); // Add in try catch block if you get error.
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier usnoHostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
SSLSocketFactory sslSocketFactory = sc.getSocketFactory();
connection = (HttpsURLConnection) urlDownload.openConnection();
connection.setHostnameVerifier(usnoHostnameVerifier);
connection.setSSLSocketFactory(sslSocketFactory);
return connection;
}
Fix for Android N & above: I had similar issue and mange to solve it by following steps described in https://developer.android.com/training/articles/security-config
But the config changes, without any complicated code logic, would only work on Android version 24 & above.
Fix for all version, including version < N: So for android lower then N (version 24) the solution is to via code changes as mentioned above. If you are using OkHttp, then follow the customTrust: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/CustomTrust.java
Hi same problem i have solved you can try this
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.NETWORK
// SET SSL
public static OkClient setSSLFactoryForClient(OkHttpClient client) {
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 null;
}
}
};
// 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();
client.setSslSocketFactory(sslSocketFactory);
client.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception e) {
throw new RuntimeException(e);
}
return new OkClient(client);
}
My answer might not be solution to your question but it will surely help others looking for similar issue like this one: javax.net.ssl.SSLHandshakeException: Chain validation failed
You just need to check your Android Device's Date and Time, it should be fix the issue. This resoled my problem.