2
votes

I am using Nexus 5X (API level 27) as my emulator for React Native app. I'm trying to have it connect to my java server using SSLSockets, but right after connecting it gives me error: Handshake failed

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*

For a while I thought it was using SSLv3, because of the error message, but after examining the connection in Wireshark I noticed it was actually TLSv1.2. Then I tried to enforce specific cipher suites for both server and android client without luck. Writing a custom SocketFactory class didn't help either.

I have found another question which might be related to my problem: SSLHandshakeException: Handshake failed on Android N/7.0. I'm still fairly confident that my issue has something to do with the supported cipher suites and/or elliptic-curve cryptography.

Android client code

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();

Server code

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();

The server itself works fine and can be connected from a different computer with the exact same code. It runs on openjdk 10.0.1. Same version with android. Interestingly in the release notes it says:

security-libs/javax.net.ssl 3DES Cipher Suites Disabled To improve the strength of SSL/TLS connections, 3DES cipher suites have been disabled in SSL/TLS connections in the JDK via the jdk.tls.disabledAlgorithms Security Property.

The android version is 8.1 in the emulator, I've also tested it with 7.0 on physical device. The error message is all the same. Has anyone else ever encountered this problem before?

Captured Cipher Suites

These are the cipher suites, and the confirmed TLS version, I received with the Client 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)

Followed by the Handshake Failure alert:

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)
1
As you already have set-up Wireshark you should elaborate a bit more what you have seen there. I think this is the key to understand the problem. Look especially at the CLIENT_HELLO message (TLS version, supported ciphers) and how the server reacts to this message.Robert
@Robert I compared the 65 cipher suites provided by the server and 14 suites given by my emulator. Seems that there are some common ones, like: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 for example. Forgot to mention 127.0.0.1 is not actually the address I'm using. It's a loop-back address and I figured it would be best to not post it here.Guy Fawkes
If server and client agree to use a ECDHE cipher you may exactly run into the bug you have referenced in your question. For a test I would enable only one or two RSA_WITH_AES based ciphers on client side (if the server supports them). I would also test the server side using a script like testssl.sh.Robert

1 Answers

1
votes

I got it working, at last. The problem was that I had created my keystore file with wrong algorithm. I used keytool to create a new store with -keyalg RSA and now my server is able to use common RSA ciphers with the client.