working tls sslprotocol sslcertificatefile not configurar combination and ssl tomcat7 encryption resttemplate sslhandshakeexception

ssl - tls - tomcat https not working



SSLHandshakeException: alerta fatal recibida: handshake_failure al configurar las cifras en el servidor tomcat 7 (1)

Tengo un servidor web Tomcat7 que intenté configurar para aceptar conexiones seguras al agregar este conector al archivo server.xml :

<Connector SSLEnabled="true" acceptCount="100" connectionTimeout="20000" executor="tomcatThreadPool" keyAlias="server" keystoreFile="c:/opt/engine/conf/tc.keystore" keystorePass="o39UI12z" maxKeepAliveRequests="15" port="8443" protocol="HTTP/1.1" redirectPort="8443" scheme="https" secure="true" sslProtocol="TLS"/>

Estoy usando un certificado autofirmado generado usando este comando:

%JAVA_HOME%/bin/keytool -genkeypair -keystore c:/opt/engine/conf/tc.keystore -storepass o39UI12z-keypass o39UI12z-dname "cn=Company, ou=Company, o=Com, c=US" -alias server -validity 36500

En el lado del cliente, tengo una aplicación de primavera que se conecta con el servidor utilizando RestTemplate . En el inicio del contexto de la aplicación, inicializo la instancia restTemplate esta manera:

final ClientHttpRequestFactory clientHttpRequestFactory = new MyCustomClientHttpRequestFactory(new NullHostNameVerifier(), serverInfo); restTemplate.setRequestFactory(clientHttpRequestFactory);

La clase MyCustomClientHttpRequestFactory se ve así:

public class MyCustomClientHttpRequestFactory extends SimpleClientHttpRequestFactory { private static final Logger LOGGER = LoggerFactory .getLogger(MyCustomClientHttpRequestFactory.class); private final HostnameVerifier hostNameVerifier; private final ServerInfo serverInfo; public MyCustomClientHttpRequestFactory (final HostnameVerifier hostNameVerifier, final ServerInfo serverInfo) { this.hostNameVerifier = hostNameVerifier; this.serverInfo = serverInfo; } @Override protected void prepareConnection(final HttpURLConnection connection, final String httpMethod) throws IOException { if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection) connection).setHostnameVerifier(hostNameVerifier); ((HttpsURLConnection) connection).setSSLSocketFactory(initSSLContext() .getSocketFactory()); } super.prepareConnection(connection, httpMethod); } private SSLContext initSSLContext() { try { System.setProperty("https.protocols", "TLSv1"); // Set ssl trust manager. Verify against our server thumbprint final SSLContext ctx = SSLContext.getInstance("TLSv1"); final SslThumbprintVerifier verifier = new SslThumbprintVerifier(serverInfo); final ThumbprintTrustManager thumbPrintTrustManager = new ThumbprintTrustManager(null, verifier); ctx.init(null, new TrustManager[] { thumbPrintTrustManager }, null); return ctx; } catch (final Exception ex) { LOGGER.error( "An exception was thrown while trying to initialize HTTP security manager.", ex); return null; } }

Hasta aquí todo funcionó bien. Cuando coloco un punto de corte en la clase SslThumbprintVerifier, el código llegó a este punto y también a la clase NullHostNameVerifier. Esto fue probado en producción y funcionó de maravilla.

Ahora quería extender la seguridad al limitar las suites de cifrado y agregué esta propiedad al conector que presenté al principio:

ciphers="TLS_KRB5_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_SHA,SSL_DHE_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_AES_256_CBC_SHA,SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSL_DHE_RSA_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_KRB5_WITH_3DES_EDE_CBC_SHA"

Ahora, cuando estoy ejecutando el código del cliente obtengo esta excepción:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

Esto sucede en el método restTemplate.doExecute() . El código no llega a la clase de verificador de huella digital ni a la clase de verificador de nombre de host como lo hacía antes de agregar las cifras.

En la depuración revisé el ctx.getSocketFactory().getSupportedCipherSuites() que mostró:

[SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_NULL_SHA, SSL_DH_anon_WITH_RC4_128_MD5, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_256_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5]

y también revisó ctx.getSocketFactory().getDefaultCipherSuites() :

[SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]

y, por último, ctx.getSupportedSSLParameters().getCipherSuites() :

[SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, SSL_RSA_WITH_NULL_MD5, SSL_RSA_WITH_NULL_SHA, SSL_DH_anon_WITH_RC4_128_MD5, TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_DH_anon_WITH_AES_256_CBC_SHA, SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, TLS_KRB5_WITH_RC4_128_SHA, TLS_KRB5_WITH_RC4_128_MD5, TLS_KRB5_WITH_3DES_EDE_CBC_SHA, TLS_KRB5_WITH_3DES_EDE_CBC_MD5, TLS_KRB5_WITH_DES_CBC_SHA, TLS_KRB5_WITH_DES_CBC_MD5, TLS_KRB5_EXPORT_WITH_RC4_40_SHA, TLS_KRB5_EXPORT_WITH_RC4_40_MD5, TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA, TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5]

Por lo que yo entiendo, si hay una intersección entre las suites de cifrado soportadas / habilitadas del cliente y las suites de cifrado admitidas por el servidor debería funcionar (tenemos tal intersección con SSL_RSA_WITH_RC4_128_SHA por ejemplo). Y sin embargo, estoy recibiendo este error.

En el siguiente paso agregué este parámetro java:

-Djavax.net.debug=ssl,handshake,failure

El registro mostró solo el cliente-hola, sin respuesta de servidor-hola:

[2013-03-20 15:29:51.315] [INFO ] data-service-pool-37 System.out trigger seeding of SecureRandom [2013-03-20 15:29:51.315] [INFO ] data-service-pool-37 System.out done seeding SecureRandom [2013-03-20 15:30:38.894] [INFO ] data-service-pool-37 System.out Allow unsafe renegotiation: false [2013-03-20 15:30:38.894] [INFO ] data-service-pool-37 System.out Allow legacy hello messages: true [2013-03-20 15:30:38.894] [INFO ] data-service-pool-37 System.out Is initial handshake: true [2013-03-20 15:30:38.894] [INFO ] data-service-pool-37 System.out Is secure renegotiation: false [2013-03-20 15:30:38.894] [INFO ] data-service-pool-37 System.out %% No cached client session [2013-03-20 15:30:38.894] [INFO ] data-service-pool-37 System.out *** ClientHello, TLSv1 [2013-03-20 15:30:38.941] [INFO ] data-service-pool-37 System.out RandomCookie: GMT: 1363720446 bytes = { 99, 249, 173, 214, 110, 82, 58, 52, 189, 92, 74, 169, 133, 128, 250, 109, 160, 64, 112, 253, 50, 160, 255, 196, 85, 93, 33, 172 } [2013-03-20 15:30:38.941] [INFO ] data-service-pool-37 System.out Session ID: {} [2013-03-20 15:30:38.941] [INFO ] data-service-pool-37 System.out Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV] [2013-03-20 15:30:38.956] [INFO ] data-service-pool-37 System.out Compression Methods: { 0 } [2013-03-20 15:30:38.956] [INFO ] data-service-pool-37 System.out *** [2013-03-20 15:30:38.956] [INFO ] data-service-pool-37 System.out data-service-pool-37, WRITE: TLSv1 Handshake, length = 81 [2013-03-20 15:30:38.956] [INFO ] data-service-pool-37 System.out data-service-pool-37, READ: TLSv1 Alert, length = 2 [2013-03-20 15:30:38.956] [INFO ] data-service-pool-37 System.out data-service-pool-37, RECV TLSv1 ALERT: fatal, handshake_failure [2013-03-20 15:30:38.972] [INFO ] data-service-pool-37 System.out data-service-pool-37, called closeSocket() [2013-03-20 15:30:38.972] [INFO ] data-service-pool-37 System.out data-service-pool-37, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

Al eliminar las cifras del servidor.xml, funciona de nuevo. También mencionaré que estoy probando el servidor y el cliente en la misma máquina. Intenté configurar el IP del servidor en la solicitud del cliente para ''localhost'' y para la máquina IP actual y no funcionó en ambos casos. Además, tenía este servidor ejecutándose en una máquina Linux diferente (el almacén de claves se generó en la máquina Linux con una ruta de Linux, por supuesto) y aún funciona sin las cifras y deja de funcionar con los sistemas de cifrado.


Bueno, tengo este problema resuelto. Parece que mediante la creación de un certificado autofirmado, el uso de la herramienta de claves , sin proporcionar el parámetro -keyalg, hace que el algoritmo de pares clave sea DSA por defecto. Ninguno de mis conjuntos de cifrado incluye el algoritmo DSA. En ese caso, aunque el cliente y el servidor tenían intersección entre sus suites de cifrado, ninguno era adecuado para el algoritmo clave.

Agregar -keyalg RSA al generar el almacén de claves, resolvió el problema.