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!