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)
ECDHE
cipher you may exactly run into the bug you have referenced in your question. For a test I would enable only one or twoRSA_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