J'obtiens des échecs de connexion qui apparaissent de manière aléatoire lorsque je me connecte à un serveur HAProxy en utilisant SSL. J'ai confirmé que ces échecs se produisent avec les versions 1.7.0_21 et 1.7.0_25 du JDK, mais pas avec la version 1.7.0_04 ni avec la version 1.6.0_38.
L'exception est
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)
Ces échecs se produisent uniquement lors de l'utilisation du contexte SSL TLS et non avec le contexte par défaut. Le code suivant est exécuté dans une boucle un millier de fois et les échecs se produisent avant la fin de la boucle (environ 2% des connexions échouent) :
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();
Cependant, si je crée le contexte SSL de cette manière, je n'ai aucun échec de connexion sur aucune des versions de Java que j'ai mentionnées :
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
La première façon utilise SSLContextImpl$TLS10Context
et le dernier utilise SSLContextImpl$DefaultSSLContext
. En regardant le code, je ne vois pas de différences qui pourraient provoquer l'exception.
Pourquoi j'obtiendrais les échecs et quels sont les avantages/inconvénients de l'utilisation de la getDefault()
appeler ?
Note : Les exceptions ont été vues pour la première fois en utilisant le HttpClient d'Apache (version 4). Ce code est le plus petit sous-ensemble qui reproduit le problème observé avec HttpClient.
Voici l'erreur que je vois lorsque j'ajoute -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
Autre information : les erreurs ne se produisent pas si je désactive la fonction Diffie-Hellman sur le serveur proxy.