Я получаю сбои соединения, которые появляются случайным образом при подключении к HAProxy-серверу с использованием SSL. Я подтвердил, что эти сбои происходят в версиях 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)
Эти сбои возникают только при использовании контекста SSL TLS, а не в контексте по умолчанию. Следующий код запускается в цикле тысячу раз, и неудачи происходят до того, как цикл завершится (около 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 на прокси-сервере.