随机的“对等体未经过身份验证”异常与 Java SSLContextImpl$TLS10Context
我在使用 SSL 连接到 HAProxy 服务器时随机出现连接失败。我已确认这些故障发生在JDK版本1.7.0_21和1.7.0_25上,但不是1.7.0_04或1.6.0_38。
例外情况是
Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:397)
at SSLTest2.main(SSLTest2.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
这些故障仅在使用 TLS SSL 上下文时发生,而不是在默认上下文中发生。以下代码在循环中运行一千次,并在循环完成之前发生故障(大约2%的连接失败):
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, null, null);
SSLSocketFactory factory = sslcontext.getSocketFactory();
SSLSocket socket = (SSLSocket)factory.createSocket("myserver", 443);
//socket.startHandshake();
SSLSession session = socket.getSession();
session.getPeerCertificates();
socket.close();
但是,如果我以这种方式创建SSL上下文,那么在我提到的任何Java版本上都没有连接失败:
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
第一种方式使用,后一种方式使用。查看代码,我没有看到任何会导致异常发生的差异。SSLContextImpl$TLS10Context
SSLContextImpl$DefaultSSLContext
为什么我会失败,使用调用的优点/缺点是什么?getDefault()
注意:这些异常最初是使用Apache HttpClient(版本4)看到的。此代码是重现在 HttpClient 中看到的问题的最小子集。
这是我在添加 -Djavax.net.debug=ssl
时看到的错误:
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, bad_record_mac
%% Invalidated: [Session-101, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA]
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
main, IOException in getSession(): javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
另一条信息是,如果我在代理服务器上关闭Diffie-Hellman,则不会发生错误。