SSLHandshakeException:Android N/7.0 上的握手失败 [英] SSLHandshakeException: Handshake failed on Android N/7.0

查看:36
本文介绍了SSLHandshakeException:Android N/7.0 上的握手失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个应用程序,(高级)用户必须为其设置自己的服务器(即 nginx)来运行后端应用程序.需要在应用程序中配置相应的域才能连接.我一直主要在我自己的手机(sony z3c)上进行测试,并开始为 5.1 开发.后来我收到了 6.0 的更新,但仍然在模拟器内保持了一个有效的 5.1.不久前,我开始使用 7.0 的图像处理 AVD,令我惊讶的是它无法连接到我的服务器,告诉我 ssl 握手失败.我的 nginx 配置非常严格,但它适用于 5.1 和 6.0,所以......?!

这是我所知道的:

  • 我使用 v24 作为支持库,即我的 compileSdkVersion 是 24.
  • 我使用 Volley v1.0.0.
  • 我已经尝试了 TLSSocketFactory,但它没有任何改变.这似乎在大多数情况下都被用来防止旧版 SDK 使用 SSL3.
  • 我试过增加超时,但它不会改变任何东西.
  • 我试过直接使用 HttpURLConnection,但它除了堆栈跟踪之外没有任何改变(它没有 volley 引用,但其他方面完全相同).

如果没有 TLSSocketFactory,请求是通过一个裸请求队列发出的,用 Volley.newRequestQueue(context) 实例化.

这是我在 android studio 中看到的:

W/System.err: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: Connection closed by peerW/System.err: 在 com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:151)W/System.err: 在 com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:112)W/System.err: 引起: javax.net.ssl.SSLHandshakeException: Connection closed by peerW/System.err: 在 com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)W/System.err: 在 com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)W/System.err: 在 com.android.okhttp.Connection.connectTls(Connection.java:235)W/System.err: 在 com.android.okhttp.Connection.connectSocket(Connection.java:199)W/System.err: 在 com.android.okhttp.Connection.connect(Connection.java:172)W/System.err: 在 com.android.okhttp.Connection.connectAndSetOwner(Connection.java:367)W/System.err: 在 com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:130)W/System.err: 在 com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:329)W/System.err: 在 com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:246)W/System.err: 在 com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:457)W/System.err: 在 com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:126)W/System.err: 在 com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:257)W/System.err: 在 com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)W/System.err: 在 com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java)W/System.err: 在 com.android.volley.toolbox.HurlStack.addBodyIfExists(HurlStack.java:264)W/System.err: 在 com.android.volley.toolbox.HurlStack.setConnectionParametersForRequest(HurlStack.java:234)W/System.err: 在 com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:107)W/System.err: 在 com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:96)W/System.err: ... 1 更多W/System.err: Suppressed: javax.net.ssl.SSLHandshakeException: Handshake failedW/System.err: 在 com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:429)W/System.err: ... 17 更多W/System.err:由:javax.net.ssl.SSLProtocolException:SSL 握手终止:ssl=0x7ffef3748040:SSL 库失败,通常是协议错误W/System.err: 错误:10000410:SSL 例程:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/s3_pkt.c:610 0x7ffeda1d2240:0x00000001)W/System.err: 错误:1000009a:SSL 例程:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/s3_clnt.c:764 0x7ffee9d2b70a:0x00000000)W/System.err: 在 com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)W/System.err: 在 com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)W/System.err: ... 17 更多

因为它说 SSLV3_ALERT_HANDSHAKE_FAILURE 我只能假设它出于某种原因尝试使用 SSLv3 连接并失败,但这对我来说没有任何意义.这可能是一个密码问题,但我怎么知道它试图使用什么?我宁愿不在服务器上启用密码,尝试连接并重复.

我的 nginx 站点使用了一个让我们加密的证书,并具有以下配置:

ssl_stapling on;ssl_stapling_verify 开启;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 开启;ssl_protocols TLSv1.2;

为了测试这些密码,我有一个 脚本 并且它确认了这些密码(在服务器网络外的喘息 vps 上运行):

<前>测试 ECDHE-RSA-AES256-GCM-SHA384...是测试 ECDHE-ECDSA-AES256-GCM-SHA384...NO(sslv3 警报握手失败)测试 ECDHE-RSA-AES256-SHA384...NO(sslv3 警报握手失败)测试 ECDHE-ECDSA-AES256-SHA384...NO(sslv3 警报握手失败)测试 ECDHE-RSA-AES256-SHA...NO(sslv3 警报握手失败)测试 ECDHE-ECDSA-AES256-SHA...NO(sslv3 警报握手失败)测试 SRP-DSS-AES-256-CBC-SHA...NO(sslv3 警报握手失败)测试 SRP-RSA-AES-256-CBC-SHA...NO(sslv3 警报握手失败)测试 DHE-DSS-AES256-GCM-SHA384...NO(sslv3 警报握手失败)测试 DHE-RSA-AES256-GCM-SHA384...NO(sslv3 警报握手失败)测试 DHE-RSA-AES256-SHA256...NO(sslv3 警报握手失败)测试 DHE-DSS-AES256-SHA256...NO(sslv3 警报握手失败)测试 DHE-RSA-AES256-SHA...NO(sslv3 警报握手失败)测试 DHE-DSS-AES256-SHA...NO(sslv3 警报握手失败)测试 DHE-RSA-CAMELLIA256-SHA...NO(sslv3 警报握手失败)测试 DHE-DSS-CAMELLIA256-SHA...NO(sslv3 警报握手失败)测试 AECDH-AES256-SHA...NO(sslv3 警报握手失败)测试 SRP-AES-256-CBC-SHA...NO(sslv3 警报握手失败)测试 ADH-AES256-GCM-SHA384...NO(sslv3 警报握手失败)测试 ADH-AES256-SHA256...NO(sslv3 警报握手失败)测试 ADH-AES256-SHA...NO(sslv3 警报握手失败)测试 ADH-CAMELLIA256-SHA...NO(sslv3 警报握手失败)测试 ECDH-RSA-AES256-GCM-SHA384...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-AES256-GCM-SHA384...NO(sslv3 警报握手失败)测试 ECDH-RSA-AES256-SHA384...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-AES256-SHA384...NO(sslv3 警报握手失败)测试 ECDH-RSA-AES256-SHA...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-AES256-SHA...NO(sslv3 警报握手失败)测试 AES256-GCM-SHA384...NO(sslv3 警报握手失败)测试 AES256-SHA256...NO(sslv3 警报握手失败)测试 AES256-SHA...NO(sslv3 警报握手失败)测试 CAMELLIA256-SHA...NO(sslv3 警报握手失败)测试 PSK-AES256-CBC-SHA...NO(没有可用的密码)测试 ECDHE-RSA-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 ECDHE-ECDSA-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 SRP-DSS-3DES-EDE-CBC-SHA...NO(sslv3 警报握手失败)测试 SRP-RSA-3DES-EDE-CBC-SHA...NO(sslv3 警报握手失败)测试 EDH-RSA-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 EDH-DSS-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 AECDH-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 SRP-3DES-EDE-CBC-SHA...NO(sslv3 警报握手失败)测试 ADH-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 ECDH-RSA-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 DES-CBC3-SHA...NO(sslv3 警报握手失败)测试 PSK-3DES-EDE-CBC-SHA...NO(没有可用的密码)测试 ECDHE-RSA-AES128-GCM-SHA256...是测试 ECDHE-ECDSA-AES128-GCM-SHA256...NO(sslv3 警报握手失败)测试 ECDHE-RSA-AES128-SHA256...NO(sslv3 警报握手失败)测试 ECDHE-ECDSA-AES128-SHA256...NO(sslv3 警报握手失败)测试 ECDHE-RSA-AES128-SHA...NO(sslv3 警报握手失败)测试 ECDHE-ECDSA-AES128-SHA...NO(sslv3 警报握手失败)测试 SRP-DSS-AES-128-CBC-SHA...NO(sslv3 警报握手失败)测试 SRP-RSA-AES-128-CBC-SHA...NO(sslv3 警报握手失败)测试 DHE-DSS-AES128-GCM-SHA256...NO(sslv3 警报握手失败)测试 DHE-RSA-AES128-GCM-SHA256...NO(sslv3 警报握手失败)测试 DHE-RSA-AES128-SHA256...NO(sslv3 警报握手失败)测试 DHE-DSS-AES128-SHA256...NO(sslv3 警报握手失败)测试 DHE-RSA-AES128-SHA...NO(sslv3 警报握手失败)测试 DHE-DSS-AES128-SHA...NO(sslv3 警报握手失败)测试 DHE-RSA-SEED-SHA...NO(sslv3 警报握手失败)测试 DHE-DSS-SEED-SHA...NO(sslv3 警报握手失败)测试 DHE-RSA-CAMELLIA128-SHA...NO(sslv3 警报握手失败)测试 DHE-DSS-CAMELLIA128-SHA...NO(sslv3 警报握手失败)测试 AECDH-AES128-SHA...NO(sslv3 警报握手失败)测试 SRP-AES-128-CBC-SHA...NO(sslv3 警报握手失败)测试 ADH-AES128-GCM-SHA256...NO(sslv3 警报握手失败)测试 ADH-AES128-SHA256...NO(sslv3 警报握手失败)测试 ADH-AES128-SHA...NO(sslv3 警报握手失败)测试 ADH-SEED-SHA...NO(sslv3 警报握手失败)测试 ADH-CAMELLIA128-SHA...NO(sslv3 警报握手失败)测试 ECDH-RSA-AES128-GCM-SHA256...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-AES128-GCM-SHA256...NO(sslv3 警报握手失败)测试 ECDH-RSA-AES128-SHA256...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-AES128-SHA256...NO(sslv3 警报握手失败)测试 ECDH-RSA-AES128-SHA...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-AES128-SHA...NO(sslv3 警报握手失败)测试 AES128-GCM-SHA256...NO(sslv3 警报握手失败)测试 AES128-SHA256...NO(sslv3 警报握手失败)测试 AES128-SHA...NO(sslv3 警报握手失败)测试 SEED-SHA...NO(sslv3 警报握手失败)测试 CAMELLIA128-SHA...NO(sslv3 警报握手失败)测试 PSK-AES128-CBC-SHA...NO(没有可用的密码)测试 ECDHE-RSA-RC4-SHA...NO(sslv3 警报握手失败)测试 ECDHE-ECDSA-RC4-SHA...NO(sslv3 警报握手失败)测试 AECDH-RC4-SHA...NO(sslv3 警报握手失败)测试 ADH-RC4-MD5...NO(sslv3 警报握手失败)测试 ECDH-RSA-RC4-SHA...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-RC4-SHA...NO(sslv3 警报握手失败)测试 RC4-SHA...NO(sslv3 警报握手失败)测试 RC4-MD5...NO(sslv3 警报握手失败)测试 PSK-RC4-SHA...NO(没有可用的密码)测试 EDH-RSA-DES-CBC-SHA...NO(sslv3 警报握手失败)测试 EDH-DSS-DES-CBC-SHA...NO(sslv3 警报握手失败)测试 ADH-DES-CBC-SHA...NO(sslv3 警报握手失败)测试 DES-CBC-SHA...NO(sslv3 警报握手失败)测试 EXP-EDH-RSA-DES-CBC-SHA...NO(sslv3 警报握手失败)测试 EXP-EDH-DSS-DES-CBC-SHA...NO(sslv3 警报握手失败)测试 EXP-ADH-DES-CBC-SHA...NO(sslv3 警报握手失败)测试 EXP-DES-CBC-SHA...NO(sslv3 警报握手失败)测试 EXP-RC2-CBC-MD5...NO(sslv3 警报握手失败)测试 EXP-ADH-RC4-MD5...NO(sslv3 警报握手失败)测试 EXP-RC4-MD5...NO(sslv3 警报握手失败)测试 ECDHE-RSA-NULL-SHA...NO(sslv3 警报握手失败)测试 ECDHE-ECDSA-NULL-SHA...NO(sslv3 警报握手失败)测试 AECDH-NULL-SHA...NO(sslv3 警报握手失败)测试 ECDH-RSA-NULL-SHA...NO(sslv3 警报握手失败)测试 ECDH-ECDSA-NULL-SHA...NO(sslv3 警报握手失败)测试 NULL-SHA256...NO(sslv3 警报握手失败)测试 NULL-SHA...NO(sslv3 警报握手失败)测试 NULL-MD5...NO(sslv3 警报握手失败

可以在模拟器的浏览器中打开 server-url 并获得完美的 json 响应,所以我知道系统本身是有能力的.

那么问题是,为什么我无法在 Android 7 上连接?

更新:

我已经使用 tcpdump 和 wireshark 查看了捕获的数据包,并且启用的密码在 ClientHello 中,所以这应该不是问题.

<前>密码套房(18套房)密码套件:未知 (0xcca9)密码套件:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)密码套件:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)密码套件:未知 (0xcca8)密码套件:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)密码套件:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)密码套件:TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)密码套件:TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)密码套件:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)密码套件:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)密码套件:TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)密码套件:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)密码套件:TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)密码套件:TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)密码套件:TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)密码套件:TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)密码套件:TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)密码套件:TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)

如您所见,0xc02f0xc030 匹配,但下一个 TLSv1.2 数据包显示:Alert (21), Handshake Failure (40).

更新 2:

这些是来自 Android 5.1 的 ClientHello 中的曲线:

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

在ServerHello中返回secp384r1 (0x0018).

这是来自 Android 7:

<前>椭圆曲线(1 条曲线)椭圆曲线:secp256r1 (0x0017)

导致握手失败.

通过删除 secp384r1 或将其替换为默认值 (prime256v1) 来更改 nginx 配置确实可以使其正常工作.所以我想问题仍然存在:我可以添加椭圆曲线吗?

使用模拟器时捕获的数据与使用 Android 7.0 设备(通用移动 4G)时相同.

更新 3:

小更新,但值得一提:我让它在使用 Android 7.1.1 (!) 的模拟器中运行.它显示了以下数据(再次使用 tcpdump 抓取并使用 wireshark 查看):

<前>椭圆曲线(3条曲线)椭圆曲线:secp256r1 (0x0017)椭圆曲线:secp384r1 (0x0018)椭圆曲线:secp512r1 (0x0019)

它显示了相同的 18 个密码套件.

解决方案

这是 Android 7.0 中的一个已知回归,谷歌承认并在 Android 7.1.1 发布之前的某个时间修复. 这里是错误报告:https://code.google.com/p/android/issues/detail?id=224438.

需要明确的是,这里的错误是 7.0 仅支持一条椭圆曲线:prime256v1 aka secp256r1 aka NIST P-256,正如 Cornelis 在问题中指出的那样.因此,如果您的用户遇到此问题,您可以使用以下解决方法(忽略您的用户最好只升级到 Android 7.1.1 的事实):

  • 配置您的服务器以使用椭圆曲线prime256v1.例如,在 Nginx 1.10 中,您可以通过设置 ssl_ecdh_curve prime256v1; 来做到这一点.

  • 如果这不起作用,请使用不依赖椭圆曲线加密的旧密码套件(例如,DHE-RSA-AES256-GCM-SHA384)(确保您了解自己在数据安全方面所做的工作)

注意:不是椭圆曲线密码学方面的专家,请务必自行研究我的建议对安全性的影响.以下是我在撰写此答案时参考的其他一些链接:

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.

解决方案

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:

这篇关于SSLHandshakeException:Android N/7.0 上的握手失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆