Message d’erreur
javax.net.ssl.SSLHandshakeException: (handshake_failure) Received fatal alert: handshake_failure
Également affiché sous la forme
- javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
- Received fatal alert: handshake_failure
À partir du JDK 21, le nom de l’alerte apparaît entre parenthèses : « (handshake_failure) Received fatal alert: handshake_failure » ; les JDK 8 et 11 affichent seulement « Received fatal alert: handshake_failure ».
Java (JSSE) — TLS alert 40 received from the server
Ce que cela signifie
Le serveur a interrompu le handshake TLS avec l’alerte 40 (handshake_failure). Soit il n’a rien trouvé d’acceptable dans le ClientHello de la JVM (aucune suite de chiffrement, aucun groupe ni aucun algorithme de signature en commun), soit il exige un certificat client que la JVM n’a pas présenté. Java signale seulement l’arrivée de l’alerte ; la raison figure dans le journal du serveur ou devient visible avec javax.net.debug.
Pourquoi cela se produit
Le serveur ne propose que des suites désactivées par le JDK
fréquenteLes mises à jour actuelles du JDK (21.0.12 et 25.0.4 lors de nos tests) listent les suites TLS_RSA_* (échange de clés RSA), 3DES, RC4 et anonymes dans jdk.tls.disabledAlgorithms. Les serveurs anciens limités à ces suites échouent avec toute JVM à jour.
TLS mutuel sans certificat client
fréquenteLe serveur a demandé un certificat et la JVM n’en avait aucun (pas de javax.net.ssl.keyStore, ou aucun certificat émis par une AC que le serveur accepte).
SNI absent ou inconnu
occasionnelleUne connexion par IP, ou avec jsse.enableSNIExtension=false, conduit les CDN et les serveurs mutualisés à interrompre le handshake.
Une JVM très ancienne face à un serveur moderne
occasionnelleIl manque à Java 7 et aux premières mises à jour de Java 8 les suites ECDHE/GCM et l’activation par défaut de TLS 1.2 qu’exigent les serveurs durcis.
Comment corriger l’erreur
- 1.
Examiner le handshake
javax.net.debug=ssl:handshake affiche le ClientHello (suites proposées) et l’alerte ; -XshowSettings:security:tls liste les protocoles et les suites activés dans le JDK.
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.
Propriétaires de serveurs : activer des suites actuelles
TLS 1.3 et TLS 1.2 avec ECDHE et AES-GCM ou ChaCha20 fonctionnent avec tous les JDK maintenus.
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 mutuel : configurer le magasin de clés du client
javax.net.ssl.keyStore (ou un SSLContext construit à partir d’une KeyManagerFactory) fournit le certificat client.
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.
En dernier recours : ajuster disabledAlgorithms pour un seul client ancien
Un fichier de surcharge passé avec -Djava.security.properties peut retirer TLS_RSA_* de jdk.tls.disabledAlgorithms pour une seule JVM ; copiez la valeur par défaut complète et ne retirez que ce dont vous avez besoin. Ces suites n’offrent pas de confidentialité persistante : gardez donc l’exception ciblée et temporaire.
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
Erreurs associées
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)