Mensaje de error
javax.net.ssl.SSLHandshakeException: (handshake_failure) Received fatal alert: handshake_failure
También se muestra como
- javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
- Received fatal alert: handshake_failure
JDK 21 y las versiones posteriores muestran el nombre de la alerta entre paréntesis: «(handshake_failure) Received fatal alert: handshake_failure»; JDK 8 y 11 solo imprimen «Received fatal alert: handshake_failure».
Java (JSSE) — TLS alert 40 received from the server
Qué significa
El servidor abortó el handshake TLS con la alerta 40 (handshake_failure). No encontró nada aceptable en el ClientHello de la JVM (ningún conjunto de cifrado, grupo ni algoritmo de firma en común) o exige un certificado de cliente que la JVM no presentó. Java solo informa de que llegó la alerta; el motivo está en el registro del servidor o se puede ver con javax.net.debug.
Por qué ocurre
El servidor solo ofrece conjuntos desactivados en el JDK
frecuenteLas actualizaciones actuales del JDK (21.0.12 y 25.0.4 en nuestras pruebas) incluyen en jdk.tls.disabledAlgorithms los conjuntos TLS_RSA_* (intercambio de claves RSA), 3DES, RC4 y anónimos. Los servidores heredados limitados a ellos fallan con cualquier JVM actualizada.
TLS mutuo sin certificado de cliente
frecuenteEl servidor pidió un certificado y la JVM no tenía ninguno (sin javax.net.ssl.keyStore, o sin ninguno emitido por una CA que acepte el servidor).
SNI ausente o desconocido
ocasionalConectarse por IP, o con jsse.enableSNIExtension=false, hace que las CDN y los servidores multiinquilino aborten el handshake.
Una JVM muy antigua frente a un servidor moderno
ocasionalJava 7 y las primeras actualizaciones de Java 8 carecen de los conjuntos ECDHE/GCM y de TLS 1.2 activado por defecto, que exigen los servidores reforzados.
Cómo solucionarlo
- 1.
Examinar el handshake
javax.net.debug=ssl:handshake imprime el ClientHello (los conjuntos ofrecidos) y la alerta; -XshowSettings:security:tls enumera los protocolos y conjuntos que el JDK tiene activados.
bash # Show what the JVM offers and how the handshake ends java -Djavax.net.debug=ssl:handshake -jar app.jar 2>&1 | grep -E 'ClientHello|cipher_suites|Alert|fatal' # Settings in effect (protocols, suites) for this JDK java -XshowSettings:security:tls -version - 2.
Propietarios del servidor: activar conjuntos actuales
TLS 1.3 y TLS 1.2 con ECDHE y AES-GCM o ChaCha20 funcionan con todos los JDK que siguen recibiendo mantenimiento.
text # Server side: offer ECDHE + AEAD suites that current JDKs support ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; - 3.
TLS mutuo: configurar el almacén de claves del cliente
javax.net.ssl.keyStore (o un SSLContext construido a partir de un KeyManagerFactory) proporciona el certificado de cliente.
bash # Mutual TLS: give the JVM the client certificate and key java -Djavax.net.ssl.keyStore=client.p12 -Djavax.net.ssl.keyStorePassword=changeit \ -Djavax.net.ssl.keyStoreType=PKCS12 -jar app.jar - 4.
Último recurso: ajustar disabledAlgorithms para un único cliente heredado
Un archivo de sobrescritura pasado con -Djava.security.properties puede quitar TLS_RSA_* de jdk.tls.disabledAlgorithms para una sola JVM; copia el valor predeterminado completo y quita solo lo que necesites. Estos conjuntos carecen de forward secrecy, así que mantén la excepción acotada y temporal.
bash # Last resort for one legacy server: take this JDK's own value and drop only TLS_RSA_* v=$(sed -n '/^jdk.tls.disabledAlgorithms=/,/[^\\]$/p' "$JAVA_HOME/conf/security/java.security" | sed 's/\\$//' | tr -d '\n') printf '%s\n' "$v" | sed -E 's/, TLS_RSA_\*//' > legacy-rsa.security java -Djava.security.properties=legacy-rsa.security -jar legacy-client.jar
Errores relacionados
No appropriate protocol (protocol is disabled or cipher suites are inappropriat…Java (JSSE)javax.net.ssl.SSLHandshakeException: (protocol_version) Received fatal alert: p…Java (JSSE)SSL routines:ssl3_read_bytes:ssl/tls alert handshake failureOpenSSL (client side)SSL routines:tls_post_process_client_hello:no shared cipherOpenSSL (server side: nginx, Apache, Postfix, openssl s_server)