【问题标题】:SSL Handshake aborted in Android EmulatorAndroid 模拟器中的 SSL 握手中止
【发布时间】:2019-01-14 09:35:47
【问题描述】:

我使用 Nexus 5X(API 级别 27)作为 React Native 应用程序的模拟器。我正在尝试使用 SSLSockets 将它连接到我的 java 服务器,但在连接后立即出现错误:握手失败

SSL handshake aborted: ssl=0x9613a1c0: Failure in SSL library, usually a protocol error
error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_HANDSHAKE_FAILURE (external/boringssl/src/ssl/tls_record.cc:579 0x9679afc0:0x00000001)
error:1000009a:SSL routines:OPENSSL_internal:HANDSHAKE_FAILURE_ON_CLIENT_HELLO (external/boringssl/src/ssl/handshake_client.cc:893 0xa43b3dc3:0x00000000)
invoke        JavaMethodWrapper.java:383
invoke        JavaModuleWrapper.java:160
run        NativeRunnable.java
handleCallback        Handler.java:790
dispatchMessage        Handler.java:99
dispatchMessage        MessageQueueThreadHandler.java:29
loop        Looper.java:164
run        MessageQueueThreadImpl.java:192
run        Thread.java:764*

由于错误消息,有一段时间我认为它使用的是 SSLv3,但在检查 Wireshark 中的连接后,我注意到它实际上是 TLSv1.2。然后我尝试为服务器和android客户端强制执行特定的密码套件,但没有运气。编写自定义 SocketFactory 类也没有帮助。

我发现了另一个可能与我的问题有关的问题:SSLHandshakeException: Handshake failed on Android N/7.0。我仍然相当确信我的问题与受支持的密码套件和/或椭圆曲线密码学有关。

Android 客户端代码

SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket connection = (SSLSocket) factory.createSocket("127.0.0.1", 4192);

connection.setEnabledProtocols(new String[]{"TLSv1.1", "TLSv1.2"});
connection.setUseClientMode(true);

DataOutputStream output = new DataOutputStream(connection.getOutputStream());
DataInputStream input = new DataInputStream(connection.getInputStream());

String[] cipher_suites = connection.getSupportedCipherSuites();
connection.setEnabledCipherSuites(cipher_suites);

connection.startHandshake();

服务器代码

SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket server = (SSLServerSocket) factory.createServerSocket(4192, 1);

SSLSocket connection = (SSLSocket) server.accept();

DataInputStream input = new DataInputStream(connection.getInputStream());
DataOutputStream output = new DataOutputStream(connection.getOutputStream());

connection.setEnabledProtocols(new String[]{"TLSv1.1", "TLSv1.2"});

String[] cipher_suites = connection.getSupportedCipherSuites();
connection.setEnabledCipherSuites(cipher_suites);

connection.startHandshake();

服务器本身工作正常,可以使用完全相同的代码从另一台计算机连接。它在 openjdk 10.0.1 上运行。与安卓版本相同。有趣的是,它在发行说明中写道:

安全库/javax.net.ssl 3DES 密码套件已禁用 为了提高 SSL/TLS 连接的强度,已通过 jdk.tls.disabledAlgorithms 安全属性在 JDK 中的 SSL/TLS 连接中禁用 3DES 密码套件。

模拟器中的android版本是8.1,我也在物理设备上用7.0测试过。错误信息都是一样的。有没有其他人遇到过这个问题?

捕获的密码套件

这些是密码套件,以及确认的 TLS 版本,我收到了客户端 Hello

Version: TLS 1.2 (0x0303)
Cipher Suites (14 suites)
    Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (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: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (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_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_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)

随后是握手失败警报:

TLSv1.2 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
    Content Type: Alert (21)
    Version: TLS 1.2 (0x0303)
    Length: 2
    Alert Message
        Level: Fatal (2)
        Description: Handshake Failure (40)

【问题讨论】:

  • 由于您已经设置了 Wireshark,您应该详细说明您在那里看到的内容。我认为这是理解问题的关键。尤其要查看 CLIENT_HELLO 消息(TLS 版本,支持的密码)以及服务器对此消息的反应。
  • @Robert 我比较了服务器提供的 65 个密码套件和我的模拟器提供的 14 个密码套件。似乎有一些常见的,例如: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 。忘了提 127.0.0.1 实际上不是我使用的地址。这是一个环回地址,我认为最好不要在此处发布。
  • 如果服务器和客户端同意使用ECDHE 密码,您可能会遇到您在问题中引用的错误。对于测试,我将在客户端仅启用一个或两个基于 RSA_WITH_AES 的密码(如果服务器支持它们)。我还将使用testssl.sh 之类的脚本测试服务器端。

标签: java android ssl


【解决方案1】:

我终于让它工作了。问题是我用错误的算法创建了我的密钥库文件。我使用 keytool 创建了一个带有 -keyalg RSA 的新商店,现在我的服务器可以在客户端使用常见的 RSA 密码。

【讨论】:

    猜你喜欢
    • 2016-04-02
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    相关资源
    最近更新 更多