0
votes

I have some codebase that uses TLS and it works with the actual cipher processing via the integer value of the cipher selected. The selected cipher is extracted as follows:

String cipherSuite = sslSocket.getSession().getCipherSuite();

which is a value like TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, and has an integer value of 49200 or 0xc030 in hex. The codebase has a manually defined mapping class that returns the integer value of the cipher given the cipher name.

I took a look at the SSLSocket object chain there from an IDE to see what other methods were available, but didn't find anything that could do the lookup that the manual mapped class did.

From another faintly related SO post online, I found a table of TLS ciphers and their values: https://web.archive.org/web/20151219054439/http://www.thesprawl.org/research/tls-and-ssl-cipher-suites/.

Now I'm just wondering rather than go through the effort in maintaining the full table mapping, in case things change in future, is there already some Java class that we can call to do the lookup? e.g. lookup by cipher name to get integer/hex value or vice versa? I'm no security expert nor a Java guru, so wouldn't know.

P.S. the codebase I was working with didn't have the full mapping of the table link I mentioned, only a partial subset. Came across this problem as the codebase was failing from missing some ciphers that were now being used in the system. I added the missing ciphers, but looking for a more elegant way to maintain the cipher mapping or lookup.

1

1 Answers

1
votes

You can get the standard TLS ciphersuite code for an existing session. You are vague how you "took a look ... from an IDE" but if you look with a debugger you should see that the SSLSessionImpl for the socket (or engine) contains cipherSuite which in turn contains both int id (the code) and String name (the name), although the API for SSLSession returns only the latter. For example in my Eclipse:

enter image description here

Since these classes and their fields (and methods) are not public you can't access them directly, but at least through j8 you can do so with reflection:

    SSLSocket sock = (SSLSocket) SSLSocketFactory.getDefault().createSocket("example.com",  443);
    SSLSession sess = sock.getSession(); // actually sun.security.ssl.SSLSessionImpl
    Class<?> c1 = Class.forName("sun.security.ssl.SSLSessionImpl");
    Field f1 = c1.getDeclaredField("cipherSuite"); f1.setAccessible(true);
    Object cs = f1.get(sess);
    Class<?> c2 = Class.forName("sun.security.ssl.CipherSuite");
    Field f2 = c2.getDeclaredField("id"); f2.setAccessible(true);
    Integer id = (Integer) f2.get(cs);
    System.out.printf("%x%n", id);

In the 'module' scheme of j9 up this gives a warning for 'illegal reflective access', although so far (up to 13.0.1) it does actually succeed. If I get a better handle on exactly how modules work I will try to improve this. (Or this being Stack, someone else can.)

Note this doesn't actually provide a mapping as you asked, only the value for the current connection which appears to be your actual need. If you really want a mapping, CipherSuite is actually an enum class so all of the instances are in fact there, but looking at the code it appears the method used to find this mapping has been changed in different versions, as well as being nonpublic, so I'm not going to the trouble of trying to work out multiple examples without knowing which if any you need.