Excepciones aleatorias de "pares no autenticados" con Java SSLContextImpl $ TLS10Context
haproxy sslsocketfactory (2)
Recibo fallas de conexión que aparecen aleatoriamente cuando me conecto a un servidor HAProxy usando SSL. He confirmado que estas fallas ocurren en las versiones de JDK 1.7.0_21 y 1.7.0_25, pero no con 1.7.0_04 o con 1.6.0_38.
La excepción es
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)
Estas fallas solo ocurren cuando se usa el contexto SSL de TLS y no con el contexto predeterminado. El siguiente código se ejecuta en un bucle miles de veces y los fallos suceden antes de que el bucle se complete (aproximadamente el 2% de las conexiones fallan):
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();
Sin embargo, si creo el contexto SSL de esta manera no tengo fallas en las conexiones en ninguna de las versiones de Java que mencioné:
SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
La primera forma usa SSLContextImpl$TLS10Context
y la última usa SSLContextImpl$DefaultSSLContext
. Al mirar el código, no veo ninguna diferencia que provoque la excepción.
¿Por qué obtendría los fallos y cuáles son las ventajas / desventajas de usar la llamada getDefault()
?
Nota: Las excepciones se vieron por primera vez usando Apache HttpClient (versión 4). Este código es el subconjunto más pequeño que reproduce el problema visto con HttpClient.
Aquí está el error que veo al agregar -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
Otra información es que los errores no ocurren si apago Diffie-Hellman en el servidor proxy.
A juzgar por los síntomas, supongo que esto está relacionado con los navegadores que usan el inicio falso de TLS , que es un truco del lado del cliente que Google introdujo para reducir el vaivén en TLS :
El inicio falso está controlado en gran medida por el navegador y funciona reduciendo los dos pases de ida y vuelta de datos descritos en las especificaciones SSL oficiales a un solo pase de ida y vuelta. Lo hizo ordenando al cliente que envíe los mensajes de ApplicationData finalizados y los primeros en un solo despacho en lugar de colocarlos en dos paquetes distintos y enviar el segundo solo después de recibir la confirmación del servidor.
Google propuso el inicio falso como un estándar oficial para hacer que SSL sea más aceptable para los sitios web que actualmente les resulta demasiado caro ofrecer. Al abreviar el apretón de manos que negocia la clave de encriptación y otras variables necesarias para proteger el paso de datos entre el usuario final y el sitio web, False Start fue pensado para reducir la penalización de rendimiento que muchos dicen que proviene del uso del protocolo.
De la cuestión relevante planteada en Mozilla Firefox : (énfasis mío)
Hasta ahora, una lista incompleta de productos que tienen problemas de compatibilidad actuales o previos con False Start incluye (AFAICT): F5, A10, TMG de Microsoft, Cisco ASA, ServerIron ADX, ESET, NetNanny, algunas configuraciones de la implementación del servidor SSL de Java .
javax.net.ssl.SSLPeerUnverifiedException surgen solo debido a la seguridad http, tienes que configurar tu conexión ya que https else sigue este código.
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = client.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
return new DefaultHttpClient(ccm, client.getParams());
utilizar esta. Espero que te ayude