I get connection failures that appear randomly when connecting to an HAProxy server using SSL. I have confirmed that these failures happen on JDK versions 1.7.0_21 and 1.7.0_25 but not with 1.7.0_04 or with 1.6.0_38.
The exception is
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)
These failures only happen when using the TLS SSL context and not with the default context. The following code is run in a loop a thousand times and failures happen before the loop completes (about 2% of the connections fail):
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();
If, however, I create the SSL context this way I have no connections failures on any of the Java versions I mentioned:
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
The first way uses SSLContextImpl$TLS10Context
and the later uses SSLContextImpl$DefaultSSLContext
. Looking at the code, I don't see any differences that would cause the exception to occur.
Why would I be getting the failures and what are the advantages/disadvantages of using the getDefault()
call?
Note: The exceptions were first seen using the Apache HttpClient (version 4). This code is the smallest subset that reproduces the problem seen with HttpClient.
Here's the error I see when adding -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
Another piece of information is that the errors do not occur if I turn off Diffie-Hellman on the proxy server.
getDefault(),
and four lines that don't. I'm asking you why you prefer the second, when it is both longer and doesn't work. – Groningen