java web-services ssl cxf sni

java - Nombre de servidor extendido(extensión SNI) no enviado con jdk1.8.0 pero enviado con jdk1.7.0



web-services ssl (5)

Como se mencionó, la causa está relacionada con el error JDK donde el uso de setHostnameVerifier () rompe SNI (Extension server_name). https://bugs.openjdk.java.net/browse/JDK-8144566

Nuestra solución: después de las pruebas, descubrimos que la configuración del SSLSocketFactory de una conexión a casi cualquier valor predeterminado parece solucionar el problema.

Esto no funciona: HttpsURLConnection.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());

Esto funciona: HttpsURLConnection.setSSLSocketFactory(new SSLSocketFactoryFacade());

Entonces, para arreglarlo para un cliente JAX-WS, podría hacer algo como esto: bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", new SSLSocketFactoryFacade());

Nuestra fachada SSLSocketFactory: (Tenga en cuenta que realmente no hace nada)

public class SSLSocketFactoryFacade extends SSLSocketFactory { SSLSocketFactory sslsf; public SSLSocketFactoryFacade() { sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault();; } @Override public String[] getDefaultCipherSuites() { return sslsf.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return sslsf.getSupportedCipherSuites(); } @Override public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException { return sslsf.createSocket(socket, s, i, b); } @Override public Socket createSocket(String s, int i) throws IOException, UnknownHostException { return sslsf.createSocket(s, i); } @Override public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException { return sslsf.createSocket(s, i, inetAddress, i1); } @Override public Socket createSocket(InetAddress inetAddress, int i) throws IOException { return createSocket(inetAddress, i); } @Override public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { return createSocket(inetAddress, i, inetAddress1, i1); } }

He implementado un cliente JAX-WS utilizando ApacheCXF (v3.0.4) y todo funciona correctamente, pero el problema surge cuando quiero usar una conexión segura (SSL / TLS) con java 8 (jdk1.8.0_25).

Veo la siguiente excepción en el registro (-Djavax.net.debug = all):

main, handling exception: java.net.SocketException: Connection reset main, SEND TLSv1.2 ALERT: fatal, description = unexpected_message main, WRITE: TLSv1.2 Alert, length = 2 main, Exception sending alert: java.net.SocketException: Connection reset by peer: socket write error

Después de un análisis depeer, observé que el problema se debe a que con Java 8 no se envía server_name (SNI), pero con Java 7 se envía y la invocación del servicio web funciona correctamente.

Registro de Java 8 (-Djavax.net.debug = all): falta "Extension server_name"

[...] Compression Methods: { 0 } Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1} Extension ec_point_formats, formats: [uncompressed] Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA *** [...]

Registro de Java 7 (-Djavax.net.debug = todo) (funciona): "La extensión nombre_servidor" está establecida

[...] Compression Methods: { 0 } Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1} Extension ec_point_formats, formats: [uncompressed] Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA Extension server_name, server_name: [host_name: testeo.hostname.es] *** [...]

Se observa que con Java 7 se establece la extensión nombre_servidor, nombre_servidor: [nombre_host: testeo.hostname.es] y luego la invocación del servicio web funciona correctamente.

¿Por qué Java 8 no estableció el nombre de servidor como lo hizo Java 7? ¿Es un problema de configuración de Java?


En primer lugar, este "nombre de servidor" está asociado con la extensión SNI (Indicación del nombre del servidor). La documentación de Java 8 JSSE habla de esto here .

La documentación incluye código de ejemplo que muestra cómo configurar los nombres de servidor que se envían. El código es para Java 8.

Sin embargo, no puedo entender por qué (aparentemente) Java 7 está configurando el nombre del servidor por defecto, y Java 8 no lo está. (La forma más fácil de averiguarlo sería usar un depurador para descubrir cómo se crea y se inicializa el objeto del motor SSL).


Probé la solución provista por Benjamin Parry, pero no funcionó para mí. Después de investigar un poco, también encontré esta solución que parece muy similar, sin embargo, SSLSocketFactoryFacade inserta manualmente el encabezado SSL correcto en lugar de ser un simple paso de paso. Proporcionar mi código final a continuación que es ligeramente diferente, pero se le debe dar un crédito a Girish Kamath en javabreaks por la idea básica:

private static class SSLSocketFactoryFacade extends SSLSocketFactory { private SSLSocketFactory sslsf; private SSLParameters sslParameters; public SSLSocketFactoryFacade(String hostName) { sslParameters = new SSLParameters(); sslParameters.setServerNames(Arrays.asList(new SNIHostName(hostName))); sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault();; } public Socket createSocket() throws IOException { Socket socket = sslsf.createSocket(); ((SSLSocket) socket).setSSLParameters(sslParameters); return socket; } public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2, int arg3) throws IOException { Socket socket = sslsf.createSocket(arg0, arg1, arg2, arg3); ((SSLSocket) socket).setSSLParameters(sslParameters); return socket; } public Socket createSocket(InetAddress arg0, int arg1) throws IOException { Socket socket = sslsf.createSocket(arg0, arg1); ((SSLSocket) socket).setSSLParameters(sslParameters); return socket; } public Socket createSocket(Socket arg0, InputStream arg1, boolean arg2) throws IOException { Socket socket = sslsf.createSocket(arg0, arg1, arg2); ((SSLSocket) socket).setSSLParameters(sslParameters); return socket; } public Socket createSocket(Socket arg0, String arg1, int arg2, boolean arg3) throws IOException { Socket socket = sslsf.createSocket(arg0, arg1, arg2, arg3); ((SSLSocket) socket).setSSLParameters(sslParameters); return socket; } public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) throws IOException, UnknownHostException { Socket socket = sslsf.createSocket(arg0, arg1, arg2, arg3); ((SSLSocket) socket).setSSLParameters(sslParameters); return socket; } public Socket createSocket(String arg0, int arg1) throws IOException, UnknownHostException { Socket socket = sslsf.createSocket(arg0, arg1); ((SSLSocket) socket).setSSLParameters(sslParameters); return socket; } public String[] getDefaultCipherSuites() { return sslsf.getDefaultCipherSuites(); } public String[] getSupportedCipherSuites() { return sslsf.getSupportedCipherSuites(); } }

Y luego puedo llamar

sslConnection.setSSLSocketFactory(new SSLSocketFactoryFacade(sslConnection.getURL().getHost()));

donde sslConnection es el HttpsURLConnection .


Usted, o las bibliotecas subyacentes (WS lib lo hace) puede estar usando setHostnameVerifier (..)

Hay un error en java8, donde si se usa setHostnameVerifier (..) el SNI no se realiza desde el lado del cliente.

https://bugs.openjdk.java.net/browse/JDK-8072464


Utilice la versión 8u141 de JDK y superior donde se solucionó este problema. Por favor, revise la página de correcciones de errores JDK 8u141 para más detalles