1
votes

I don't know if this is related to having updated Android Build Tools since I didn't try right after but I can't seem to get Charles to work propery with SSL Proxying on Android (it was working fine before).

In a nutshell, if I enable ssl proxying on my api endpoint on Charles I get:

Caused by: java.security.cert.CertificateException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: Certificate expired at Wed Aug 31 10:09:00 GMT+02:00 2016 (compared to Thu Sep 01 15:18:53 GMT+02:00 2016)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:344)
at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:219)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:115)
at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:556)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)

Of course I've checked our servers certificates (they didn't expire). I've checked the setup many times, I've tried deleting emulators (API 23 & 24) and reinstalling fresh ones, I've even tried upgrading build tools and compile sdk version to 24 and using Java 8. And I've also tried upgrading to Charles 4 and reinstalling the root certificate.

The keytool -list -keystore/usr/libexec/java_home/jre/lib/security/cacerts -storepass changeit does list the Charles Certificate. (for both the 1.7 and 1.8 jdks)

Charles Root certificate is properly installed on the emulator and expires in 2044

enter image description here

If I disable SSL Proxying on Charles, everything works just fine again with our without Charles running.

Also, when using an emulator running API 24, the exception is slightly different:

Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:563)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:444)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:508)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:401)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:375)
at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:304)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:178)
at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:596)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)

On more important thing to note, the same setup works just fine on the iOS Simulators using the same api endpoint. So this definitely has to do with Java/Android configuration.

Any help is appreciated.

2

2 Answers

4
votes

This happens with Android 7.0 if you target API level 24. Now user added CAs are not trusted by default and each app must explicitly opt-in.

To have your app trust the Charles certificate, declare a custom network security configuration in your AndroidManifest

<application
    android:networkSecurityConfig="@xml/network_security_config"
    >

Create the file in res/xml/network_security_config.xml with this configuration:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <!-- Trust user added CAs while debuggable only -->
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>

More info: http://android-developers.blogspot.fr/2016/07/changes-to-trusted-certificate.html and https://developer.android.com/training/articles/security-config.html

0
votes

I ended up removing all gradle cache folders and the project .gradle folder

rm -rf ~/.gradle/caches
rm -rf .gradle

And forcing Kotlin to use v1.0.3 instead of EAP builds and it worked back again. I don't know fully what went wrong here.