Determine Diffie-Hellman “Parameters” Length for a

2019-05-18 04:53发布

问题:

I'd like to make an HTTPS connection to a server and, if I'm using non-ephemeral DH key exchange, I'd like to know what the parameters are for that connection. Actually, I don't really care if it's ephemeral or not.

What I'm looking for is the ability to make a connection and then warn if the connection is using "weak" DH parameters. Is that something I can check at connection-time? Or is the set of DH parameters (or, more specifically, the length of those parameters, in bits) defined by the cipher suite itself?

For example, the Qualys community thread has an illustration of the cipher suites that SSLLabs considers "weak" (well, everyone considers them weak... they just have a public tool which complains about them): https://community.qualys.com/thread/14821

They specifically mention e.g. TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 which is cipher suite 0x9f and mention the DH parameters. Are those parameters' parameters baked-into the cipher suite (meaning they are always 1024-bit) or is this a configuration of the server that makes those cipher suites weak due to the specific DH parameter choice?

In either case, I'd like to be able to sniff that information from the connection if at all possible. Does anyone know if this can be done, and how?

I've written some code to attempt to get this information about the handshake, but I keep getting null for the object I was hoping would contain this data.

SSLSocketFactory sf = ...;
Socket sock = new Socket();
sock.connect(address, timeout);

SSLSocket socket = (SSLSocket)sf.createSocket(sock, host, port, true);
socket.startHandshake();
SSLSession sess = socket.getHandshakeSession();

I was hoping that sess at this point would contain some interesting information about the handshake, but it's null. The javadoc for startHandshake indicates that it will notify an event listener when the handshake is completed. So I tried this:

SSLSocketFactory sf = ...;
Socket sock = new Socket();
sock.connect(address, timeout);

SSLSocket socket = (SSLSocket)sf.createSocket(sock, host, port, true);
socket.startHandshake();
// SSLSession sess = socket.getHandshakeSession();
SSLSession sess = socket.getSession(); // This forces the handshake to complete
sess = socket.getHandshakeSession();

... but sess is still null at this point. The "real" SSLSession does exist and gives me information about the connection, but the "handshake session" seems to always be null.

So I tried writing an HandshakeCompletedListener, and I do in fact get an SSLSession, but it appears to be the same one that I can get from the SSLSocket already, so the "handshake" session seems to be unhelpful.

How can I get those parameters from the SSLSession?

回答1:

Are those parameters' parameters baked-into the cipher suite (meaning they are always 1024-bit) or is this a configuration of the server that makes those cipher suites weak due to the specific DH parameter choice?

No, this is a configuration parameter for the protocol. There is a default of 1024 bits for Java but that may be changed globally for JSSE (the Java TLS implementation) using a system property: jdk.tls.ephemeralDHKeySize. Best set this during startup with a -D option for the Java VM.

For static DH key pairs (that are used for authentication) you would have to look into the DH certificate. But I don't think you'll find any, everybody uses RSA for authentication.

In either case, I'd like to be able to sniff that information from the connection if at all possible. Does anyone know if this can be done, and how?

Well, for sniffing tools such as WireShark would suffice. Undoubtedly you can parse things like DH parameters from a TLS connection (if they are used in the first place of course).

You can also debug connections using -Djavax.net.debug

For Java applications / libraries you could look up the cipher suite and then, if it contains DHE_ look up the aforementioned system property (keeping in mind its default values).


The Java JSSE API was not written with deep packet inspection in mind. It's (literally) a service oriented implementation for servers and client applications. Although you could of course use the OpenJDK code itself (it's GPL'ed, right?) you are better off using a separate implementation, possibly with an even more permissive license.

For a sniffer however I would rather use C/C++ (or at least a C/C++ frontend) than Java.



回答2:

For most cipher algorithms, the length is determined by the name cypher name, as also mentioned here How to get the actual block cipher key size for Java SSL connection _in code_? . Instead of trying to warn people when they are using unsecure cyphers, I'd recommend to disable those ciphers by selecting only the cyphers you want to support. You can do this on a jvm level or on the SSLSocket, e.g.

String pickedCipher[] ={"TLS_RSA_WITH_AES_128_CBC_SHA"}; 
socket.setEnabledCipherSuites(pickedCipher);

You can also set the desired key size, see here https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#customizing_dh_keys

You can see defaults and classes used in Java security here https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html

If you are curious and want to investigate this in more detail, I'd recommend to turn on ssl logging, as described here.