Java SSLHandshakeException "no cipher suites in common"
Having had this exception myself, I delved into the JRE source code. It became apparent that the message is rather misleading. It could mean what it says, but it more generally means that the server doesn't have the data it needs to respond to the client in the requested way. This can happen, for example, if certificates are missing from the keystore, or haven't been generated with the an appropriate algoritm. Indeed, given the cipher suites that are installed by default, one would have to go to some lengths to really get this exception because of lack of common cipher suites. In my particular case I'd generated the certificates with the default algorithm of DSA, when what I needed to get the server to work with Firefox was RSA.
You're initialising your SSLContext
with a null
KeyManager
array.
The key manager is what handles the server certificate (on the server side), and this is what you're probably aiming to set when using javax.net.ssl.keyStore
.
However, as described in the JSSE Reference Guide, using null
for the first parameter doesn't do what you seem to think it does:
If the KeyManager[] parameter is null, then an empty KeyManager will be defined for this context. If the TrustManager[] parameter is null, the installed security providers will be searched for the highest-priority implementation of the TrustManagerFactory, from which an appropriate TrustManager will be obtained. Likewise, the SecureRandom parameter may be null, in which case a default implementation will be used.
An empty KeyManager
doesn't contain any RSA or DSA certificates. Therefore, all the default cipher suites that would rely on such a certificate are disabled. This is why you get all these "Ignoring unavailable cipher suite" messages, which ultimately result in a "no cipher suites in common" message.
If you want your keystore to be used as a keystore, you'll need to load it and initialise a KeyManagerFactory with it:
KeyStore ks = KeyStore.getInstance("JKS");
InputStream ksIs = new FileInputStream("...");
try {
ks.load(ksIs, "password".toCharArray());
} finally {
if (ksIs != null) {
ksIs.close();
}
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(ks, "keypassword".toCharArray());
The use kmf.getKeyManagers()
as the first parameter to SSLContext.init()
.
For the other two parameters, since you're visibly not requesting client-certificate authentication, you should leave the trust manager to its default value (null
) instead of copying/pasting a trust manager that's a potential cause of vulnerability, and you can also use the default null
SecureRandom
.