SSL握手异常:没有共同的密码套件

9
按照这里的说明重新创建了之前错误创建的证书。现在服务器端显示javax.net.ssl.SSLHandshakeException: no cipher suites in common,客户端显示javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure。与此问题不同。
服务器是ClassFileServer.java,相应的客户端是SSLSocketClientWithClientAuth.java
有没有什么提示可以让两端玩得愉快一点,需要注意的是我正在使用本地主机,因此我认为密码能力是相同的。
更新: 以下是我用来生成文件的步骤,可能会混淆密钥和信任存储库:
在服务器上(按照这个指南): $ keytool -genkey -alias serverkey -keyalg RSA -keypass p@ssw0rd -storepass p@ssw0rd -keystore keystore.jks $ keytool -export -alias serverkey -storepass p@ssw0rd -file server.cer -keystore keystore.jks $ keytool -import -v -trustcacerts -alias clientkey -file ../client/client.cer -keystore cacerts.jks -keypass p@ssw0rd -storepass p@ssw0rd 在客户端(按照这个指南): $ keytool -genkey -alias clientkey -keyalg RSA -keypass changeit -storepass changeit -keystore keystore.jks $ keytool -export -alias clientkey -storepass changeit -file client.cer -keystore keystore.jks $ keytool -import -v -trustcacerts -alias serverkey -file ../server/server.cer -keystore cacerts.jks -keypass changeit -storepass changeit 由于调试超过了此网站的正文限制,不得不使用其他媒介。

客户端调试错误: http://pastebin.com/mHCmEqAk

服务器调试错误: http://pastebin.com/YZbh7H8f

3个回答

8
javax.net.ssl.SSLHandshakeException: no cipher suites in common

这有两个原因:
  1. 服务器没有私钥和证书,可能根本没有密钥库。在这种情况下,它只能使用不安全的匿名密码套件,默认情况下已禁用,并应该保持这种状态。因此,它无法与客户端达成一致的密码套件。

  2. 客户端或服务器强加了密码套件的过度限制,因此不能达成协议。

关于您的密钥库和信任库,除了您只需要两个导入步骤外,看起来都很好。你不需要将服务器的证书导入到服务器的信任库中,也不需要将客户端的证书导入客户端的信任库中。您只需要这样做:

服务器:

$ keytool -import -v -trustcacerts -alias clientkey -file ../client/client.cer -keystore cacerts.jks -keypass p@ssw0rd -storepass p@ssw0rd

客户端:

$ keytool -import -v -trustcacerts -alias serverkey -file ../server/server.cer -keystore cacerts.jks -keypass changeit -storepass changeit

你之所以需要它,是因为你使用了自签名证书。简单的解决方法是:不要这样做。使用受信任的CA签名证书,该证书与Java随附的默认信任存储库兼容。


我删除了多余的条目,但仍然收到相同的错误。我尝试按照这里的评论将相应的证书导入密钥库:http://stackoverflow.com/questions/9547980/unable-to-find-valid-certification-path-to-requested-target-and-certificate-unkn#comment12099962_9547980。我可能仍然混淆了信任和密钥库。另外,请注意这些是自签名证书。 - Astron
1
@Astron,(1)你是否已将代码行“ks.load(new FileInputStream(“testkeys”),passphrase)”更改为加载相应的密钥库,而不是“testkeys”,(2)你能否使用-Djavax.net.debug=ssl,handshake运行客户端,并将结果编辑到你的帖子中。 - user207421
2
客户端/服务器需要指定trustStore,因为它们正在使用默认的trustStore,导致失败。在客户端使用-Djavax.net.ssl.trustStore=/home/share/samples/sockets/client/cacerts.jks -Djavax.net.ssl.trustStorePassword=changeit,并在服务器上使用类似的代码,可以使会话完成。奇怪的是,该应用程序支持客户端身份验证,但在客户端/服务器代码中没有trustStore条款。感谢调试信息,这对我帮助很大!将调试建议添加到您的答案中。 - Astron

4
我在设置Cassandra集群的SSL时遇到了这个错误。问题出现在2.0版本的文档中描述生成密钥时:

keytool -genkey -alias -keystore .keystore

它省略了使用RSA算法的说明,应该是(请参见v1.2文档):

keytool -genkey -alias -keyalg RSA -keystore .keystore


0
作为将trustStores作为JVM参数传递的替代方案,-Djavax.net.ssl.trustStore=<cacerts_file.jks>,还可以将truststores添加到SSLContext中,然后按照以下代码片段创建SSLSocketFactory,
SSLContext ctx;
KeyManagerFactory kmf;
TrustManagerFactory tmf;
KeyStore ks;
TrustManager tm;

ctx = SSLContext.getInstance("TLS");

kmf = KeyManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(privateKey), passPhrase.toCharArray());
kmf.init(ks, passphrase);

KeyStore trustKeyStore = KeyStore.getInstance("JKS");
trustKeyStore.load(new FileInputStream(trustStore), trustPassPhrase.toCharArray());

TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance("SUNX509");
trustMgrFactory.init(trustKeyStore);

ctx.init(kmf.getKeyManagers(), trustMgrFactory.getTrustManagers(), null);

SSLSocketFactory f = (SSLSocketFactory) ctx.getSocketFactory();

SSLSocket s = (SSLSocket) f.createSocket(serverIp, serverPort);

注意:此客户端套接字同时进行客户端和服务器身份验证。如果您想禁用客户端身份验证,请在初始化 SSLContext ctx 时将 null 作为第一个参数传递。

这一切都是真的,但问题出在密钥库而不是信任库。 - user207421
@user207421,您需要为您的问题提出单独的问题。 - Vineet Menon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接