SSLHandshakeException: Handshake failed on Android N/7.0

63,736

Solution 1

This is a known regression in Android 7.0, acknowledged by Google and fixed sometime before the release of Android 7.1.1. Here is the bug report: https://code.google.com/p/android/issues/detail?id=224438.

To be clear, the bug here is that 7.0 only supports ONE elliptic curve: prime256v1 aka secp256r1 aka NIST P-256, as Cornelis points out in the question. So if your users are facing this issue, these are the workarounds available to you (ignoring the fact that your users should ideally just upgrade to Android 7.1.1):

  • Configure your server to use the elliptic curve prime256v1. For example, in Nginx 1.10 you do this by setting ssl_ecdh_curve prime256v1;.

  • If that doesn't work, use older cipher suites that don't rely on elliptic-curve cryptography (e.g., DHE-RSA-AES256-GCM-SHA384) (make sure you understand what you're doing here in terms of data security)

NOTE: I am not an expert in elliptic-curve cryptography, make sure to do your own research on the security implications of my suggestions. Here are some other links I referred to while writing this answer:

Solution 2

I had the problem with a Self Signed Certificate and the issue was in the cipher which wasn't accepted by Android 7.0

I ran: openssl s_client -showcerts -connect <domain>:<port>

in the result I found:

Protocol : TLSv1
Cipher   : DHE-RSA-AES256-SHA

I searched for the Android Equivalent of the Cipher and added it to my Retrofit Restadapter:

ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
            .tlsVersions(TlsVersion.TLS_1_2)
            .cipherSuites(

CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
            .build();

clientBuilder.connectionSpecs(Collections.singletonList(spec));

From here every connection with the correct certificate pinning or a correct certificate but with the 'wrong' cipher according to Android 7.0 was accepted.

When looking back at this answer a year later I have to admit I'm still happy I posted it, on the other hand, if you are in the position to change the certificate to the correct Cypher suite please do this always over "downgrading" te accepted suites in your app. If you have to work with a self-signed certificate (for example for embedded) this is a working solution for you.

Solution 3

I have used this to fix "javax.net.ssl.SSLHandshakeException: Handshake failed" error and working fine for Android 7.0 and others version too.

put this in onCreate() method of application class.

fun initializeSSLContext(mContext: Context) {
            try {
                SSLContext.getInstance("TLSv1.2")
            } catch (e: NoSuchAlgorithmException) {
                e.printStackTrace()
            }

            try {
                ProviderInstaller.installIfNeeded(mContext.applicationContext)
            } catch (e: GooglePlayServicesRepairableException) {
                e.printStackTrace()
            } catch (e: GooglePlayServicesNotAvailableException) {
                e.printStackTrace()
            }

        }

Solution 4

Here you working solution for Volley:

before you create queue in singleton codes:

public class VolleyServiceSingleton {

    private RequestQueue mRequestQueue;
    private HurlStack mStack;

    private VolleyServiceSingleton(){

        SSLSocketFactoryExtended factory = null;

        try {
            factory = new SSLSocketFactoryExtended();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }


        final SSLSocketFactoryExtended finalFactory = factory;
        mStack = new HurlStack() {
            @Override
            protected HttpURLConnection createConnection(URL url) throws IOException {
                HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super.createConnection(url);
                try {
                    httpsURLConnection.setSSLSocketFactory(finalFactory);
                    httpsURLConnection.setRequestProperty("charset", "utf-8");

                } catch (Exception e) {
                    e.printStackTrace();
                }
                return httpsURLConnection;
            }

        };



        mRequestQueue = Volley.newRequestQueue(YourApplication.getContext(), mStack, -1);    

    }


}

and here is SSLSocketFactoryExtended:

public class SSLSocketFactoryExtended extends SSLSocketFactory
{
    private SSLContext mSSLContext;
    private String[] mCiphers;
    private String[] mProtocols;


    public SSLSocketFactoryExtended() throws NoSuchAlgorithmException, KeyManagementException
    {
        initSSLSocketFactoryEx(null,null,null);
    }

    public String[] getDefaultCipherSuites()
    {
        return mCiphers;
    }

    public String[] getSupportedCipherSuites()
    {
        return mCiphers;
    }

    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException
    {
        SSLSocketFactory factory = mSSLContext.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(s, host, port, autoClose);

        ss.setEnabledProtocols(mProtocols);
        ss.setEnabledCipherSuites(mCiphers);

        return ss;
    }

    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException
    {
        SSLSocketFactory factory = mSSLContext.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(address, port, localAddress, localPort);

        ss.setEnabledProtocols(mProtocols);
        ss.setEnabledCipherSuites(mCiphers);

        return ss;
    }

    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException
    {
        SSLSocketFactory factory = mSSLContext.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(host, port, localHost, localPort);

        ss.setEnabledProtocols(mProtocols);
        ss.setEnabledCipherSuites(mCiphers);

        return ss;
    }

    public Socket createSocket(InetAddress host, int port) throws IOException
    {
        SSLSocketFactory factory = mSSLContext.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(host, port);

        ss.setEnabledProtocols(mProtocols);
        ss.setEnabledCipherSuites(mCiphers);

        return ss;
    }

    public Socket createSocket(String host, int port) throws IOException
    {
        SSLSocketFactory factory = mSSLContext.getSocketFactory();
        SSLSocket ss = (SSLSocket)factory.createSocket(host, port);

        ss.setEnabledProtocols(mProtocols);
        ss.setEnabledCipherSuites(mCiphers);

        return ss;
    }

    private void initSSLSocketFactoryEx(KeyManager[] km, TrustManager[] tm, SecureRandom random)
            throws NoSuchAlgorithmException, KeyManagementException
    {
        mSSLContext = SSLContext.getInstance("TLS");
        mSSLContext.init(km, tm, random);

        mProtocols = GetProtocolList();
        mCiphers = GetCipherList();
    }

    protected String[] GetProtocolList()
    {
        String[] protocols = { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
        String[] availableProtocols = null;

        SSLSocket socket = null;

        try
        {
            SSLSocketFactory factory = mSSLContext.getSocketFactory();
            socket = (SSLSocket)factory.createSocket();

            availableProtocols = socket.getSupportedProtocols();
        }
        catch(Exception e)
        {
            return new String[]{ "TLSv1" };
        }
        finally
        {
            if(socket != null)
                try {
                    socket.close();
                } catch (IOException e) {
                }
        }

        List<String> resultList = new ArrayList<String>();
        for(int i = 0; i < protocols.length; i++)
        {
            int idx = Arrays.binarySearch(availableProtocols, protocols[i]);
            if(idx >= 0)
                resultList.add(protocols[i]);
        }

        return resultList.toArray(new String[0]);
    }

    protected String[] GetCipherList()
    {
        List<String> resultList = new ArrayList<String>();
        SSLSocketFactory factory = mSSLContext.getSocketFactory();
        for(String s : factory.getSupportedCipherSuites()){
            Log.e("CipherSuite type = ",s);
            resultList.add(s);
        }
        return resultList.toArray(new String[resultList.size()]);
    }

}

in this codes I simple add all Ciphers that are supported by device, for me this works ), may be will help someone ) Cheers )

p.s. no need to add security network config parameter in manifest.

Solution 5

I spent 4 days around this problem and tried everything, the problem I had was with using LetsEncrypt (certbot etc.) to generate my certificates.

Once I switched to a different CA, Android 7.0 requests started coming through.

Share:
63,736
Cornelis
Author by

Cornelis

Updated on July 08, 2022

Comments

  • Cornelis
    Cornelis almost 2 years

    I'm working on an app for which the (power)users have to set up their own server (i.e. nginx) to run the backend application. The corresponding domain needs to be configured in the app so it can connect. I've been testing primarily on my own phone (sony z3c) and started developing for 5.1. Later I received an update for 6.0 but still maintained a working 5.1 inside the emulator. Not too long ago, I started to work on an AVD with an image for 7.0 and to my suprise it won't connect to my server, telling me the ssl handshake failed. My nginx configuration is pretty strict, but it works for both 5.1 and 6.0, so .... ?!

    Here is what I know:

    • I use v24 for support libs, i.e. my compileSdkVersion is 24.
    • I use Volley v1.0.0.
    • I've tried the TLSSocketFactory, but it doesn't change anything. This seems to be used most of the times to prevent SSL3 use for older SDK versions anyway.
    • I've tried increasing the timeout, but it doesn't change anything.
    • I've tried using HttpURLConnection directly, but it doesn't change anything apart from the stack trace (it's without the volley references, but identical otherwise).

    Without the TLSSocketFactory the request are made through a bare request queue, instantiated with Volley.newRequestQueue(context).

    This is what I see in android studio:

    W/System.err: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: Connection closed by peer
    W/System.err:     at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:151)
    W/System.err:     at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:112)
    W/System.err: Caused by: javax.net.ssl.SSLHandshakeException: Connection closed by peer
    W/System.err:     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
    W/System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)
    W/System.err:     at com.android.okhttp.Connection.connectTls(Connection.java:235)
    W/System.err:     at com.android.okhttp.Connection.connectSocket(Connection.java:199)
    W/System.err:     at com.android.okhttp.Connection.connect(Connection.java:172)
    W/System.err:     at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:367)
    W/System.err:     at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:130)
    W/System.err:     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:329)
    W/System.err:     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:246)
    W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:457)
    W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:126)
    W/System.err:     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:257)
    W/System.err:     at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
    W/System.err:     at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java)
    W/System.err:     at com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:264)
    W/System.err:     at com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:234)
    W/System.err:     at com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:107)
    W/System.err:     at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:96)
    W/System.err:   ... 1 more
    W/System.err:   Suppressed: javax.net.ssl.SSLHandshakeException: Handshake failed
    W/System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:429)
    W/System.err:       ... 17 more
    W/System.err:   Caused by: javax.net.ssl.SSLProtocolException: SSL handshake terminated: ssl=0x7ffef3748040: Failure in SSL library, usually a protocol error
    W/System.err: error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/s3_pkt.c:610 0x7ffeda1d2240:0x00000001)
    W/System.err: error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/s3_clnt.c:764 0x7ffee9d2b70a:0x00000000)
    W/System.err:     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
    W/System.err:     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)
    W/System.err:       ... 17 more
    

    Since it says SSLV3_ALERT_HANDSHAKE_FAILURE I can only assume it for some reason tries to connect using SSLv3 and fails, but this doesn't make any sense to me whatsoever. It might be a cipher-issue, but how can I tell what it is trying to use ? I would rather not enable a ciphers on the server, make a connection attempt and repeat.

    My nginx site uses a let's encrypt certificate and has the following configuration:

    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:!aNULL;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ecdh_curve secp384r1;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1.2;
    

    To test these ciphers I've a script and it confirms these ciphers (run on a wheezy vps outside the server's network):

    Testing ECDHE-RSA-AES256-GCM-SHA384...YES
    Testing ECDHE-ECDSA-AES256-GCM-SHA384...NO (sslv3 alert handshake failure)
    Testing ECDHE-RSA-AES256-SHA384...NO (sslv3 alert handshake failure)
    Testing ECDHE-ECDSA-AES256-SHA384...NO (sslv3 alert handshake failure)
    Testing ECDHE-RSA-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing ECDHE-ECDSA-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-DSS-AES-256-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-RSA-AES-256-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-AES256-GCM-SHA384...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-AES256-GCM-SHA384...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-AES256-SHA256...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-AES256-SHA256...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-CAMELLIA256-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-CAMELLIA256-SHA...NO (sslv3 alert handshake failure)
    Testing AECDH-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-AES-256-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-AES256-GCM-SHA384...NO (sslv3 alert handshake failure)
    Testing ADH-AES256-SHA256...NO (sslv3 alert handshake failure)
    Testing ADH-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-CAMELLIA256-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-AES256-GCM-SHA384...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-AES256-GCM-SHA384...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-AES256-SHA384...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-AES256-SHA384...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-AES256-SHA...NO (sslv3 alert handshake failure)
    Testing AES256-GCM-SHA384...NO (sslv3 alert handshake failure)
    Testing AES256-SHA256...NO (sslv3 alert handshake failure)
    Testing AES256-SHA...NO (sslv3 alert handshake failure)
    Testing CAMELLIA256-SHA...NO (sslv3 alert handshake failure)
    Testing PSK-AES256-CBC-SHA...NO (no ciphers available)
    Testing ECDHE-RSA-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing ECDHE-ECDSA-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-DSS-3DES-EDE-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-RSA-3DES-EDE-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing EDH-RSA-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing EDH-DSS-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing AECDH-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-3DES-EDE-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing DES-CBC3-SHA...NO (sslv3 alert handshake failure)
    Testing PSK-3DES-EDE-CBC-SHA...NO (no ciphers available)
    Testing ECDHE-RSA-AES128-GCM-SHA256...YES
    Testing ECDHE-ECDSA-AES128-GCM-SHA256...NO (sslv3 alert handshake failure)
    Testing ECDHE-RSA-AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing ECDHE-ECDSA-AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing ECDHE-RSA-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing ECDHE-ECDSA-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-DSS-AES-128-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-RSA-AES-128-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-AES128-GCM-SHA256...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-AES128-GCM-SHA256...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-SEED-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-SEED-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-RSA-CAMELLIA128-SHA...NO (sslv3 alert handshake failure)
    Testing DHE-DSS-CAMELLIA128-SHA...NO (sslv3 alert handshake failure)
    Testing AECDH-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing SRP-AES-128-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-AES128-GCM-SHA256...NO (sslv3 alert handshake failure)
    Testing ADH-AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing ADH-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-SEED-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-CAMELLIA128-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-AES128-GCM-SHA256...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-AES128-GCM-SHA256...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-AES128-SHA...NO (sslv3 alert handshake failure)
    Testing AES128-GCM-SHA256...NO (sslv3 alert handshake failure)
    Testing AES128-SHA256...NO (sslv3 alert handshake failure)
    Testing AES128-SHA...NO (sslv3 alert handshake failure)
    Testing SEED-SHA...NO (sslv3 alert handshake failure)
    Testing CAMELLIA128-SHA...NO (sslv3 alert handshake failure)
    Testing PSK-AES128-CBC-SHA...NO (no ciphers available)
    Testing ECDHE-RSA-RC4-SHA...NO (sslv3 alert handshake failure)
    Testing ECDHE-ECDSA-RC4-SHA...NO (sslv3 alert handshake failure)
    Testing AECDH-RC4-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-RC4-MD5...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-RC4-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-RC4-SHA...NO (sslv3 alert handshake failure)
    Testing RC4-SHA...NO (sslv3 alert handshake failure)
    Testing RC4-MD5...NO (sslv3 alert handshake failure)
    Testing PSK-RC4-SHA...NO (no ciphers available)
    Testing EDH-RSA-DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing EDH-DSS-DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing ADH-DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing EXP-EDH-RSA-DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing EXP-EDH-DSS-DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing EXP-ADH-DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing EXP-DES-CBC-SHA...NO (sslv3 alert handshake failure)
    Testing EXP-RC2-CBC-MD5...NO (sslv3 alert handshake failure)
    Testing EXP-ADH-RC4-MD5...NO (sslv3 alert handshake failure)
    Testing EXP-RC4-MD5...NO (sslv3 alert handshake failure)
    Testing ECDHE-RSA-NULL-SHA...NO (sslv3 alert handshake failure)
    Testing ECDHE-ECDSA-NULL-SHA...NO (sslv3 alert handshake failure)
    Testing AECDH-NULL-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-RSA-NULL-SHA...NO (sslv3 alert handshake failure)
    Testing ECDH-ECDSA-NULL-SHA...NO (sslv3 alert handshake failure)
    Testing NULL-SHA256...NO (sslv3 alert handshake failure)
    Testing NULL-SHA...NO (sslv3 alert handshake failure)
    Testing NULL-MD5...NO (sslv3 alert handshake failure
    

    I can open the server-url in the emulator's browser and get a perfect json response so I know the system itself is capable.

    So the question is, why can't I connect on Android 7 ?

    Update:

    I've looked at a captured packet using tcpdump and wireshark and the enabled ciphers are in the ClientHello, so that should not be a problem.

    Cipher Suites (18 suites)
    
    Cipher Suite: Unknown (0xcca9)
    Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
    Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
    Cipher Suite: Unknown (0xcca8)
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
    Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
    Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
    Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
    Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
    Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
    Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
    Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
    Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
    Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
    Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
    

    As you can see 0xc02f and 0xc030 match, but the next TLSv1.2 packet says: Alert (21), Handshake Failure (40).

    Update 2:

    These are the curves from Android 5.1 in the ClientHello:

    Elliptic curves (25 curves)
    
    Elliptic curve: sect571r1 (0x000e)
    Elliptic curve: sect571k1 (0x000d)
    Elliptic curve: secp521r1 (0x0019)
    Elliptic curve: sect409k1 (0x000b)
    Elliptic curve: sect409r1 (0x000c)
    Elliptic curve: secp384r1 (0x0018)
    Elliptic curve: sect283k1 (0x0009)
    Elliptic curve: sect283r1 (0x000a)
    Elliptic curve: secp256k1 (0x0016)
    Elliptic curve: secp256r1 (0x0017)
    Elliptic curve: sect239k1 (0x0008)
    Elliptic curve: sect233k1 (0x0006)
    Elliptic curve: sect233r1 (0x0007)
    Elliptic curve: secp224k1 (0x0014)
    Elliptic curve: secp224r1 (0x0015)
    Elliptic curve: sect193r1 (0x0004)
    Elliptic curve: sect193r2 (0x0005)
    Elliptic curve: secp192k1 (0x0012)
    Elliptic curve: secp192r1 (0x0013)
    Elliptic curve: sect163k1 (0x0001)
    Elliptic curve: sect163r1 (0x0002)
    Elliptic curve: sect163r2 (0x0003)
    Elliptic curve: secp160k1 (0x000f)
    Elliptic curve: secp160r1 (0x0010)
    Elliptic curve: secp160r2 (0x0011)
    

    In the ServerHello secp384r1 (0x0018) is returned.

    And this is from Android 7:

    Elliptic curves (1 curve)
    
    Elliptic curve: secp256r1 (0x0017)
    

    Resulting in the Handshake Failure.

    Changing the nginx configuration by removing secp384r1 or replacing it with the default (prime256v1) does get it to work. So I guess the question remains: am I able to add elliptic curves ?

    The captured data is the same when using the emulator as when using an Android 7.0 device (General Mobile 4G).

    Update 3:

    Small update, but worth mentioning: I got it to work in the emulator using Android 7.1.1 (!). It shows the following data (again, grabbed using tcpdump and viewed using wireshark):

    Elliptic curves (3 curves)
    
    Elliptic curve: secp256r1 (0x0017)
    Elliptic curve: secp384r1 (0x0018)
    Elliptic curve: secp512r1 (0x0019)
    

    It shows the same 18 Cipher Suites.

    • CommonsWare
      CommonsWare almost 8 years
      "I can open the server-url in the emulator's browser" -- most likely, that browser is not using Java code for the HTTP connection, so that's only a partial test. Networking, particular SSL handling, got a fairly substantial overhaul in Android 7.0 in support of the network security configuration stuff. Are you relying on user certificates (i.e., certs added by the user via Settings) by any chance?
    • Steffen Ullrich
      Steffen Ullrich almost 8 years
      I think you server config might be a bit too strict. tt allows only a single curve and only two ciphers. A packet capture of the connection and analysis in wireshark would show which ciphers and curves are offered by the client in the ClientHello so you might check if the once your servers supports are also supported by the client. Don't care too much about "sslv3 handshake failure" - you get this also when TLS 1.2 is in use because the protocol is basically the same in this area and thus it reuses functionality from sslv3 which causes strange error messages.
    • Cornelis
      Cornelis almost 8 years
      @CommonsWare: I'm not relying on user certificates, no.
    • Cornelis
      Cornelis almost 8 years
      @SteffenUllrich: I've updated my answer to include the list of cipher suites offered by the ClientHello, the ones configured are available.
    • Steffen Ullrich
      Steffen Ullrich almost 8 years
      @Cornelis: to cite myself: "... and curves" - so where are the curves?
    • Cornelis
      Cornelis almost 8 years
      @SteffenUllrich: You're right. The packet that originated from Android 7 only shows one curve in the ClientHello whereas Android 5.1 shows a list of 25 curves. See the question for the full list.
    • Cornelis
      Cornelis almost 8 years
      Removing secp384r1 from the config (or replacing it with prime256v1) does the trick to get it to work with secp256r1.
    • MaxGhost
      MaxGhost almost 8 years
      I'm running into the same issue here. Similarly to you, servers are owned by the customers and Android N broke SSL to them. The server in question is using apache2 with an EC 384 bit key. I'll keep an eye on this thread but I have nothing to offer to solve it. Looking to fix it myself. Thanks for the research above, it helped track down my issue.
    • mrAlmond
      mrAlmond almost 8 years
      I'm having a similar issue when running an app based on Qt 5.5.1 on Android 7. The ssl handshake fails. Unfortunately I can't get any log for now.
    • Mina Fawzy
      Mina Fawzy almost 8 years
      you can throw this exception NoSuchAlgorithmException, KeyManagementException
    • coyer
      coyer over 7 years
      Just ran into the same issue. Any other solutions, rather changing the server config, available?
    • ban-geoengineering
      ban-geoengineering over 7 years
    • Faruk Toptas
      Faruk Toptas almost 4 years
      I use LetsEncrypt, this solved my problem with Android7.0 : github.com/square/okhttp/issues/3648#issuecomment-336284979
  • Cornelis
    Cornelis over 7 years
    The examples in the documentation you link to are all very clear about them being related to CA/Certificate trust problems. I am able to prevent the error by changing the server's nginx configuration for ssl_ecdh_curve from secp384r1 to prime256v1 (or remove it since this is the default value for my nginx version). The SSL Certificate is therefore not the problem.
  • IgorGanapolsky
    IgorGanapolsky over 7 years
    So your problem was fixed then?
  • Cornelis
    Cornelis over 7 years
    The problem stands as is: how to get Android 7 to offer secp384r1 in its ClientHello. It works on older versions of the Android OS, soo.. why won't it work on 7 ?
  • IgorGanapolsky
    IgorGanapolsky over 7 years
    @Cornelis Quite simply because the server you are hitting doesn't support the same Cipher Suite that Android N supports. You can use Wireshark to see exactly which Cipher Suite your app is asking from the server.
  • coyer
    coyer over 7 years
    Ran into the same issue. Android < 7 could access the server while Android 7 fails with the handshake-exception. So this must be a bug in Android 7.
  • Cornelis
    Cornelis over 7 years
    The ciphers in the server config are supported out-of-the box, see the official documentation. I verified this works with wireshark (you can find the ClientHello in my question). I've also confirmed this with the output of getSupportedCipherSuites and getEnabledCipherSuites. I've yet to find a way to do all this for curves.
  • jmc34
    jmc34 over 7 years
    @Cornelis did you solve your issue, I am running into a similar one and just cannot figure it out?
  • Cornelis
    Cornelis over 7 years
    @jmc34 Unfortunately, this is still an open issue.
  • Dean Wild
    Dean Wild over 7 years
    manually adding the required cipher suite solved my issue - thanks
  • DiscDev
    DiscDev over 7 years
    This exact solution worked for us - a bunch of Galaxy S7 users on AT&T recently got the 7.0 update and it completely broke our app during a major event. Bad Google, bad.
  • Wessel van Waas
    Wessel van Waas over 7 years
    @DiskDev do I understand you right the problem is still fixed or has it broken down again after the 7.0 update from AT&T?
  • DiscDev
    DiscDev over 7 years
    Your workaround fixed the problem for us. AT&T Galaxy S7 users got the 7.0 update a week or 2 ago, and since we didn't know about this issue, it caused our app to crash at a very inopportune time for users with that device. We have another event in a week, and with your workaround (since we're using retrofit and don't want to make server-side changes to our ciphers) we are back up and running. THANK YOU!
  • Kels
    Kels about 7 years
    Has anybody got solution for above question ?
  • Vicky Chijwani
    Vicky Chijwani about 7 years
    @Kels there are no real solutions for this Android 7.0 bug, only the workarounds I listed above.
  • Kels
    Kels about 7 years
    Thanks for your reply. But when I tested in 7.1.1 and still got same error.
  • v4_adi
    v4_adi almost 7 years
    Thanks, @WesselvanWaas. You saved my day. I can't thank you enough. This is the only solution that worked.
  • rubo77
    rubo77 almost 7 years
    COOL! adding ssl_ecdh_curve prime256v1; to my /etc/nginx/snippets.d/ssl_default also worked for my matrix synapse server for Riot and Android 7!
  • 4levels
    4levels about 6 years
    Since Nginx 1.11.0 and OpenSSL 1.0.2 one can specify multiple ciphers ssl_ecdh_curve prime256v1:secp384r1; - see nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_ecdh_cur‌​ve
  • Antwan van Houdt
    Antwan van Houdt almost 6 years
    @VickyChijwani Adding here : DHE RSA GCM SHA384 is a secure cipher suite ( I don't know if its supported on 7.0 ), it only has the downside of being slower comparatively. GCM is widely considered to be much better than CBC. Some suggest prime256v1 has a backdoor, but currently not much else is supported.
  • Dziki Arbuz
    Dziki Arbuz over 2 years
    That's the only solution that worked for me, thanks :)
  • GeneCode
    GeneCode about 2 years
    pls add java version as well
  • GeneCode
    GeneCode about 2 years
    I got this eror: Local module descriptor class for com.google.android.gms.providerinstaller.dynamite not found.
  • AlexS
    AlexS about 2 years
    This not helps on Emulator 7 OS
  • AlexS
    AlexS about 2 years
    This is not works :(