How can I fix javax.net.ssl.SSLHandshakeException: no cipher suites in common?

1

I know that there are many similar threads out there, but none of the solutions presented in these threads helped me, so here comes another one.

I've an Android client communicating with a Java server. I want the communication to be secure so I use SSL. However, the handshake fails with the following error:

From logcat:

03-28 03:31:30.171: W/System.err(1214): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb81201c8: Failure in SSL library, usually a protocol error
03-28 03:31:30.171: W/System.err(1214): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0xad3cdd5c:0x00000000)
03-28 03:31:30.181: W/System.err(1214):     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)
03-28 03:31:30.181: W/System.err(1214):     at com.myapp.ServerCon.getSecureSocket(ServerCon.java:362)
03-28 03:31:30.181: W/System.err(1214):     at com.myapp.ServerCon.access$0(ServerCon.java:310)
03-28 03:31:30.181: W/System.err(1214):     at com.myapp.ServerCon$1.doInBackground(ServerCon.java:283)
03-28 03:31:30.181: W/System.err(1214):     at com.myapp.ServerCon$1.doInBackground(ServerCon.java:1)
03-28 03:31:30.191: W/System.err(1214):     at android.os.AsyncTask$2.call(AsyncTask.java:288)
03-28 03:31:30.191: W/System.err(1214):     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-28 03:31:30.191: W/System.err(1214):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
03-28 03:31:30.191: W/System.err(1214):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
03-28 03:31:30.191: W/System.err(1214):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
03-28 03:31:30.191: W/System.err(1214):     at java.lang.Thread.run(Thread.java:841)
03-28 03:31:30.191: W/System.err(1214): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb81201c8: Failure in SSL library, usually a protocol error
03-28 03:31:30.191: W/System.err(1214): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0xad3cdd5c:0x00000000)
03-28 03:31:30.191: W/System.err(1214):     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
03-28 03:31:30.191: W/System.err(1214):     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
03-28 03:31:30.191: W/System.err(1214):     ... 10 more

On the server with java -Djavax.net.debug=ssl,handshake -jar myserver.jar:

adding as trusted cert:
  Subject: EMAILADDRESS=mymail@ex.com, CN=myname, L=Stockholm, C=SV
  Issuer:  EMAILADDRESS=mymail@ex.com, CN=myname, L=Stockholm, C=SV
  Algorithm: RSA; Serial number: 0xe63fe3941be0b4a5
  Valid from Tue Mar 25 11:40:58 CET 2014 until Wed Mar 25 11:40:58 CET 2015

trigger seeding of SecureRandom
done seeding SecureRandom

Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
    Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for SSLv2Hello
    Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for SSLv2Hello
    Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for SSLv2Hello
    Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 for SSLv2Hello
    Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 for SSLv2Hello

Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for SSLv2Hello
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for SSLv2Hello
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for SSLv3
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 for SSLv3
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for SSLv3
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for TLSv1.1
Thread-1, READ: TLSv1 Handshake, length = 179
*** ClientHello, TLSv1
RandomCookie:  GMT: 1395989998 bytes = { 111, 250, 184, 147, 57, 151, 111, 1, 186, 199, 20, 220, 158, 177, 180, 53, 61, 151, 68, 38, 40, 140, 252, 173, 103, 147, 144, 88 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension ec_point_formats, formats: [uncompressed, ansiX962_compressed_prime, ansiX962_compressed_char2]
Extension elliptic_curves, curve names: {sect571r1, sect571k1, secp521r1, sect409k1, sect409r1, secp384r1, sect283k1, sect283r1, secp256k1, secp256r1, sect239k1, sect233k1, sect233r1, secp224k1, secp224r1, sect193r1, sect193r2, secp192k1, secp192r1, sect163k1, sect163r1, sect163r2, secp160k1, secp160r1, secp160r2}
***
%% Initialized:  [Session-1, SSL_NULL_WITH_NULL_NULL]
%% Invalidated:  [Session-1, SSL_NULL_WITH_NULL_NULL]
Thread-1, SEND TLSv1 ALERT:  fatal, description = handshake_failure
Thread-1, WRITE: TLSv1 Alert, length = 2
Thread-1, called closeSocket()
Thread-1, handling exception: javax.net.ssl.SSLHandshakeException: no cipher suites in common
javax.net.ssl.SSLHandshakeException: no cipher suites in common
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:266)
        at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:894)
        at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:622)
        at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:167)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
        at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:882)
        at sun.security.ssl.AppInputStream.read(AppInputStream.java:102)
        at java.io.InputStream.read(InputStream.java:101)
        at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1792)
        at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1769)
        at org.apache.commons.io.IOUtils.copy(IOUtils.java:1744)
        at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:462)
        at com.myserver.Listener$ListenerThread.run(Listener.java:88)

The client code:

private static SSLSocket getSecureSocket() throws IOException {
    if (sslSocketFactory == null) {
        try {

            KeyStore truststore = KeyStore.getInstance("BKS");
            truststore.load(mTruststoreInputStream, STORES_PASSWORD.toCharArray());

            TrustManagerFactory trustManagerFactory = TrustManagerFactory.
                    getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(truststore);

            KeyStore keystore = KeyStore.getInstance("BKS");
            keystore.load(mKeystoreInputStream, STORES_PASSWORD.toCharArray());

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.
                    getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keystore, STORES_PASSWORD.toCharArray());


            sslSocketFactory = new SSLSocketFactory(SSLSocketFactory.TLS, 
                    keystore, STORES_PASSWORD, truststore, null, null);
        } catch (KeyStoreException e) {
            e.printStackTrace();
            return null;
        } catch (CertificateException e ) {
            e.printStackTrace();
            return null;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
            return null;
            } catch (KeyManagementException e) {
                e.printStackTrace();
                return null;
            }

            }
    SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket();
            Log.d(TAG, "Trying to connect socket to " + IP + " on port " + PORT + ".");
            socket.connect(new InetSocketAddress(IP, PORT));
            return socket;
public static void test() {
        new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... arg0) {
                try {
                    SSLSocket socket = getSecureSocket();
                    OutputStream os = socket.getOutputStream();
                    String data = "A big step for man, a small step for mankind";
                    byte[] bytes = data.getBytes();
                    os.write(bytes);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }

        }.execute();
    }

The server code:

public SSLServerSocket createServerSocket() {
        try {
            KeyStore keystore = KeyStore.getInstance("JKS");
            FileInputStream keystoreInputStream = new FileInputStream(KEYSTORE_NAME);
            keystore.load(keystoreInputStream, STORES_PASSWORD.toCharArray());
            KeyStore truststore = KeyStore.getInstance("JKS");
            FileInputStream truststoreInputStream = new FileInputStream(TRUSTSTORE_NAME);
            truststore.load(truststoreInputStream, STORES_PASSWORD.toCharArray());
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
            trustManagerFactory.init(truststore);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
            keyManagerFactory.init(keystore, STORES_PASSWORD.toCharArray());
            X509ExtendedKeyManager x509KeyManager = null;
            for (KeyManager keyManager : keyManagerFactory.getKeyManagers()) {
                if (keyManager instanceof X509KeyManager) {
                    x509KeyManager = (X509ExtendedKeyManager) keyManager;
                    break;
                }
            }
            if (x509KeyManager == null) {
                debug("Searched for x509 key managers but found none.");
                throw new NullPointerException();
            }
            X509ExtendedTrustManager x509TrustManager = null;
            for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
                if (trustManager instanceof X509TrustManager) {
                    x509TrustManager = (X509ExtendedTrustManager) trustManager;
                }
            }
            if (x509TrustManager == null) {
                debug("Searched for x509 trust managers but found none.");
                throw new NullPointerException();
            }
            SSLContext sslContext = SSLContext.getInstance("TLS");
            KeyManager[] keyManagers = { x509KeyManager };
            TrustManager[] trustManagers = { x509TrustManager };
            sslContext.init(keyManagers, trustManagers, null);
            SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory();
            SSLServerSocket serverSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(PORT);
            serverSocket.setNeedClientAuth(true);
            /* Force TLS 1.0, this will disable i.e SSL2 which is insecure. */
            //serverSocket.setEnabledProtocols(new String[] { "TLSv1" });
            return serverSocket;
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return null;
    }

while (true) {
    try {
        debug("Listening for incoming connections...");
        SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
        // Handle connection in a separate thread.
        ListenerThread thread = new ListenerThread(clientSocket);
        thread.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

I generated my certificates as follows:

Generated my keys with openssl:

openssl genrsa -des3 -out client_key.pem 4096
openssl genrsa -des3 -out client_key.pem 4096

CSR:

openssl req -new -x509 -key client_key.pem -out client_cert.pem -days 365
openssl req -new -x509 -key server_key.pem -out server_cert.pem -days 365

Used portecle to convert to bks. First, opened portecle and created a new bks-file. Imported server_cert.pem and saved as truststore.bks. Next, combined the client cert and keyfile

cat client_cert.pem client_key.pem > client.pem

Used openssl to generate a pkcs12-file

openssl pkcs12 -export -in client.pem -out client.pkcs12 -name "client"

Created a new bks-file in portecle. Imported client.pkcs12 and saved as client.bks (this is my server keystore).

These two files were imported into the Android project and loaded from /res/raw

Server certs were created in the same way, but I used portecle to export as jks instead. The server keystore contains the server.pkcs12 and the server truststore contains the client certificate (client_cert.pem).

Any help would be greatly appreciated!

java
android
ssl
asked on Stack Overflow Mar 28, 2014 by user1938742 • edited Mar 28, 2014 by user1938742

1 Answer

0

This can only happen if:

  • there is no private key available at the server, or
  • one end or the other changes the enabled cipher suites. The simple solution is not to do that.

Using the same file as both the keystore and the truststore doesn't begin to make sense. One contains private information, the other public. They don't mix.

Your client code can't possibly work beyond the first SSLSocket created, as it will try to load keystores and truststores from input streams that have already been read. You should have a single method, called once, to create a single SSLContext, and then get your SSLSockets directly from that.

answered on Stack Overflow Mar 29, 2014 by user207421 • edited Aug 7, 2016 by user207421

User contributions licensed under CC BY-SA 3.0