Trust Anchor not found for Android SSL Connection

537,579

Solution 1

The solution of @Chrispix is dangerous! Trusting all certificates allows anybody to do a man in the middle attack! Just send ANY certificate to the client and it will accept it!

Add your certificate(s) to a custom trust manager like described in this post: Trusting all certificates using HttpClient over HTTPS

Although it is a bit more complex to establish a secure connection with a custom certificate, it will bring you the wanted ssl encryption security without the danger of man in the middle attack!

Solution 2

Contrary to the accepted answer you do not need a custom trust manager, you need to fix your server configuration!

I hit the same problem while connecting to an Apache server with an incorrectly installed dynadot/alphassl certificate. I'm connecting using HttpsUrlConnection (Java/Android), which was throwing -

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

The actual problem is a server misconfiguration - test it with http://www.digicert.com/help/ or similar, and it will even tell you the solution:

"The certificate is not signed by a trusted authority (checking against Mozilla's root store). If you bought the certificate from a trusted authority, you probably just need to install one or more Intermediate certificates. Contact your certificate provider for assistance doing this for your server platform."

You can also check the certificate with openssl:

openssl s_client -debug -connect www.thedomaintocheck.com:443

You'll probably see:

Verify return code: 21 (unable to verify the first certificate)

and, earlier in the output:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`

The certificate chain will only contain 1 element (your certificate):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2

... but should reference the signing authorities in a chain back to one which is trusted by Android (Verisign, GlobalSign, etc):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

Instructions (and the intermediate certificates) for configuring your server are usually provided by the authority that issued your certificate, for example: http://www.alphassl.com/support/install-root-certificate.html

After installing the intermediate certificates provided by my certificate issuer I now have no errors when connecting using HttpsUrlConnection.

Solution 3

If you use retrofit, you need to customize your OkHttpClient.

retrofit = new Retrofit.Builder()
    .baseUrl(ApplicationData.FINAL_URL)
    .client(getUnsafeOkHttpClient().build())
    .addConverterFactory(GsonConverterFactory.create())
    .build();

Full code are as below.

public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        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 new java.security.cert.X509Certificate[]{};
                    }
                }
            };
    
                // 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();
    
                OkHttpClient.Builder builder = new OkHttpClient.Builder();
                builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
                builder.hostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
                return builder;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        
        public static ApiInterface getApiClient() {
            if (apiInterface == null) {
    
                try {
                    retrofit = new Retrofit.Builder()
                            .baseUrl(ApplicationData.FINAL_URL)
                            .client(getUnsafeOkHttpClient().build())
                            .addConverterFactory(GsonConverterFactory.create())
                            .build();
    
                } catch (Exception e) {
    
                    e.printStackTrace();
                }
    
    
                apiInterface = retrofit.create(ApiInterface.class);
            }
            return apiInterface;
        }
        
    }

Solution 4

Update based on latest Android documentation (March 2017):

When you get this type of error:

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:374)
        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.getInputStream(HttpURLConnectionImpl.java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)

the issue could be one of the following:

  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

The solution is to teach HttpsURLConnection to trust a specific set of CAs. How? Please check https://developer.android.com/training/articles/security-ssl.html#CommonProblems

Others who are using AsyncHTTPClient from com.loopj.android:android-async-http library, please check Setup AsyncHttpClient to use HTTPS.

Solution 5

You can trust particular certificate at runtime.
Just download it from server, put in assets and load like this using ssl-utils-android:

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

In the example above I used OkHttpClient but SSLContext can be used with any client in Java.

If you have any questions feel free to ask. I'm the author of this small library.

Share:
537,579

Related videos on Youtube

Chrispix
Author by

Chrispix

Updated on January 12, 2022

Comments

  • Chrispix
    Chrispix over 2 years

    I am trying to connect to an IIS6 box running a godaddy 256bit SSL cert, and I am getting the error :

    java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    

    Been trying to determine what could be causing that, but drawing blanks right now.

    Here is how I am connecting :

    HttpsURLConnection conn;              
    conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
    conn.setConnectTimeout(20000);
    conn.setDoInput(true);
    conn.setDoOutput(true);
    conn.connect();
    String tempString = toString(conn.getInputStream());
    
  • Stevie
    Stevie about 11 years
    This is ok for working with a self-generated cert, but for one (like the OP's) which has a valid chain back to the root CA's it is just a workaround for a badly configured server - see my answer.
  • Matthias B
    Matthias B about 11 years
    In case the OP has access to the servers SSL configuration he is connecting to, this might be a solution. But if he's not the one hosting the service he's connecting to he has to fix the problem on his side, meaning implementing a custom trust manager.
  • Matthias B
    Matthias B about 11 years
    @Stevie Accepting EVERY certificate is only an option for a proof of concept test, where SSL connection is not the part you want to test. Otherwise you don't have to use SSL, if you accept every certificate, as the connection is not secure!
  • Stevie
    Stevie about 11 years
    Your solution works, no question, but don't you agree that it is a workaround rather than a fix for the root cause? If I have to connect to a server from 3 clients (Android, iOS, Windows Mobile) then I have to apply the workaround on all 3, whereas I can fix the server once and they will all "just work".
  • Stevie
    Stevie about 11 years
    Ah, I'm sorry, I think there's a misunderstanding - I completely agree that no-one should ever accept every certificate! :) My comment was in regard to your 2nd paragraph - the suggestion to use a custom trust manager - which IMHO should be a last resort workaround rather than a recommended solution.
  • jpros
    jpros over 10 years
    Thanks Stevie, I had my server misconfigured for 3 months, and only now I detected this! Now my android app is working 100%
  • Jerry Tian
    Jerry Tian over 10 years
    this is exactly the root cause of our server. we are introducing HAProxy into production, and the misconfiguration of it cause the problem.
  • a fair player
    a fair player about 10 years
    @Stevie I make many calls to different APIs that share the same domain, but only one of them fails with (javax.net.ssl.SSLHandshakeException) ... any idea why such thing would happen? and by the way, the SSL Certificate is not trusted. So, I thought that all the calls should fail with the same exception.
  • Stevie
    Stevie about 10 years
    Are all calls from the same client infrastructure? Maybe some clients are more touchy. Do you use different sub-domains for some of the API's? Does the failing API do something a little different - say, using CORS? Perhaps your situation is different enough to require a new question?
  • jww
    jww almost 10 years
    If the certificate is expired, then its not valid according to a number of standards. Its OK to use a custom TrustManager and use a different set of criteria. But out of the box, that's what you have to work with.
  • dvaey
    dvaey over 8 years
    This is fine if you have access to the server. What if you find this error on a server you dont have access to?
  • Stevie
    Stevie over 8 years
    @dvaey get in touch with whoever does own the server and tell them their config is broken and their https is not working properly - give them this link to prove it digicert.com/help ... I imagine they would be appreciative and quick to resolve. Otherwise you'll have to take one of the workaround steps in the other answers, but then you'll have to either accept no security (ignore certs) or redeploy your apps when the cert expires and your custom trust store no longer matches the new cert.
  • dotnetdave82
    dotnetdave82 over 8 years
    This is a superb post and got me to the root cause of my issue very quickly. Thanks very much.
  • M4ver1k
    M4ver1k over 8 years
    This is the actual solution to the problem and not a workaround. This should be a community wiki. Thank you @Stevie
  • Chrispix
    Chrispix over 8 years
    Jut a heads up.. I removed the 'solution' I pasted as a work-around to not cause more issues, as people did not see it as a 'temporary work around'.
  • WawaBrother
    WawaBrother over 8 years
    To expand Stevie's solution, let me explain what a fix would be like, so you won't be panic as I was: I got my certificate from ssl.com. Here is the steps on how to install the intermediate certificates (if you use nginx): nginx.org/en/docs/http/configuring_https_servers.html Basically, you need to download the bundled certificate chain from your provider, then concatenate them with your current certificate. (Beware the order).
  • dorsz
    dorsz about 7 years
    This answer helped me (mobile developer) navigate network specialist in my huge company to solve the issue :) because for some reason then didn't install the intermediate certificates properly
  • Nidhin Chandran
    Nidhin Chandran almost 7 years
    We also had the same issue. Intermediate certificate was missing
  • Hugo Allexis Cardona
    Hugo Allexis Cardona over 6 years
    @Chrispix, you shouldn't have removed the partial fix, it's good for just testing purposes
  • Newbie009
    Newbie009 over 6 years
    Solution for android 2.3.x in case someone need it, stackoverflow.com/a/46465722/7125370
  • TheLearner
    TheLearner over 6 years
    What about if one is using an okhttp client?
  • ofskyMohsen
    ofskyMohsen over 6 years
    If you are a ROM developer put your CA root certificate in AOSP tree in system/ca-certificates/files
  • LiuWenbin_NO.
    LiuWenbin_NO. over 6 years
    Thanks a lot for the points! This gives me the correct reminds. For me my case is to connect to NodeJS push server from ReactNative. I had no 'ca' configuration so I ran into the issue, added CA the issue fixed. The final var options = { key: fs.readFileSync('./keys/server-key.pem'), ca: [fs.readFileSync('./keys/ca-cert.pem')], cert: fs.readFileSync('./keys/server-cert.pem') };
  • Bhimbim
    Bhimbim over 6 years
    hi stevie, i already do ssl debug, and it says retun code 0, im using comodo, as far as i know my server ssl configuration is correct. Should i keep digging the ssl configuration or moved to android's work around ?. You can check my website brinsmob.brins.co.id:5000, please let me know if you find anything wrong. I just got confuse where to look, the server configuration or android, thank you.
  • Stevie
    Stevie over 6 years
    @bhimbim your SSL setup looks fine to me, so presumably the problem is in your app somehow. If you aren't having exactly the same problem as described in the original post, maybe its worth posting a new question with specifics?
  • Bhimbim
    Bhimbim over 6 years
    @Stevie, hi stevie, thanks for your interest on my question, this full story of my case : stackoverflow.com/questions/48426351/…
  • Abbas
    Abbas about 6 years
    @Stevie I have the same problem, however this issue only occurs on Mobile and Tablets. I also have some Android TV boxes and somehow no issue there. Do you have any idea why on Android TV the api would work but not on mobile and tabs?
  • user1506104
    user1506104 over 5 years
    For okhttp, pls check @mklimek's answer.
  • Choletski
    Choletski over 5 years
    what about .pfx ?
  • oxied
    oxied over 5 years
    That's I wanted to find! Thanks
  • Sam
    Sam over 5 years
    I get error Hostname '192.168.0.16' was not verified. I am testing my webapi via my debugger (IIS Express) locally. Any idea how to fix this? Thanks :)
  • Vishwa Pratap
    Vishwa Pratap about 5 years
    I am try to use code but i am getting the following error again.. "javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found." can u help in this
  • Vadim Kotov
    Vadim Kotov about 5 years
    Before doing this, please check if server is configured properly, see Stevie's answer - stackoverflow.com/a/16302527/1000551
  • Vadim Kotov
    Vadim Kotov about 5 years
    Also, this issue is described in the docs - developer.android.com/training/articles/…
  • Patrice Andala
    Patrice Andala over 4 years
    Isn't this unsafe since any user can access the assets folder for an app once they have the apk?
  • user207421
    user207421 over 4 years
    This is radicaly insecure. Do not use.
  • user207421
    user207421 over 4 years
    This is radically insecure. Do not use.
  • Lubbo
    Lubbo over 4 years
    What if my server certificate works on Android 8+ and fails on 7-? I've already added intermediate and root certificates to the server and digicert.com/help shows that all is properly configured.
  • CoolMind
    CoolMind about 4 years
    Thanks! Rewrote the method getUnsafeOkHttpClient() in Kotlin: stackoverflow.com/a/60507560/2914140.
  • CrandellWS
    CrandellWS almost 4 years
    I aggree with this answer it is best to fix the server configuration. In my case I did this and checked SSL in several websites they all say it is good but yet on my older android I am now getting this error...Do you think it will auto upfate and fix in my case?
  • BekaBot
    BekaBot almost 4 years
    @PatriceAndala, Root CAs are publicly available, so its ok
  • BekaBot
    BekaBot almost 4 years
    only for API 24+
  • Brian S
    Brian S almost 4 years
    @BekaBot - this is probably true, but according to the documentation 23 and below trust user certs by default By default, secure connections (using protocols like TLS and HTTPS) from all apps trust the pre-installed system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default
  • Manu
    Manu over 3 years
    Thank you so much, this worked for me nicely.
  • Wojciech Marciniak
    Wojciech Marciniak almost 3 years
    No matter from what device. Compliance with security standards is a must. If the server is misconfigured then - if you can manage it - fix it, if not - do not use it. As simple as that. Excellent answer.
  • Somnath Kadam
    Somnath Kadam over 2 years
    how to check what misconfiguration on server ?
  • Reza
    Reza over 2 years
    Thanks, if ssl renewing every 2 months, do we have to replace new cer file in the app every 2 months ?
  • Akito
    Akito over 2 years
    The problem with this solution is the following: 1. You need access to the server. 2. If it works on all Android versions, except a really old one, why should you fix the server, when all work, except a single client? -- Both issues are big and the first is already a deal breaker. So, this solution is by far not as good as it sounds on paper.
  • Stevie
    Stevie over 2 years
    @Akito why would you want to use a server that is misconfigured such that https is broken? if you control it, the easiest fix is to configure it correctly. If you don't control it and there is no chain of trust why would you risk using it? It is either compromised or incompetently managed. Any other "solution" is a hack implemented because of not understanding how certificate chains work. re: your point 2 - a misconfigured server won't work with any version of android, old or new, nor any other client platform, because the problem lies with the server not the client.
  • Akito
    Akito over 2 years
    @Stevie I don't control it. My application is retrieving a PNG, that is always the same, does not change. It displays the PNG. That's it. I don't need perfectly configured HTTPS for retrieving a small PNG file. And even if the file was "compromised", it wouldn't make a difference, because it's just a placeholder file. So, your idea is not bad, in theory, but in practice it's just not realistic. It's far away from actual reality, actual real life. That said, your last statement is wrong and I can prove it. What I said works with every Android version, except the oldest one I tested.
  • ban-geoengineering
    ban-geoengineering over 2 years
    I think he meant @klimat's answer - here: stackoverflow.com/a/39883606/1617737
  • Stevie
    Stevie over 2 years
    @Akito it sounds to me like the server you are using is not misconfigured, but the oldest version of Android you tested with does not have the root CA in its list of known authorities. In other words, a totally different problem.