Home » Android » android – javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

android – javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

Posted by: admin April 23, 2020 Leave a comment

Questions:

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 to do something extra now that my API is behind SSL?

Here is how I connect:

private final String API = "https://myhost/myapi";

private final RestAdapter REST_ADAPTER = new RestAdapter.Builder()
        .setServer(API)
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .build();

01-10 09:49:55.621    2076-2100/com.myapp.mobile D/Retrofit﹕ javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:401)
            at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
            at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
            at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
            at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
            at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
            at $Proxy12.signin(Native Method)
            at com.myapp.loginactivity$3.doInBackground(LoginActivity.java:143)
            at com.myapp.loginactivity$3.doInBackground(LoginActivity.java:136)
            at android.os.AsyncTask$2.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)
     Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:282)
            at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:202)
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:595)
            at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
            at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:398)
            at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
            at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
            at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
            at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
            at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
            at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
            at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
            at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:90)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:48)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:287)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:222)
            at $Proxy12.signin(Native Method)
            at com.myapp.LoginActivity$3.doInBackground(LoginActivity.java:143)
            at com.myapp.LoginActivity$3.doInBackground(LoginActivity.java:136)
            at android.os.AsyncTask$2.call(AsyncTask.java:287)
            at java.util.concurrent.FutureTask.run(FutureTask.java:234)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
            at java.lang.Thread.run(Thread.java:841)
How to&Answers:

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
truststore location

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();
}
.................

Answer:

This can happen for several reasons, including:

  1. The CA that issued the server certificate was unknown
  2. The server certificate wasn’t signed by a CA, but was self signed
  3. The server configuration is missing an intermediate CA

please check out this link for solution: https://developer.android.com/training/articles/security-ssl.html#CommonProblems

Answer:

There are 4 ways that I know of:

  • import the certificate to your app and use it for the connection
  • disable certificate checking
  • add your certificate to the trusted system certificates in Android
  • buy a verified certificate that is accepted by Android

I assume you don’t want to pay for this, so I think the most elegant solution is the first one, what can be accomplished this way:

http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

Answer:

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);
}

Answer:

The SSL is not properly configured. Those trustAnchor errors usually mean that the trust store cannot be found. Check your configuration and make sure you are actually pointing to the trust store and that it is in place.

Make sure you have a -Djavax.net.ssl.trustStore system property set and then check that the path actually leads to the trust store.

You can also enable SSL debugging by setting this system property -Djavax.net.debug=all. Within the debug output you will notice it states that it cannot find the trust store.

Answer:

I use this class and have no problem.

public class WCFs
{
    // https://192.168.30.8/myservice.svc?wsdl
    private static final String NAMESPACE = "http://tempuri.org/";
    private static final String URL = "192.168.30.8";
    private static final String SERVICE = "/myservice.svc?wsdl";
    private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";


    public static Thread myMethod(Runnable rp)
    {
        String METHOD_NAME = "myMethod";

        SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

        request.addProperty("Message", "Https WCF Running...");
        return _call(rp,METHOD_NAME, request);
    }

    protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
    {
        final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        int TimeOut = 5*1000;

        envelope.dotNet = true;
        envelope.bodyOut = soapReq;
        envelope.setOutputSoapObject(soapReq);

        final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);

        try
        {
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
            {
                @Override
                public boolean verify(String hostname, SSLSession session)
                {
                    return true;
                }
            });

            KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
            ((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));


        }
        catch(Exception e){}

        HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
        {
            @Override
            public void run()
            {
                Handler h = new Handler(Looper.getMainLooper());
                Object response = null;

                for(int i=0; i<4; i++)
                {
                    response = send(envelope, httpTransport_net , METHOD_NAME, null);

                    try
                    {if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}

                    if(response != null)
                        break;

                    ThreadHelper.threadSleep(250);
                }

                if(response != null)
                {
                    if(rp != null)
                    {
                        rp.setArguments(response.toString());
                        h.post(rp);
                    }
                }
                else
                {
                    if(Thread.currentThread().isInterrupted())
                        return;

                    if(rp != null)
                    {
                        rp.setExceptionState(true);
                        h.post(rp);
                    }
                }

                ThreadHelper.stopThread(this);
            }
        };

        thread.start();

        return thread;
    }


    private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
    {
        try
        {
            if(headerList != null)
                androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
            else
                androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);

            Object res = envelope.getResponse();

            if(res instanceof SoapPrimitive)
                return (SoapPrimitive) envelope.getResponse();
            else if(res instanceof SoapObject)
                return ((SoapObject) envelope.getResponse());
        }
        catch(Exception e)
        {}

        return null;
    }

    public static KeyStore getFromRaw(@RawRes int id, String algorithm, String filePassword)
    {
        try
        {
            InputStream inputStream = ResourceMaster.openRaw(id);
            KeyStore keystore = KeyStore.getInstance(algorithm);
            keystore.load(inputStream, filePassword.toCharArray());
            inputStream.close();

            return keystore;
        }
        catch(Exception e)
        {}

        return null;
    }

    public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
    {
        try
        {
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustKey);

            SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
            context.init(null, tmf.getTrustManagers(), null);

            return context.getSocketFactory();
        }
        catch(Exception e){}

        return null;
    }
}

Answer:

OK, So I faced the same issue for my android app which have secured domain i.e. HTTPS,

These are the steps:

  1. You need SSL certificate file i.e. “.pem” file for your domain.
  2. put that file into the assets folder
  3. Just copy and paste this class in your project

public class SSlUtilsw {

public static SSLContext getSslContextForCertificateFile(Context context, String fileName){

    try {
        KeyStore keyStore = SSlUtilsw.getKeyStore(context, fileName);
        SSLContext sslContext = SSLContext.getInstance("SSL");
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        sslContext.init(null,trustManagerFactory.getTrustManagers(),new SecureRandom());
        return sslContext;

    }catch (Exception e){
        String msg = "Error during creating SslContext for certificate from assets";
        e.printStackTrace();
        throw new RuntimeException(msg);
    }
}

public static KeyStore getKeyStore(Context context,String fileName){
    KeyStore keyStore = null;
    try {
        AssetManager assetManager=context.getAssets();
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream caInput=assetManager.open(fileName);
        Certificate ca;
        try {
            ca=cf.generateCertificate(caInput);

        }finally {
            caInput.close();
        }
        String keyStoreType=KeyStore.getDefaultType();
        keyStore=KeyStore.getInstance(keyStoreType);
        keyStore.load(null,null);
        keyStore.setCertificateEntry("ca",ca);
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return keyStore;
}}
  1. In your http client class of retrofit, add this

        val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
    trustManagerFactory.init(null as KeyStore?)
    val trustManagers: Array<TrustManager> = trustManagerFactory.trustManagers
    if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
        throw IllegalStateException("Unexpected default trust managers:" + trustManagers.contentToString())
    }
    val trustManager = trustManagers[0] as X509TrustManager
    
    httpClient.sslSocketFactory(SSlUtils.getSslContextForCertificateFile(
            applicationContextHere, "yourcertificate.pem").socketFactory, trustManager)
    

And that’s it.

Answer:

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.

Answer:

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