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.
Same here. My Nginx server using sll_ecdh_curve prime384v1 setting. Unfortunately, backend guy not allowed me to configure the Nginx server following Vicky Chijwani's instructions due to Client's secirity policies. I was tried to use Valley and the latest version of the OkHttp library, but it did not help. To bypass that bug, I had to use WebView to communicate with the API Service on Adroid 7.0 devices. Here is my Adapter class. I hope someone else will find it useful.
Which means that on Android Nougat (7.0), the game for CAs changed completely. If you have your key cert, you can add a network security configuration file (if you have your cert), as described here: https://developer.android.com/training/articles/security-config.html
Or you can create your own TrustManager, as described here: https://developer.android.com/training/articles/security-ssl.html#SelfSigned
Or you can enable cipher suites that your server demands but aren't enabled by default on Android N. For example, here are two ciphers that I needed to add in my own application talking to an old Windows CE server:
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 settingssl_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:
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:
I searched for the Android Equivalent of the Cipher and added it to my Retrofit Restadapter:
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.
Here you working solution for Volley:
before you create queue in singleton codes:
and here is SSLSocketFactoryExtended:
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.