SSLHandshakeException: Android N/7.0 でハンドシェイクが失敗しました 質問する

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 です。
  • 私はボレーを使うバージョン1.0.0
  • 私は試してみましたTLSソケットファクトリーただし、何も変わりません。これは、古い SDK バージョンで SSL3 の使用を防ぐために使用されることがほとんどです。
  • 私は増やしてみましたタイムアウト、しかし何も変わりません。
  • HttpURLConnection を直接使用してみましたが、スタック トレース以外は何も変わりません (volley 参照はありませんが、それ以外は同じです)。

TLSSocketFactory がない場合、リクエストは でインスタンス化された、単なるリクエスト キューを通じて行われますVolley.newRequestQueue(context)

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

何らかの理由で SSLv3 を使用して接続しようとして失敗したとSSLV3_ALERT_HANDSHAKE_FAILUREしか考えられませんが、これはまったく意味がわかりません。暗号の問題かもしれませんが、何を使用しようとしているのかをどうやって判断すればよいでしょうか。サーバーで暗号を有効にせずに、接続を試行して繰り返したいと思います。

私の nginx サイトは let's encrypt 証明書を使用しており、次の構成になっています。

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;

これらの暗号をテストするために、私は脚本そして、次の暗号を確認します (サーバーのネットワーク外の wheezy VPS で実行)。

ECDHE-RSA-AES256-GCM-SHA384 をテストしています...はい
ECDHE-ECDSA-AES256-GCM-SHA384 をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ECDHE-RSA-AES256-SHA384 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDHE-ECDSA-AES256-SHA384 をテストしています...いいえ (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 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
DHE-RSA-AES256-GCM-SHA384 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
DHE-RSA-AES256-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
DHE-DSS-AES256-SHA256 をテストしています...いいえ (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 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ADH-AES256-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ADH-AES256-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ADH-CAMELLIA256-SHA のテスト...NO (sslv3 アラート ハンドシェイク失敗)
ECDH-RSA-AES256-GCM-SHA384 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-ECDSA-AES256-GCM-SHA384 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-RSA-AES256-SHA384 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-ECDSA-AES256-SHA384 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-RSA-AES256-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ECDH-ECDSA-AES256-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
AES256-GCM-SHA384 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
AES256-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
AES256-SHA をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
CAMELLIA256-SHA のテスト...NO (sslv3 アラート ハンドシェイク失敗)
PSK-AES256-CBC-SHA をテストしています...いいえ (利用可能な暗号はありません)
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 をテストしています...いいえ (利用可能な暗号はありません)
ECDHE-RSA-AES128-GCM-SHA256 をテストしています...はい
ECDHE-ECDSA-AES128-GCM-SHA256 をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ECDHE-RSA-AES128-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDHE-ECDSA-AES128-SHA256 をテストしています...いいえ (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 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
DHE-RSA-AES128-GCM-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
DHE-RSA-AES128-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
DHE-DSS-AES128-SHA256 をテストしています...いいえ (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 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ADH-AES128-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ADH-AES128-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ADH-SEED-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ADH-CAMELLIA128-SHA のテスト...NO (sslv3 アラート ハンドシェイク失敗)
ECDH-RSA-AES128-GCM-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-ECDSA-AES128-GCM-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-RSA-AES128-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-ECDSA-AES128-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-RSA-AES128-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ECDH-ECDSA-AES128-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
AES128-GCM-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
AES128-SHA256 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
AES128-SHA をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
SEED-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
CAMELLIA128-SHA のテスト...NO (sslv3 アラート ハンドシェイク失敗)
PSK-AES128-CBC-SHA をテストしています...いいえ (利用可能な暗号はありません)
ECDHE-RSA-RC4-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ECDHE-ECDSA-RC4-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
AECDH-RC4-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ADH-RC4-MD5 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
ECDH-RSA-RC4-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
ECDH-ECDSA-RC4-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
RC4-SHA をテストしています...NO (sslv3 アラート ハンドシェイク失敗)
RC4-MD5 をテストしています...いいえ (sslv3 アラート ハンドシェイク失敗)
PSK-RC4-SHA をテストしています...いいえ (利用可能な暗号はありません)
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 アラート ハンドシェイク失敗

できるエミュレータのブラウザでサーバー 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)

ご覧のとおり0xc02f一致0xc030していますが、次の TLSv1.2 パケットには次のように書かれていますAlert (21), Handshake Failure (40)

アップデート2:

これらは、ClientHello の Android 5.1 の曲線です。

楕円曲線(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 デバイス (General Mobile 4G) を使用する場合と同じです。

アップデート3:

小さなアップデートですが、言及する価値はあります。Android 7.1.1 (!) を使用してエミュレータで動作させることができました。次のデータが表示されます (これも tcpdump を使用して取得し、wireshark を使用して表示しました)。

楕円曲線(3つの曲線)

楕円曲線: secp256r1 (0x0017)
楕円曲線: secp384r1 (0x0018)
楕円曲線: secp512r1 (0x0019)

同じ 18 個の暗号スイートが表示されます。

ベストアンサー1

これは Android 7.0 の既知の回帰であり、Google によって認識され、Android 7.1.1 のリリース前に修正されました。バグレポートは次のとおりです:出典: google.com

明確に言うと、ここでのバグは、Cornelis が質問で指摘しているように、7.0 では 1 つの楕円曲線 (prime256v1、別名 secp256r1、別名 NIST P-256) しかサポートされていないことです。したがって、ユーザーがこの問題に直面している場合は、次の回避策を利用できます (理想的にはユーザーは Android 7.1.1 にアップグレードする必要があるという事実は無視します)。

  • 楕円曲線 を使用するようにサーバーを設定しますprime256v1。たとえば、Nginx 1.10 では を設定しますssl_ecdh_curve prime256v1;

  • それでもうまくいかない場合は、楕円曲線暗号に依存しない古い暗号スイート(例DHE-RSA-AES256-GCM-SHA384:)を使用してください(ここでデータセキュリティの観点から何をしているのかを理解していることを確認してください)。

注記:私はない楕円曲線暗号の専門家として、私の提案がセキュリティに及ぼす影響についてご自身で調査するようにしてください。この回答を書く際に参考にした他のリンクを以下に示します。

おすすめ記事