2016-04-05 322 views
0

这个问题是我相当偏离主题和不明确的问题here的延续。Java SSL握手失败

最近我一直在使用的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上。

+0

客户端只支持一个密码套件:'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256'。 Ergo这不是真正的代码。你的阅读时间太短。注意:不要在非兼容的TrustManager实现中浪费时间。您需要在此处发布调试跟踪。 – EJP

+0

@EJP我不明白你的意思是“这不是真正的代码......”另外,你说什么意思读取超时太短?我唯一的超时是在监听套接字上设置accept()超时......另外,我希望能够有一个TrustManager将所有的证书信任为我正在构建的框架的一个选项。 –

+0

它不能是真正的代码,因为客户端只支持一个密码套件,并且在您的文章中没有密码套件设置代码。默认情况下,Java客户端将支持几十个密码套件。 '超时太短'意味着'超时太短'。半秒钟是不够的一个数量级。如果没有连接不能等待几秒钟,您还需要做什么? – EJP

回答

0

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

在监听线程,在那里我创建服务器套接字,我通过在空为SSLContext.init()keymanagers。这会导致服务器无法响应客户端,并因此导致握手错误(指向不受支持的密码套件,但实际上是由null keymanagers引起的)。使用KeyManagerFactory创建并加载KeyManager已解决该问题。

2

从调试输出它是可见的是

  • 客户端只支持一个密码:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256。由于此ciphe是TLS 1.2密码,客户端将不支持TLS 1.0或TLS 1.1。
  • 服务器回答TLS警报给ClientHello,从而结束与致命错误的握手。

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

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

+0

服务器和客户机在同一台机器上运行在同一个JDK上。这可能是IntelliJ在某种程度上限制了这一点,但我并没有在我的代码中的任何地方限制密码(据我所知)... –

+1

@ Meguy26:请检查代码之外的设置,即属性文件,命令行选项等。 –

+0

我不认为有任何。唯一的命令行选项用于调试,并且我没有以任何方式修改JDK。 –