Trust Anchor not found for Android SSL Connection
Asked Answered
A

23

277

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());
Admittance answered 26/7, 2011 at 4:22 Comment(1)
I think the easiest solution is the following: use the code from this answer https://mcmap.net/q/35876/-accepting-https-connections-with-self-signed-certificates , change it up a little bit to just create a SSLSocketFactory, then use SSLSocket socket = (SSLSocket)sslSocketFactory.createSocket(HOST, PORT); and BOOM you have a secure socket!Batangas
I
95

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!

Indeciduous answered 21/10, 2011 at 10:16 Comment(7)
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.Caron
@Caron 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!Indeciduous
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.Caron
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'.Admittance
@Chrispix, you shouldn't have removed the partial fix, it's good for just testing purposesAdamite
If you are a ROM developer put your CA root certificate in AOSP tree in system/ca-certificates/filesPulmotor
Before doing this, please check if server is configured properly, see Stevie's answer - https://mcmap.net/q/35851/-trust-anchor-not-found-for-android-ssl-connectionTerzas
C
302

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.

Caron answered 30/4, 2013 at 14:36 Comment(27)
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.Indeciduous
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".Caron
Thanks Stevie, I had my server misconfigured for 3 months, and only now I detected this! Now my android app is working 100%Failsafe
this is exactly the root cause of our server. we are introducing HAProxy into production, and the misconfiguration of it cause the problem.Gathers
@Caron 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.Callum
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?Caron
This is fine if you have access to the server. What if you find this error on a server you dont have access to?Fourdrinier
@Fourdrinier 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.Caron
This is a superb post and got me to the root cause of my issue very quickly. Thanks very much.Coney
This is the actual solution to the problem and not a workaround. This should be a community wiki. Thank you @CaronImmerse
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).Kwakiutl
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 properlyIvories
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') };Earn
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.Forsworn
@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?Caron
@Stevie, hi stevie, thanks for your interest on my question, this full story of my case : #48426851Forsworn
@Caron 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?Talkfest
Also, this issue is described in the docs - developer.android.com/training/articles/…Terzas
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.Micropyle
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?Aaberg
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.Narco
how to check what misconfiguration on server ?Diversity
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.Sonorant
@Sonorant 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.Caron
@Caron 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.Sonorant
@Sonorant 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.Caron
Check out this answer, it fixed the problem for me: https://mcmap.net/q/35876/-accepting-https-connections-with-self-signed-certificates . Just change it up a little bit so you craete a SSLSocketFactory and use this to SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(HOST, PORT);Batangas
I
95

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!

Indeciduous answered 21/10, 2011 at 10:16 Comment(7)
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.Caron
@Caron 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!Indeciduous
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.Caron
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'.Admittance
@Chrispix, you shouldn't have removed the partial fix, it's good for just testing purposesAdamite
If you are a ROM developer put your CA root certificate in AOSP tree in system/ca-certificates/filesPulmotor
Before doing this, please check if server is configured properly, see Stevie's answer - https://mcmap.net/q/35851/-trust-anchor-not-found-for-android-ssl-connectionTerzas
S
22

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.

Septuagint answered 5/10, 2016 at 21:1 Comment(5)
what about .pfx ?Sanson
Isn't this unsafe since any user can access the assets folder for an app once they have the apk?Tanbark
@PatriceAndala, Root CAs are publicly available, so its okNardone
Thanks, if ssl renewing every 2 months, do we have to replace new cer file in the app every 2 months ?Success
This does not work for modern versions of OkHttp. setSslSocketFactory does not exist. Can you provide an updated example?Lippmann
P
22

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.

Polio answered 16/3, 2017 at 5:32 Comment(3)
What about if one is using an okhttp client?Mikol
For okhttp, pls check @mklimek's answer.Polio
I think he meant @klimat's answer - here: https://mcmap.net/q/35851/-trust-anchor-not-found-for-android-ssl-connectionMonaco
C
20

Replying to very old post. But maybe it will help some newbie and if non of the above works out.

Explanation: I know nobody wants explanation crap; rather the solution. But in one liner, you are trying to access a service from your local machine to a remote machine which does not trust your machine. You request need to gain the trust from remote server.

Solution: The following solution assumes that you have the following conditions met

  1. Trying to access a remote api from your local machine.
  2. You are building for Android app
  3. Your remote server is under proxy filtration (you use proxy in your browser setting to access the remote api service, typically a staging or dev server)
  4. You are testing on real device

Steps:

You need a .keystore extension file to signup your app. If you don't know how to create .keystore file; then follow along with the following section Create .keystore file or otherwise skip to next section Sign Apk File

Create .keystore file

Open Android Studio. Click top menu Build > Generate Signed APK. In the next window click the Create new... button. In the new window, please input in data in all fields. Remember the two Password field i recommend should have the same password; don't use different password; and also remember the save path at top most field Key store path:. After you input all the field click OK button.

Sign Apk File

Now you need to build a signed app with the .keystore file you just created. Follow these steps

  1. Build > Clean Project, wait till it finish cleaning
  2. Build > Generate Signed APK
  3. Click Choose existing... button
  4. Select the .keystore file we just created in the Create .keystore file section
  5. Enter the same password you created while creating in Create .keystore file section. Use same password for Key store password and Key password fields. Also enter the alias
  6. Click Next button
  7. In the next screen; which might be different based on your settings in build.gradle files, you need to select Build Types and Flavors.
  8. For the Build Types choose release from the dropdown
  9. For Flavors however it will depends on your settings in build.gradle file. Choose staging from this field. I used the following settings in the build.gradle, you can use the same as mine, but make sure you change the applicationId to your package name

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
    
  10. Click the bottom two Signature Versions checkboxes and click Finish button.

Almost There:

All the hardwork is done, now the movement of truth. Inorder to access the Staging server backed-up by proxy, you need to make some setting in your real testing Android devices.

Proxy Setting in Android Device:

  1. Click the Setting inside Android phone and then wi-fi
  2. Long press on the connected wifi and select Modify network
  3. Click the Advanced options if you can't see the Proxy Hostname field
  4. In the Proxy Hostname enter the host IP or name you want to connect. A typical staging server will be named as stg.api.mygoodcompany.com
  5. For the port enter the four digit port number for example 9502
  6. Hit the Save button

One Last Stop:

Remember we generated the signed apk file in Sign APK File section. Now is the time to install that APK file.

  1. Open a terminal and changed to the signed apk file folder
  2. Connect your Android device to your machine
  3. Remove any previous installed apk file from the Android device
  4. Run adb install name of the apk file
  5. If for some reason the above command return with adb command not found. Enter the full path as C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exe install name of the apk file

I hope the problem might be solved. If not please leave me a comments.

Salam!

Csch answered 16/3, 2018 at 5:43 Comment(1)
In my case the reason was using proxy-server on Android emulator (I use Charles). I just added servers to section "Bypass proxy for" (in wifi settings on emulator). Addresses of servers can be found in Charles. Or you can juct disable proxy.Arbuckle
T
14

Use https://www.ssllabs.com/ssltest/ to test a domain.

The solution of Shihab Uddin in Kotlin.

import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.security.cert.CertificateException

object {

    val okHttpClient: OkHttpClient
    val gson: Gson
    val retrofit: Retrofit

    init {

        okHttpClient = getOkHttpBuilder()
            // Other parameters like connectTimeout(15, TimeUnit.SECONDS)
            .build()

        gson = GsonBuilder().setLenient().create()

        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build()
    }

    fun getOkHttpBuilder(): OkHttpClient.Builder =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            OkHttpClient().newBuilder()
        } else {
            // Workaround for the error "Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate expired at".
            getUnsafeOkHttpClient()
        }

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

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(chain: Array<X509Certificate?>?,
                                                    authType: String?) = Unit

                    override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
                }
            )
            // Install the all-trusting trust manager
            val sslContext: SSLContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory,
                trustAllCerts[0] as X509TrustManager)
            builder.hostnameVerifier { _, _ -> true }
            builder
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
}

The same error will also appear if you use Glide, images won't show. To overcome it see Glide - javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found and How to set OkHttpClient for glide.

@GlideModule
class MyAppGlideModule : AppGlideModule() {

    val okHttpClient = Api.getOkHttpBuilder().build() // Api is the class written above.
    // It is better to create okHttpClient here and not use Api.okHttpClient,
    // because their settings may differ. For instance, it can use its own
    // `addInterceptor` and `addNetworkInterceptor` that can affect on a read JSON.


    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
        registry.replace(GlideUrl::class.java, InputStream::class.java,
            OkHttpUrlLoader.Factory(okHttpClient))
    }
}

build.gradle:

// Glide.
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0'
kapt 'com.github.bumptech.glide:compiler:4.11.0'

UPDATE

I also got another error on API 16 emulator:

routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741'.

Reading 1 and 2, I changed code so:

okHttpClient = getOkHttpBuilder().build()

private fun getOkHttpBuilder(): OkHttpClient.Builder {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        Security.insertProviderAt(Conscrypt.newProvider(), 1)
    }
    return OkHttpClient().newBuilder()
}

// build.gradle:
implementation 'org.conscrypt:conscrypt-android:2.5.1'

I also removed these lines from MyApplication:

try {
    ProviderInstaller.installIfNeeded(applicationContext)
    val sslContext = SSLContext.getInstance("TLSv1.2")
    sslContext.init(null, null, null)
    sslContext.createSSLEngine()
} catch (e: GooglePlayServicesRepairableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    GoogleApiAvailability.getInstance().showErrorNotification(this, e.connectionStatusCode)
} catch (e: GooglePlayServicesNotAvailableException) {
    Timber.e(e.stackTraceToString())
    // Prompt the user to install/update/enable Google Play services.
    // GoogleApiAvailability.getInstance().showErrorNotification(this, e.errorCode)
} catch (e: NoSuchAlgorithmException) {
    Timber.e(e.stackTraceToString())
} catch (e: KeyManagementException) {
    Timber.e(e.stackTraceToString())
}

But the library adds 3.4 Mb to apk.

Tarter answered 3/3, 2020 at 12:44 Comment(1)
Thank you so much, this worked for me nicely.Juneberry
Y
11

I had the same problem while trying to consume an external webservice that uses a self signed certificate for exposing its testing version. Here are the steps I've used to solve the issue globally (it will apply whatever the framework you're using : Retrofit, oKhttp, HttpUrlConnection)

  1. Load the domain in chrome (https://dev.thedomain.private)
  2. Export the certificate in .der format (padlock symbol near the url, then details then export and select the der format)
  3. Save the der into the raw forlder res/raw/dev_thedomain_private.der
  4. Create a security config file under resources/xml
    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <domain-config>
            <domain includeSubdomains="true">dev.thedomain.private</domain>
            <trust-anchors>
                <certificates src="@raw/dev_thedomain_private"/>
            </trust-anchors>
        </domain-config>
    </network-security-config>
  1. reference the security config in your manifest under the application tag
    <application
        android:networkSecurityConfig="@xml/network_security_config"

You're done ! The certificate will be trusted now...

Yulandayule answered 19/3, 2023 at 9:36 Comment(3)
In my case it was 'res', not 'resources'. And when I exported the cert from the browser, it came with "-" in place of ".", which was bad because "-" was illegal (needed "_" underscore, not dash). According to the doc, you can use PEM or DER. Browser gave me PEM and I converted to DER. It worked, though.Contrite
I used this, but I got this error: resource xml/network_security_config (aka com.companyname.TimeApp:xml/network_security_config) not found.Maximo
getting the error for file path @raw/dev_thedomain_private not foundBadly
D
5

I had the same problem what i found was that the certificate .crt file i provided missing an intermediate certificate. So I asked all .crt files from my server admin, then concatinated them in reverse order.

Ex. 1. Root.crt 2. Inter.crt 3. myCrt.crt

in windows i executed copy Inter.crt + Root.crt newCertificate.crt

(Here i ignored myCrt.crt)

Then i provided newCertificate.crt file into code via inputstream. Work done.

Donelson answered 12/8, 2015 at 10:35 Comment(1)
We also had the same issue. Intermediate certificate was missingTerriss
D
5

I know that you don't need to trust all certificates but in my case I had problems with some debugging environments where we had self-signed certificates and I needed a dirty solution.

All I had to do was to change the initialization of the sslContext

mySSLContext.init(null, trustAllCerts, null); 

where trustAllCerts was created like this:

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[]{};
    }

    public void checkClientTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }
} };

Hope that this will come in handy.

Dissimilate answered 4/12, 2018 at 8:19 Comment(3)
That's I wanted to find! ThanksCompensation
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 :)Mme
This is radically insecure. Do not use.Repress
T
5

In my case, the root & intermediate certificates was successfully installed but I still got "Trust anchor for certification path not found." exception!. After digging the android document, found out that 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. If your app running on a OS with api level higher than 23 you should explicitly allow the app to trust user-added CA by adding its address to network_security_config like bellow:

<domain-config>
        <domain includeSubdomains="true">PUT_YOUR_SERVER_ADDERESS</domain>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
</domain-config>
Trader answered 23/5, 2021 at 12:52 Comment(0)
K
4

The error message I was getting was similar but the reason was that the self signed certificate had expired. When the openssl client was attempted, it gave me the reason which was overlooked when I was checking the certificate dialog from firefox.

So in general, if the certificate is there in the keystore and its "VALID", this error will go off.

Knifeedged answered 28/6, 2013 at 11:51 Comment(1)
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.Polychromy
S
4

I had the same problem while connecting from Android client to Kurento server. Kurento server use jks certificates, so I had to convert pem to it. As input for conversion I used cert.pem file and it lead to such errors. But if use fullchain.pem instead of cert.pem - all is OK.

Simaroubaceous answered 11/10, 2017 at 11:24 Comment(0)
F
3

The Trust anchor error can happen for a lot of reasons. For me it was simply that I was trying to access https://example.com/ instead of https://www.example.com/.

So you might want to double-check your URLs before starting to build your own Trust Manager (like I did).

Franci answered 31/7, 2018 at 8:53 Comment(0)
A
0

In Gingerbread phones, I always get this error: Trust Anchor not found for Android SSL Connection, even if I setup to rely on my certificate.

Here is the code I use (in Scala language):

object Security {
    private def createCtxSsl(ctx: Context) = {
        val cer = {
            val is = ctx.getAssets.open("mycertificate.crt")
            try
                CertificateFactory.getInstance("X.509").generateCertificate(is)
            finally
                is.close()
        }
        val key = KeyStore.getInstance(KeyStore.getDefaultType)
        key.load(null, null)
        key.setCertificateEntry("ca", cer)

        val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    tmf.init(key)

        val c = SSLContext.getInstance("TLS")
        c.init(null, tmf.getTrustManagers, null)
        c
    }

    def prepare(url: HttpURLConnection)(implicit ctx: Context) {
        url match {
            case https: HttpsURLConnection ⇒
                val cSsl = ctxSsl match {
                    case None ⇒
                        val res = createCtxSsl(ctx)
                        ctxSsl = Some(res)
                        res
                    case Some(c) ⇒ c
                }
                https.setSSLSocketFactory(cSsl.getSocketFactory)
            case _ ⇒
        }
    }

    def noSecurity(url: HttpURLConnection) {
        url match {
            case https: HttpsURLConnection ⇒
                https.setHostnameVerifier(new HostnameVerifier {
                    override def verify(hostname: String, session: SSLSession) = true
                })
            case _ ⇒
        }
    }
}

and here is the connection code:

def connect(securize: HttpURLConnection ⇒ Unit) {
    val conn = url.openConnection().asInstanceOf[HttpURLConnection]
    securize(conn)
    conn.connect();
    ....
}

try {
    connect(Security.prepare)
} catch {
    case ex: SSLHandshakeException /*if ex.getMessage != null && ex.getMessage.contains("Trust anchor for certification path not found")*/ ⇒
        connect(Security.noSecurity)
}

Basically, I setup to trust on my custom certificate. If that fails, then I disable security. This is not the best option, but the only choice I know with old and buggy phones.

This sample code, can be easily translated into Java.

Aurore answered 24/3, 2015 at 16:1 Comment(1)
C
0

I have had a similar problem and I have completely ruled out the strategy of trusting all sources.

I share here my solution applied to an application implemented in Kotlin

I would first recommend using the following website to obtain information about the certificate and its validity

If it does not appear as an 'Accepted Issuers' in the Android default trust store, we must get that certificate and incorporate it into the application to create a custom trust store

The ideal solution in my case was to create a high-level Trust Manager that combines the custom and the Android default trust store

Here he exposes the high level code used to configure the OkHttpClient that he used with Retrofit.

override fun onBuildHttpClient(httpClientBuild: OkHttpClient.Builder) {

        val trustManagerWrapper = createX509TrustManagerWrapper(
            arrayOf(
                getCustomX509TrustManager(),
                getDefaultX509TrustManager()
            )
        )

        printX509TrustManagerAcceptedIssuers(trustManagerWrapper)

        val sslSocketFactory = createSocketFactory(trustManagerWrapper)
        httpClientBuild.sslSocketFactory(sslSocketFactory, trustManagerWrapper)

    }

In this way, I could communicate with the server with a self-signed certificate and with other servers with a certificate issued by a trusted certification entity

This is it, I hope it can help someone.

Cianca answered 4/1, 2020 at 14:20 Comment(0)
I
0

I know this is a very old article, but I came across this article when trying to solve my trust anchor issues. I have posted how I fixed it. If you have pre-installed your Root CA you need to add a configuration to the manifest.

https://mcmap.net/q/35883/-does-okhttp-support-accepting-self-signed-ssl-certs

Illusory answered 6/2, 2020 at 20:52 Comment(2)
only for API 24+Nardone
@Nardone - 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 defaultIllusory
S
0

Sometimes it happens when admins setup the certificate incorrectly Check URL here https://www.sslshopper.com/ssl-checker.html

In my case, there was an error

The certificate is not trusted in all web browsers. You may need to install an Intermediate/chain certificate to link it to a trusted root certificate. Learn more about this error. You can fix this by following GlobalSign's Certificate Installation Instructions for your server platform. Pay attention to the parts about Intermediate certificates.

Scorekeeper answered 10/3, 2021 at 13:27 Comment(0)
O
0

In my case, the certificate in the website was correct (Issuer = GlobalSign RSA OV SSL CA 2018), but the certificate file I was downloading was wrong, because of the Antivirus that was "intercepting" the certificate and deliverying a new different certificate to download fron the browsers (Issuer = ESET SSL Filter CA) !!!

Check your certificate file has the correct issuer.

Ogive answered 12/1, 2023 at 21:5 Comment(0)
U
0

As others already mentioned the certificate is not trusted. The solution would be to obtain that certificate and include it as a trusted certificate within your http client.

Extract the server certificate as shown here: Using openssl to get the certificate from a server

And then create a SSLSocketFactory for the HttpsURLConnection client as shown below.

public static void main(String[] args) throws IOException {
    SSLFactory sslFactory = SSLFactory.builder()
            .withDefaultTrustMaterial()     // JDK trusted certificates
            .withSystemTrustMaterial()      // Android system trusted certificates
            .withTrustMaterial("/path/to/truststore.p12", "password".toCharArray()) // your custom list of trusted certificates
            .build();

    HttpsURLConnection connection = (HttpsURLConnection) (new URL("https://api.chucknorris.io/jokes/random")).openConnection();
    connection.setSSLSocketFactory(sslFactory.getSslSocketFactory());
    connection.setHostnameVerifier(sslFactory.getHostnameVerifier());
}

The above example is for the well known HttpsURLConnection. However if you are using a different client, this might be also usefull as it contains a list of almost 50 different http clients for configuring ssl, see here: Example http client ssl configuration

I need tell that the above snippet is based on a library which I provide here: GitHub - SSLContext Kickstart which can be included with the following snippet to your gradle build file:

implementation("io.github.hakky54:sslcontext-kickstart:8.1.6")
Unconstitutional answered 15/9, 2023 at 14:3 Comment(0)
C
-1

In my case this was happening after update to Android 8.0. The self-signed certificate Android was set to trust was using signature algorithm SHA1withRSA. Switching to a new cert, using signature algorithm SHA256withRSA fixed the problem.

Chalmers answered 16/3, 2018 at 17:1 Comment(0)
E
-2

I use these methods that one of them is in solutions above works for me : First:

   public  okhttp3.OkHttpClient 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();

        okhttp3.OkHttpClient.Builder builder = new 
      okhttp3.OkHttpClient.Builder();
        builder.sslSocketFactory(sslSocketFactory, 
      (X509TrustManager)trustAllCerts[0]);
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession 
       session) {
                return true;
            }
        });

        okhttp3.OkHttpClient okHttpClient = builder.build();
        return okHttpClient;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Second:

    @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: put this libraries to your classpath:

 implementation 'com.squareup.okhttp:okhttp:2.3.0'
implementation 'com.squareup.okhttp:okhttp-urlconnection:2.3.0'
    androidTestImplementation 'androidx.test.espresso:espresso- 
    core:3.3.0'

be sure that you call them in your class

Einberger answered 5/6, 2021 at 11:20 Comment(2)
This will disable all transport layer security and opens the app wide for all sorts of attacks!Rutile
For local development, because of ZScaler, when connected to network and to avoid SSLHandshakeExceptions, above trick works wonder. But yeah, only use this in non production environment.Juneberry
Q
-3
**Set proper alias name**
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
            X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
            String alias = cert.getSubjectX500Principal().getName();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
Quincentenary answered 4/3, 2016 at 14:36 Comment(0)
S
-3

Relpcae your clicent Like below var httpClient = new HttpClient(new System.Net.Http.HttpClientHandler());

Change https to http

Speer answered 11/1, 2022 at 12:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.