2016-04-05 214 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。 –