确定Java中TLS握手的Diffie-Hellman“参数”长度

我想与服务器建立HTTPS连接,如果我使用非短暂的DH密钥交换,我想知道该连接的参数是什么。 实际上,我并不关心它是否是短暂的。

我正在寻找的是能够建立连接,然后警告连接是否使用“弱”DH参数。 这是我可以在连接时检查的东西吗? 或者是由密码套件本身定义的DH参数集(或者更具体地说,这些参数的长度 ,以位为单位)?

例如,Qualys社区线程有一个SSLLabs认为“弱”的密码套件的图示(好吧,每个人都认为它们很弱……他们只是有一个抱怨它们的公共工具): https://community.qualys。 COM /线程/ 14821

他们特别提到例如TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ,它是密码套件0x9f并提及DH参数。 这些参数的参数是否被加密到密码套件中(意味着它们总是 1024位),或者这是服务器的配置,由于特定的DH参数选择,使得这些密码套件变弱了?

在任何一种情况下,如果可能的话,我希望能够从连接中嗅出该信息。 有谁知道这是否可以做到,以及如何做?

我已经编写了一些代码来尝试获取有关握手的信息,但是我一直在为我希望包含这些数据的对象获取null

 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(); 

我希望此时的sess包含一些关于握手的有趣信息,但它是nullstartHandshake的javadoc表示它将在握手完成时通知事件侦听器。 所以我尝试了这个:

 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(); 

…但是此时sess仍为null 。 “真正的”SSLSession确实存在,并提供有关连接的信息,但“握手会话”似乎总是为null

所以我尝试编写一个HandshakeCompletedListener ,事实上我确实得到了一个SSLSession ,但它似乎与我已经从SSLSocket获得的相同,所以“握手”会话似乎没有用。

如何从SSLSession获取这些参数?

这些参数的参数是否被加密到密码套件中(意味着它们总是1024位),或者这是服务器的配置,由于特定的DH参数选择,使得这些密码套件变弱了?

不,这是协议的配置参数。 Java的默认值为1024位,但可以使用系统属性jdk.tls.ephemeralDHKeySize对JSSE(Java TLS实现)进行全局更改。 最好在启动期间使用Java VM的-D选项设置此项。

对于静态DH密钥对(用于身份validation),您必须查看DH证书。 但我不认为你会找到任何人,每个人都使用RSA进行身份validation。

在任何一种情况下,如果可能的话,我希望能够从连接中嗅出该信息。 有谁知道这是否可以做到,以及如何做?

那么,对于诸如WireShark之​​类的嗅探工具就足够了。 毫无疑问,您可以从TLS连接中解析诸如DH参数之类的内容(如果它们首先用于它们)。

您还可以使用-Djavax.net.debug调试连接

对于Java应用程序/库,您可以查找密码套件,然后,如果它包含DHE_查找上述系统属性(请记住其默认值)。


Java JSSE API并未考虑深度数据包检测。 它(字面上)是服务器和客户端应用程序的面向服务的实现。 虽然你当然可以使用OpenJDK代码本身(它是GPL,对吗?)你最好使用单独的实现,可能还有更宽松的许可证。

但对于嗅探器,我宁愿使用C / C ++(或至少是C / C ++前端)而不是Java。

对于大多数密码算法,长度由名称cypher名称确定,如此处所述如何获取Java SSL连接的实际分组密钥大小_in code_? 。 我建议通过仅选择您想要支持的密码来禁用这些密码,而不是在人们使用不安全的密码时警告他们。 你可以在jvm级别或SSLSocket上执行此操作,例如

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

您也可以设置所需的密钥大小,请参阅https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#customizing_dh_keys

您可以在此处查看Java安全性中使用的默认值和类https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html

如果您很好奇并希望更详细地研究这个问题,我建议您打开ssl日志记录,如此处所述。