passwd
passwd

Reputation: 3353

Android Studio, javax.net.ssl.SSLHandshakeException: Unacceptable certificate

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.

Upvotes: 9

Views: 31413

Answers (3)

Robert
Robert

Reputation: 42575

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!

Upvotes: 9

Jorge L Hernandez
Jorge L Hernandez

Reputation: 939

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.

Upvotes: 12

Amit Kadam
Amit Kadam

Reputation: 629

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

Upvotes: 9

Related Questions