Java SSL握手失败

时间:2016-04-05 00:04:25

标签: java sockets ssl

这个问题是我非常偏离主题且不明确的问题here的延续。

最近我一直在使用SSLSockets,无论我做什么,我都会遇到以下错误:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at com.gmail.socraticphoenix.plasma.net.client.ClientThread.run(ClientThread.java:72)

截至目前,我正在使用信任所有证书的TrustManager(用于测试目的),它看起来像这样:

public static TrustManager[] getAllTrusting() {
    return new TrustManager[]{
            new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }

                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            }
    };
}

创建侦听器套接字的代码是:

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, NetUtility.getAllTrusting(), new SecureRandom());
    SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
    SSLServerSocket socket = (SSLServerSocket) factory.createServerSocket(this.server.getPort());
    socket.setUseClientMode(false);
    socket.setSoTimeout(500);

客户端套接字的代码如下:

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, NetUtility.getAllTrusting(), new SecureRandom());
    SSLSocketFactory factory = sslContext.getSocketFactory();
    SSLSocket socket = (SSLSocket) factory.createSocket(this.client.getTargetHost(), this.client.getTargetPort());
    socket.setUseClientMode(true);
    socket.startHandshake();

我尝试过设置协议,启用和禁用会话创建以及设置密码套件。我很难过。完整的调试跟踪在pastebin上。

另外,作为一个注释,当我用常规的,不安全的套接字替换监听器和客户端代码时,test class输出预期的结果,这意味着代码就是问题所在。

TL; DR handshake_failure,请帮助!

编辑1: 为了澄清,服务器和客户端在同一台机器上运行在同一个JDK上。

2 个答案:

答案 0 :(得分:2)

从调试输出中可以看到

  • 客户端仅支持单个密码:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256。由于此ciphe是TLS 1.2密码,因此客户端不支持TLS 1.0或TLS 1.1。
  • 服务器以对ClientHello的TLS警报进行应答,从而以致命错误结束握手。

来自服务器的警报意味着它无法继续握手。确切原因不包含在警报中,但您可能会在服务器端的某些日志文件中看到它。我的猜测是服务器根本不支持客户端接受的这个单一密码。

虽然我不熟悉在Java中处理这些问题,但我建议您简单地抛弃所有代码,这些代码无效地将客户端限制为单个密码。默认情况下,Java应该支持更多的密码,从而减少问题。如果问题仍然存在,请查看服务器端以获取有关服务器不接受客户端的更多信息。

答案 1 :(得分:0)

感谢大家的帮助,但以下是我的解决方案:

在我创建服务器套接字的侦听器线程中,我在keymanagers中为SSLContext.init()传入null。这导致服务器无法响应客户端,因此导致握手错误(指向不受支持的密码套件,但实际上是由null密钥管理器引起的)。使用KeyManager创建和加载KeyManagerFactory已修复此问题。