3

I have a Java client that may create many sessions to the same server. The TLS protocol has a facility to cache session keys and thus avoid the expensive PKI processing for each connection. But I cannot get it to actually work.

openssl s_client -reconnect -state -prexit -connect localhost:1234 Reports that the server has "Reused, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA384", and same master keys.

The data stream is binary, not HTTP encapsulated.

The code that I use is (approx.) as follows. It works, but no session reuse.

    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();
 }
Tuntable
  • 3,276
  • 1
  • 21
  • 26
  • Clarification: what you want is called Session Resumption; Secure Renegotiation is a completely different feature. If you want to check server support with `openssl s_client` use `-sess_out` then `-sess_in` preferably with `-no_ticket` to match Java. Also the saved data isn't exactly "session keys"; it is the session *master secret* which is used to *derive* keys. Those said, **IT DOES WORK FOR ME** with code almost identical to yours (I default TM algo as well as KM) on vanilla Sun/Oracle j6,7,8. ... – dave_thompson_085 Dec 06 '14 at 06:24
  • ... Some things to check: I assume you are reusing/sharing the same ctx (and with your code probably factory also). You can check sessions are cached (initially or later) by iterating over ctx.getClientSessionContext().getIds() . Also, are (all) your connections closed cleanly? The RFCs require cached sessions be invalidated (discarded) for some error cases, and I'm not sure and can't easily test which of those JSSE implements. – dave_thompson_085 Dec 06 '14 at 06:28
  • It's enabled by default. There's nothing in your code that would affect that, unless you're using a new SSLContext every time. The problem is probably at the other end. – user207421 Dec 06 '14 at 07:42
  • @dave_thompson_085, thanks for that, the critical line was "Reused, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA384". I had used getClientSessionContext(), seems to be losing IDs. All connections are closed with socket.close(), (not stream.close()). – Tuntable Dec 07 '14 at 05:54
  • P.S. openssl s_client also had same master keys. Also with your -sess_out/in. -no_ticket for good measure. – Tuntable Dec 07 '14 at 06:06
  • @aberglas What are you talking about? 'getClientSessionContext()` does not appear in your question. What evidence do you actually have that sessions aren't being resumed? – user207421 Dec 07 '14 at 08:53
  • It's not only calling socket.close(), but no protocol error has occurred previously (which might not always throw an exception) and the shutdown protocol has no error either (which the API *can't* indicate). That said, on modern systems protocol errors are not common. Cached sessions *do* expire after some time, but this defaults to 1 day and you don't change it, and I doubt your test runs that long. – dave_thompson_085 Dec 09 '14 at 08:28

1 Answers1

0

The problem is that any fatal alert kills the session resumption. So reading past the end of one stream kills subsequent resuse. There is more here

Java TLS Session Reuse after closed connection

Community
  • 1
  • 1
Tuntable
  • 3,276
  • 1
  • 21
  • 26