39

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)
birdy
  • 8,916
  • 24
  • 103
  • 171

12 Answers12

17

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();
}
.................
Fernando.
  • 712
  • 8
  • 12
  • If you are using `retrofit` you have to attach this `OkHttpClient` as suggested here: https://github.com/square/retrofit/issues/265. Also I have found this only works with: `bcprov-jdk16-1.46.jar` otherwise you get the `wrong version of keystore error` – tread Mar 17 '15 at 14:42
  • Cannot resolve method `okHttpClient.setSslSocketFactory(..)`, now should be `client = new OkHttpClient.Builder().sslSocketFactory(sslContext.getSocketFactory()).build();` – G. Ciardini Jun 25 '19 at 08:42
  • @Fernando can you help with the server part, what cerfiticate to use there, shoould it be the same?\ – inrob Mar 08 '20 at 02:03
  • i am unable to generate file i create bash file but it only goes to if ...whats the condition for it – babbin tandukar Oct 05 '21 at 03:02
4

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

Defuera
  • 5,076
  • 2
  • 29
  • 37
4

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);
}
Community
  • 1
  • 1
sushant gosavi
  • 3,272
  • 3
  • 30
  • 50
4

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

vijay
  • 729
  • 7
  • 13
3

You basically have four potential solutions to fix a "javax.net.ssl.SSLHandshakeException: " exception on Android

  1. Trust all certificates. Don't do this, unless you really know what you're doing.
  2. Create a custom SSLSocketFactory that trusts only your certificate. This works as long as you know exactly which servers you're going to connect to, but as soon as you need to connect to a new server with a different SSL certificate, you'll need to update your app.
  3. Create a Keystore file that contains Android's "master list" of certificates, then add your own. If any of those certs expire down the road, you are responsible for updating them in your app. I can't think of a reason to do this.
  4. Create a custom SSLSocketFactory that uses the built-in certificate KeyStore, but falls back on an alternate KeyStore for anything that fails to verify with the default. This is well explained in click here

Also, I want to elaborate more to point number 1. We can selectively skip some domain using manifest network config as explain:

  1. Create a file "network_security_config.xml" in xml folder in res folder with following content.

       <network-security-config xmlns:tools="http://schemas.android.com/tools"
         xmlns:android="http://schemas.android.com/apk/res/android">
             <domain-config>
              <domain includeSubdomains="true">191.1.1.0</domain>
              <domain includeSubdomains="true">your_domain</domain>
             <trust-anchors>
                 <certificates src="system" />
                 <certificates src="user" />
             </trust-anchors>
         </domain-config>
     </network-security-config>
    
  2. Add "network_security_config.xml" to application tag in manifest as:

    android:networkSecurityConfig="@xml/network_security_config"

Thats it..done!!. You successfully skipped the SSL certificate.

taranjeetsapra
  • 497
  • 7
  • 17
2

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

kupsef
  • 3,307
  • 1
  • 20
  • 30
  • 5
    How could I just disable certificate checking? Wanting to do this only in a test environment. – theblang Aug 14 '14 at 16:50
  • How do you "add your certificate to the trusted system certificates in Android"? – IgorGanapolsky Feb 18 '15 at 21:30
  • There are several tutorials in the internet about that. Here is one for you: http://www.guyrutenberg.com/2013/03/16/manually-install-ssl-certificate-in-android-jelly-bean/ – kupsef Feb 21 '15 at 09:32
1

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.

Kevin Bowersox
  • 90,944
  • 18
  • 150
  • 184
1

This is a Server-Side issue.

Server side have .crt file for HTTPS, here we have to do combine

cat your_domain.**crt** your_domain.**ca-bundle** >> ssl_your_domain_.crt 

then restart.

sudo service nginx restart

For me working fine.

kk.
  • 3,288
  • 11
  • 33
  • 60
prabha
  • 11
  • 2
  • Thank you! Yes, I hadn't set `ca` file in my Node.js HTTPS server. It was working with `key` and `cert` only on browser, but it seems like Java needs `ca` bundle (having two or three `----BEGIN ...` parts) file. :) – Aidin Mar 14 '22 at 18:03
1

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;
    }
amit semwal
  • 303
  • 3
  • 15
  • isn't it ignoring cert proof checking? it's possibly not safe in production environment as at the end of the day you have to fix security issues for long term projects. – mgks Oct 02 '21 at 07:08
  • 1
    it will prevent to upload app on playstore – Gaurav Mandlik Mar 15 '22 at 09:00
0

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;
    }
}
Boendal
  • 2,461
  • 1
  • 22
  • 35
Ali Bagheri
  • 2,512
  • 23
  • 24
0

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

There are 2 Solutions for it:

SOLUTION 1 (EASY but not recommended):

Use this OkHttpClient.Builder to your Retrofit and it will work for you.

class UnsafeOkHttpClient {
companion object {
    fun getUnsafeOkHttpClient(): OkHttpClient.Builder {
        try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
                @Throws(CertificateException::class)
                override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
                }

                @Throws(CertificateException::class)
                override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
                }

                override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> {
                    return arrayOf()
                }
            })

            // Install the all-trusting trust manager
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, java.security.SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory = sslContext.socketFactory

            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
            // builder.hostnameVerifier { _, _ -> true }
            builder.hostnameVerifier ( hostnameVerifier = HostnameVerifier{ _, _ -> true })

            return builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
    }
}

SOLUTION 2 (LENGTHY but recommended):

  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.

Kishan Solanki
  • 11,648
  • 2
  • 65
  • 69
  • Hi, I have added certificate successfully, I am still getting handshake error. Not sure why. Do we need to do anything API side? Please advice stuck from many days. "CN=Cloudflare, C=US" getting this in if log this `cf.generateCertificate(caInput);`. – RaRa Oct 15 '20 at 06:33
0

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.

Irfan Anwar
  • 1,798
  • 15
  • 30