9

I'm trying to run an Android Virtual Device from Android Studio. Everything works fine, until I try to access any Google's service from inside the virtual device. Our network is using corporate proxy and we have to install corporate certificates in order the applications to work. I installed the certificates to Java(jdk) via keytool -importcert -trustcacerts ..., then installed it to Android\Android Studio\jre\bin the same way. Then uploaded the certs into the virtual machine using adb push C:\certs\cert1.cer /sdcard/cert1.cer, and applied it in the Android in settings. But I'm still getting the error

Caused by: javax.net.ssl.SSLHandshakeException: Unacceptable certificate: CN=CompanyName Root CA, OU=IT Department, O='CompanyName Professional' LLC, L=NY, ST=NY, C=EN

Is it real to bypass anyhow? And why does it still ask for the certificate if I already have it imported. In browser all websites work fine if open it in the virtual machine. Thanx.

Robert
  • 39,162
  • 17
  • 99
  • 152
passwd
  • 2,883
  • 3
  • 12
  • 22
  • 1
    Installing it into the emulator is the wrong way for modern Android devices. You have to edit the [Network Security Configuration](https://developer.android.com/training/articles/security-config) of the app to accept your company root CA certificate. See for example [this](https://stackoverflow.com/questions/48879181) question. – Robert Aug 20 '19 at 07:37
  • Thanx, but what to do, if the error occurs when I just open `Google Maps` on the virtual android device? – passwd Aug 20 '19 at 07:46
  • 1
    In that case you have to root the emulator, install XPosed and the modules "Just trust me" and "SSL Unpinning" (the last time I was using those modules I had to use the latest self-compiled versions from their Github repos, the precompiled modules in XPosed were too old. Note that this totally disables SSL/TLS security checking. On a long term it would be better to ask for a PC that is located in a network that is not going through that proxy (because more and more apps use certificate pinning which is totally incompatible with the SSL-proxy concept). – Robert Aug 20 '19 at 08:02
  • Thank you very much. Do you know why the error occurs even though I added `user defined` certs in security options? And only with Google services. – passwd Aug 20 '19 at 08:11
  • Adding a CA certificate as user defined certificate only work on older Android versions (AFAIR Android 6 and older). Additionally most Google apps use certificate pinning, therefore they will never accept your company root CA certificate. – Robert Aug 20 '19 at 08:40

3 Answers3

9

For anyone that encounters this error, I got this error on an Android Xamarin App and it was do to the date & time of the device out of sync.

7

Installing your root CA certificate as "User defined certificate" into the emulator is the wrong way for modern Android devices (Android 6+).

User installed CA certificates are by default not trusted by apps. On a rooted device you can install new CA certificates as system certificates as shown here:

If your device is rooted and has Magisk installed you can also use the Magisk Move Certificates module that moves user installed certificates into the system store.

Since Google introduced the Android Network Security Configuration every app has to explicitly add the user defined certificates to the trust list:

res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config>
        <trust-anchors>
            <certificates src="system"/>
            <certificates src="user"/>
        </trust-anchors>
    </base-config>
</network-security-config>

Every app that does not define a Android Network Security Configuration or that have such a configuration but do not include the <certificates src="user"/> entry will ignore your additionally installed certificate.

And make sure the AndroidManifest.xml contains the android:networkSecurityConfig attribute in the <application> tag:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

Additionally some apps (e.g. Google services and Play Store) perform certificate/key pinning which totally prevents breaking the HTTPS traffic unless the system is heavily modified:

Disable SSL/TLS certificate checking at all

You have to root the device and install LSPosed/Xposed + multiple modules to allow SSL/TLS interception like TrustMeAlready and SSL Unpinning).

Alternatively you can use Frida and certain scripts for disabling SSL/TLS certificate checking and some pinning implementations. As far as I know the Frida based Objection project contains some SSL unpinning script(s).

WARNING: Doing so totally eliminates the security of each and every SSL/TLS/HTTPS connections used by your device (up to the used proxy). Therefore not only you but everybody can intercept the connections made by the device and modify them this way!

Robert
  • 39,162
  • 17
  • 99
  • 152
  • May also want to add the certificate as stated here https://developer.android.com/training/articles/security-config#ConfigCustom – Reejesh Oct 07 '21 at 06:36
7

Best solution (Working):

Create a new class: HttpsTrustManager

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());
    }
}

And call the following function before HTTP call

HttpsTrustManager.allowAllSSL();
Amit Kadam
  • 589
  • 6
  • 7
  • 1
    For any one willing to use this, import all these: 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; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; – Alexandre Prazeres Aug 11 '21 at 18:17
  • Not sure why but not working for Andriod 7 Devices. – Kishan Solanki May 18 '22 at 11:48