2014-12-05 63 views
1

我有一個Java客戶端可能會爲同一臺服務器創建多個會話。 TLS協議具有緩存會話密鑰的功能,從而避免了每個連接的昂貴的PKI處理。但我無法讓它實際工作。如何在Java中啓用客戶端TLS會話重用

的OpenSSL的s_client.First -reconnect -state -prexit -connect本地主機:1234個 報告服務器已經 「重複使用,使用TLSv1/SSLv3的,密碼是ECDHE-RSA-AES256-SHA384」,和相同的主密鑰。

數據流是二進制的,而不是HTTP封裝。

我使用的代碼是(大約)如下。它可以工作,但不會重複使用會話。

initSSLContext(keyStore, "password", trustStore, "PKIX", "TLSv1"); 

While (true) { 

    connect(); 

    byte[] encode1 = { 0x42, 0, 0, 0, 0, 0, 0, 0, 0, }; 
    outs.write(encode1); 
    byte[] ttlbuf = new byte[10000]; 
    int len = ins.read(ttlbuf, 0, ttlbuf.length); 
    StringBuilder sb = new StringBuilder(); 
    socket.close(); 
} 

private void initSSLContext(KeyStore keyStore, String keyStorePwd, KeyStore trustStore, 
     String sslTrustManagerAlg, String sslProtocol) throws Exception { 
    KeyManager[] keyManagers = null; 

    if (keyStore != null && keyStorePwd != null) { 
     KeyManagerFactory kmf = 
      KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
     kmf.init(keyStore, keyStorePwd.toCharArray()); 
     keyManagers = kmf.getKeyManagers(); 
    } 

    TrustManager[] trustManagers = null; 
    if (trustStore != null) { 
     TrustManagerFactory tmf = TrustManagerFactory.getInstance(sslTrustManagerAlg); 
     tmf.init(trustStore); 
     trustManagers = tmf.getTrustManagers(); 
    } 

    ctx = SSLContext.getInstance(sslProtocol); 
    ctx.init(keyManagers, trustManagers, null); 

    factory = ctx.getSocketFactory(); 
} 

private void connect() throws IOException { 
    socket = (SSLSocket) factory.createSocket(host, port); 
    socket.setSoTimeout(30000); 
    // ensure first ClientHello is TLSv1 rather than SSLv2 
    socket.setEnabledProtocols(new String[] { "TLSv1" }); 
    socket.setEnabledCipherSuites(DEFAULT_SSL_CIPHER_SUITES); 
    localHost = socket.getLocalAddress().getHostAddress(); 
    localPort = socket.getLocalPort(); 
    ins = socket.getInputStream(); 
    outs = socket.getOutputStream(); 
} 
+0

說明:你想要什麼叫做會話恢復;安全重新協商是一個完全不同的功能。如果你想用'openssl s_client'檢查服務器支持,最好使用'-sess_out'然後'-sess_in',最好用'-no_ticket'來匹配Java。另外保存的數據不完全是「會話密鑰」;它是會話*主密鑰*,用於*派生*密鑰。那些人說,**它爲我**工作,代碼幾乎與你的(我默認TM算法以及KM)在香草Sun/Oracle j6,7,8相同。 ... – 2014-12-06 06:24:14

+0

...有些事情要檢查:我假設您正在重複使用/共享相同的ctx(並且您的代碼可能也是工廠)。您可以通過迭代ctx.getClientSessionContext()。getIds()來檢查會話是否緩存(初始或稍後)。另外,(全部)您的連接是否完全關閉?對於某些錯誤情況,RFC要求緩存的會話失效(丟棄),我不確定並且不能輕易測試那些JSSE實現中的哪一個。 – 2014-12-06 06:28:00

+0

默認啓用。除非每次使用新的SSLContext,否則代碼中不會有任何影響。問題可能在另一端。 – EJP 2014-12-06 07:42:39

回答