Android volley error: "Trust anchor for certification path not found", only in real device, not emulator
Asked Answered
E

5

15

I'm having a problem in my Android app, in one of my fragments I use volley to do a network request:

JsonObjectRequest request = new JsonObjectRequest(
            Request.Method.POST,
            CustomNetworkManager.getInstance(this.getActivity().getApplicationContext()).getRequestUrl(url),
            requestData,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    // process response
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    Log.d("FeedFragment", "Volley error: " + error.toString());
                }
            });

On a real device I get the following error (running API23):

D/FeedFragment: Volley error: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

In an AVD running the same API version it is working fine. I checked other similar threads but couldn't find an answer.

Thanks for your help.

edit: If anyone faces the same error, make sure you don't have any problems with your certificates (http://developer.android.com/intl/pt-br/training/articles/security-ssl.html#CommonProblems)

Escort answered 16/3, 2016 at 17:53 Comment(4)
Try removing 1st parameter : Request.Method.POSTNecessarian
I just did that and got the same error.Escort
Are you using latest version or older ?Necessarian
I was using version 1.0.16, I tried using the latest 1.0.19, but without success. I tried @OShiffer's solution and it worked. Thanks for your help!Escort
L
35

try to add this function to your Application:

    /**
     * Enables https connections
     */
    @SuppressLint("TrulyRandom")
    public static void handleSSLHandshake() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }

                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }};

            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            });
        } catch (Exception ignored) {
        }
    }

and then call it in your Application onCreate.

UPDATE:

This code is not relevant and shouldn't be used! it is forbidden by Google. for more information look here.

Logger answered 16/3, 2016 at 18:31 Comment(15)
It worked, thank you! Although, it worries me, isn't accepting all certificates a possible security breach?Escort
@Sammy Patenotte, you right! i just did a little research about that issue and found this: appcelerator.com/blog/2016/02/… and this is what we should do about it: developer.android.com/training/articles/security-ssl.htmlLogger
Thank you, after reading the second link, I realized the problem was with my intermediate certificates, and updating them solved my problem without having to modify the TrustManager :)Escort
after using the above function, i am facing the following issue on volleyerror "com.android.volley.ParseError: org.json.JSONException: Value <html><head><meta of type java.lang.String cannot be converted to JSONObject". Please suggest me how to fix it.Bemis
it has nothing with this function. you got an error in your response from server, and you cannot parse it because you expecting to get an object, but you get html string. try to use a sniffer to inspect your requests.Logger
application onCreateLogger
i dont sure if i understand you... in your application's onCreate(), after super.onCreate(), just add "handleSSLHandshake()".Logger
Yes i did the same what you are saying but error remain sameSodden
its hard to me to know what is the reason for your bug because i don't see your code/request/error. also, try to see the link that i posted.Logger
Let us continue this discussion in chat.Sodden
@Logger , can you check my code there in chat pleaseSodden
that's solved my problem but u said it's forbidden by google now. what's the new solution works fine with google?Progressionist
Why would this suddenly be an issue for me? I've been testing an app for weeks making https requests to a login script, then all of a sudden I start getting this error, despite nothing changing on my server. Why????? My certificate is valid, not self signed. It's literally been working for several weeks.Boldfaced
This is not the correct and proper answer as it makes your app vulnerable and will most likely reject by the PlayStoreCarrier
I've encountered same error when testing my app on localhost. using an emulator However when applying your code all certificates are trusted and my requests go through.Surfing
L
4

Just in case one still uses Volley...

Follow the instructions here:

https://developer.android.com/training/articles/security-ssl#java

Download the certificate file (.crt), put it into your assets directory (next to your java and res directories), then change the following code:

InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));

to use the file from assets:

InputStream caInput = new BufferedInputStream(getAssets().open("load-der.crt"));

Forget the part after

// Tell the URLConnection to use a SocketFactory from our SSLContext

and add one single line instead:

HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

Run this code before any connections made.

That's all.

Lickspittle answered 25/9, 2018 at 19:34 Comment(3)
Worked perfectly as described, thanks! Btw, your comment Just in case one still uses Volley... suggests that there is something better to manage requests? Spill the beansMeara
Thanks a lot! It works great! However, this method seems to only trust the custom keystore and ignores the system keystore. Any idea how to also trust the system keystore with this approach?Topping
What package is better than Volley? Can someone share?Gales
J
2

This solved my problem trying to run my android volley app on arc welder only needs to be run once..at the initial splash activity

Jews answered 30/6, 2018 at 16:59 Comment(1)
This is weird, i changed the splash activity to the activity i make the API request from, for testing and it didn't work then i changed it back to the splash activity as you said and it workedPerry
D
2

Step 1: Create a HttpsTrustManager class that implements X509TrustManager:

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class HttpsTrustManager implements X509TrustManager {

    private static TrustManager[] trustManagers;
    private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};

    @Override
    public void checkClientTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {

    }

    @Override
    public void checkServerTrusted(
            java.security.cert.X509Certificate[] x509Certificates, String s)
            throws java.security.cert.CertificateException {

    }

    public boolean isClientTrusted(X509Certificate[] chain) {
        return true;
    }

    public boolean isServerTrusted(X509Certificate[] chain) {
        return true;
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return _AcceptedIssuers;
    }

    public static void allowAllSSL() {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }

        });

        SSLContext context = null;
        if (trustManagers == null) {
            trustManagers = new TrustManager[]{new HttpsTrustManager()};
        }

        try {
            context = SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }

        HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    }

}

Step 2: Add HttpsTrustManager.allowAllSSL() before you make an HTTPS request:

HttpsTrustManager.allowAllSSL();
Deuterogamy answered 22/3, 2022 at 23:46 Comment(2)
This is working for me.Terzetto
Then upvote the answer (and the question) @UlagapandiUPMSDeuterogamy
M
0

In my case problem was Charles. Configure/close it and everything works for me

Magnetostriction answered 1/6, 2023 at 11:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.