如何在Java中启用客户端TLS会话重用
问题描述:
我有一个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();
}
说明:你想要什么叫做会话恢复;安全重新协商是一个完全不同的功能。如果你想用'openssl s_client'检查服务器支持,最好使用'-sess_out'然后'-sess_in',最好用'-no_ticket'来匹配Java。另外保存的数据不完全是“会话密钥”;它是会话*主密钥*,用于*派生*密钥。那些人说,**它为我**工作,代码几乎与你的(我默认TM算法以及KM)在香草Sun/Oracle j6,7,8相同。 ... – 2014-12-06 06:24:14
...有些事情要检查:我假设您正在重复使用/共享相同的ctx(并且您的代码可能也是工厂)。您可以通过迭代ctx.getClientSessionContext()。getIds()来检查会话是否缓存(初始或稍后)。另外,(全部)您的连接是否完全关闭?对于某些错误情况,RFC要求缓存的会话失效(丢弃),我不确定并且不能轻易测试那些JSSE实现中的哪一个。 – 2014-12-06 06:28:00
默认启用。除非每次使用新的SSLContext,否则代码中不会有任何影响。问题可能在另一端。 – EJP 2014-12-06 07:42:39