Un error común que hemos visto al momento de establecer comunicación dentro de nuestros programas Javas al momento de consumir una URL por el modo seguro es un "Handshake Failure" pero ¿qué significa eso? continua leyendo para averiguarlo.
Muchos sabemos que el internet nació con el protocolo conocido como "http" o que en algunos lugares pueden decirles modo plano, modo no seguro, etc. pero conforme fue avanzando el Internet y su propagación en el mundo; se fue haciendo indispensable blindar de seguridad el consumo de algunas URL.
Al tal grado de que nació el protocolo HTTP como modo seguro y es HTTPS. Este protocolo en particular utiliza una serie de negociación de un punto a otro para poder ser consumido y en éste punto utilizamos los famosos certificados SSL (Secure Sockets Layer). De acuerdo con DigiCert los certificados SSL:
“a veces denominados certificados digitales, se
utilizan para establecer una conexión cifrada entre el navegador o la
computadora del usuario, y un servidor o un sitio web. La conexión SSL protege
los datos confidenciales, como la información de tarjetas de crédito, que se
intercambian durante cada visita (denominada "sesión") y evita que
sean interceptados por partes no autorizadas.”
Dicho todo lo anterior, tal vez si llegaste a este post es porque tienes conocimiento y quieres llegar a la solución de un error como éste:
error:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Este error lo podemos estar recibiendo con las versiones de Java7 o Java 1.7, por lo que antes de implementar la solución, debemos validar que el certificado esté instalado correctamente desde donde lo consumamos ya sea desde un Java Keystore o el propio cacerts.
En el caso que conozcas el alias:
keytool -v -list -keystore cacerts -storepass password
Para el caso que no conoces el alias:
keytool -v -list -keystore cacerts -storepass password | grep -i alias
El password que viene por default es "changeit" y el nombre del keystore colocamos cacerts pero si es un JKS puedes sustituir el nombre cacerts por el nombre de Java Keystore.
Si observas que no está instalado o tienes duda de si es el correcto, puedes descargar tu certificado que vayas a usar ya sea desde un navegador pero como somos Linuxeros y Unixeros no sería bonito usar un navegador, así que vamos a colocar el comando para obtener el certificado:
openssl s_client -showcerts -server servername -connect servername:443 > servername.pem
Para salir de la pantalla, tecleamos "quit" y luego damos Enter. Con esto, vamos a obtener lo necesario para el certificado y abriendo el archivo pem vamos a observar una cadena que tiene "BEGIN CERTIFICATE" desde ahí inicia nuestro certificado, finaliza hasta la leyenda "END CERTIFICATE", del cual podemos copiar ese extracto y colocarlo en un archivo servername.crt
Ahora bien, para importar el certificado utilizaremos el comando keytool:
keytool -v -import -file servername.crt -alias servername -keystore cacerts -storepass
Una vez que ingresamos el comando anterior, vamos a decir "Si" o "Yes" dependiendo como tengas configurado tu S.O. Si todo lo anterior sigue correcto, en la salida del archivo servername.pem podemos buscar una línea llamada "Protocol" del cual nos dirá la versión de TLS que utiliza:
grep Protocol servername.pem
La versión de Java tiene el inconveniente de no funcionar con los TLSv1 en adelante, por lo cual si usas Java 1.7_95 hacia abajo colocaremos la siguiente línea en la ejecución java:
-Dhttps.protocols=TLSv1.2,TLSv1.1,TLSv1
En el caso contrario, para Java 1.7 Release 95 en adelante, usaremos la siguiente línea dentro de tu ejecución con java:
-Djdk.tls.client.protocols=
TLSv1.2,TLSv1.1,TLSv1
El issue ha sido arreglado con la versión de java8, así que probablemente pienses en migrar tu java a dicha versión para que no tengas dicho problema. Déjame tus comentarios si has tenido el mismo inconveniente o cualquier duda que tengas.
Bytes