27

Google has advised that I have an unsafe implementation of the interface X509TrustManager in my Android application and need to change my code as follows:

To properly handle SSL certificate validation, change your code in the checkServerTrusted method of your custom X509TrustManager interface to raise either CertificateException or IllegalArgumentException whenever the certificate presented by the server does not meet your expectations. For technical questions, you can post to Stack Overflow and use the tags “android-security” and “TrustManager.”

How can the following code be modified to fix the above issue?

public EasySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
    super(truststore);

    TrustManager tm = new X509TrustManager()  {
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

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

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    mContext.init(null, new TrustManager[] { tm }, null);
}
Nabeel
  • 611
  • 1
  • 6
  • 11

5 Answers5

30

I have solved this using the following code:

public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                try {
                    chain[0].checkValidity();
                } catch (Exception e) {
                    throw new CertificateException("Certificate not valid or trusted.");
                }
            }
Nabeel
  • 611
  • 1
  • 6
  • 11
  • @Glowcall, at where I should write above code in application to solved error? I mean under which activity? – anddev Mar 07 '16 at 07:39
  • @anddev The affected activity/class depends on what Google referred to in the Email you were sent regarding this warning. Just find the relevant checkServerTrusted method in your source and replace it with the above; that should fix it. – Nabeel Mar 07 '16 at 16:17
  • 3
    If the CA is a self-signed CA, this solution is not a good idea! some times we must accept self-signed CA – zys Mar 08 '16 at 12:40
  • just one note: google doesn't check implementations of the interface X509TrustManager when app is in Beta or Alpha stage. Only prod and only five hours after publishing. – Yazazzello May 12 '16 at 09:27
  • @Lollipop so is there a solution for self signed certificates ?? – Sharp Edge Jul 12 '16 at 09:32
  • I implement the TrustManager to be able to work with the server on my development machine, bypassing all the certificate checks. Will adding this exception prevent me from sending requests to my development machine ? – geekoraul Sep 12 '16 at 19:35
  • > google doesn't check implementations of the interface X509TrustManager when app is in Beta or Alpha stage This is no longer true--I'm getting this error now for an app in alpha! – Lane Rettig Sep 22 '16 at 10:09
  • 3
    Don't use this very bad code! The code allows man-in-the-middle attacks and renders the entire point of SSL null. The `checkValidity()` method only checks if the certificate is not expired and nothing else, meaning this code will happily accept ANY not expired certificate whatsoever, even if the certificate is for another server and not signed by anything. – Nohus May 31 '17 at 19:47
  • @Nohus, what is your solution then? – Nabeel Jun 02 '17 at 02:50
  • I will write my answer when I get some time in a day or two and let you know. – Nohus Jun 02 '17 at 16:05
  • does anyone know where is this exception is being caught? – Artanis Dec 28 '18 at 17:52
  • find any solution if yes please share your ans with us! – Hardik Vasani Mar 05 '20 at 06:15
1

If you encounter this from external library you're using, check if appache libraray is the cause of it.

For me apache library caused the error : i was using deprecated class - MultipartEntity. This class uses SSLContextBuilder which uses TrustManagerDelegate. TrustManagerDelegate implements X509TrustManager, which cause "unsafe implementation of TrustManager" error when uploading application to google play store.

The solution is : instead of deprecated MultipartEntity class, use MultipartEntityBuilder.

For example :

MultipartEntity httpMultipart = new MultipartEntity();
String contentType = httpMultipart.getContentType().getValue();

Will be replaced by :

MultipartEntityBuilder httpMultipart = new MultipartEntityBuilder();
String contentType = httpMultipart.build().getContentType().getValue();
Dus
  • 4,052
  • 5
  • 30
  • 49
1

Add the upgraded version of OKttps worked for me crashing in Android 10

implementation 'com.squareup.okhttp3:okhttp:4.8.0'
0

I have meet this problem.If your code is like that:

 TrustManager tm = new X509TrustManager()  {
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

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

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
};

it will accept all certificate and it is a bad idea,so google send you mail. We can make a change to accept self-signed certificate too. I solved it,here is my question and my solution

Community
  • 1
  • 1
zys
  • 1,306
  • 3
  • 18
  • 37
-2

If you are using HttpClient then the solution of @Nabeel is very nice, but if you are using HttpsUrlConnection then this code is very nice for that:

import android.util.Log;

import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

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;

/**
 * TrustManager that accepts all certificates and hosts.
 * Useful when you want to use HTTPS but you have self-signed certificates.
 * Works with HttpsUrlConnection.
 * Use at your own risk and only for development.
 *
 * @author gotev (Aleksandar Gotev)
 */
public class AllCertificatesAndHostsTruster implements TrustManager, X509TrustManager {

    @Override
    public final void checkClientTrusted(final X509Certificate[] xcs, final String string)
            throws CertificateException {
    }

    @Override
    public final void checkServerTrusted(final X509Certificate[] xcs, final String string)
            throws CertificateException {
    }

    @Override
    public final X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }

    /**
     * Gets an {@link SSLContext} which trusts all certificates.
     * @return {@link SSLContext}
     */
    public static SSLContext getSSLContext() {
        final TrustManager[] trustAllCerts =
                new TrustManager[] {new AllCertificatesAndHostsTruster()};

        try {
            final SSLContext context = SSLContext.getInstance("SSL");
            context.init(null, trustAllCerts, new SecureRandom());
            return context;

        } catch (Exception exc) {
            Log.e("CertHostTruster", "Unable to initialize the Trust Manager to trust all the "
                    + "SSL certificates and HTTPS hosts.", exc);
            return null;
        }
    }

    /**
     * Creates an hostname verifier which accepts all hosts.
     * @return {@link HostnameVerifier}
     */
    public static HostnameVerifier getAllHostnamesVerifier() {
        return new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
    }

    /**
     * Call this method once before all your network calls
     * to accept all the self-signed certificates in HTTPS connections.
     */
    public static void apply() {
        final TrustManager[] trustAllCerts =
                new TrustManager[] {new AllCertificatesAndHostsTruster()};

        try {
            final SSLContext context = SSLContext.getInstance("SSL");
            context.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

        } catch (Exception exc) {
            Log.e("CertHostTruster", "Unable to initialize the Trust Manager to trust all the "
                    + "SSL certificates and HTTPS hosts.", exc);
        }
    }
}

Source: https://gist.github.com/gotev/6784c1303793c6ee9e56

Then to use self-signed certificates, just invoke:

AllCertificatesAndHostsTruster.apply();

before any network calls.

Community
  • 1
  • 1
Gunjan
  • 5
  • 1