Mensagem de erro
javax.net.ssl.SSLHandshakeException: (handshake_failure) Received fatal alert: handshake_failure
Também aparece como
- javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
- Received fatal alert: handshake_failure
O JDK 21 e as versões posteriores mostram o nome do alerta entre parênteses: “(handshake_failure) Received fatal alert: handshake_failure”; os JDKs 8 e 11 imprimem apenas “Received fatal alert: handshake_failure”.
Java (JSSE) — TLS alert 40 received from the server
O que significa
O servidor abortou o handshake TLS com o alerta 40 (handshake_failure). Ele não encontrou nada aceitável no ClientHello da JVM (nenhuma cipher suite, nenhum grupo e nenhum algoritmo de assinatura em comum) ou exige um certificado de cliente que a JVM não apresentou. O Java só informa que o alerta chegou; o motivo está no log do servidor ou fica visível com javax.net.debug.
Por que acontece
O servidor só oferece cipher suites que o JDK desativou
comumAs atualizações atuais do JDK (21.0.12 e 25.0.4 em nossos testes) listam em jdk.tls.disabledAlgorithms as cipher suites TLS_RSA_* (troca de chaves RSA), 3DES, RC4 e anônimas. Servidores legados restritos a elas falham com qualquer JVM atualizada.
TLS mútuo sem certificado de cliente
comumO servidor solicitou um certificado, e a JVM não tinha nenhum (sem javax.net.ssl.keyStore, ou nenhum emitido por uma CA que o servidor aceite).
SNI ausente ou desconhecido
ocasionalConectar por IP, ou com jsse.enableSNIExtension=false, faz CDNs e servidores multilocatários abortarem o handshake.
Uma JVM muito antiga se conectando a um servidor moderno
ocasionalO Java 7 ou as primeiras atualizações do Java 8 não têm as cipher suites ECDHE/GCM nem o TLS 1.2 ativado por padrão, que servidores com configuração reforçada exigem.
Como corrigir
- 1.
Examinar o handshake
Com javax.net.debug=ssl:handshake, a JVM imprime o ClientHello (as cipher suites oferecidas) e o alerta; -XshowSettings:security:tls lista os protocolos e as cipher suites que o JDK tem ativados.
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.
Donos do servidor: ativar cipher suites atuais
O TLS 1.3 e o TLS 1.2 com ECDHE e AES-GCM ou ChaCha20 funcionam com todos os JDKs ainda mantidos.
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 mútuo: configurar o keystore do cliente
O javax.net.ssl.keyStore (ou um SSLContext criado a partir de um KeyManagerFactory) fornece o 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 um único cliente legado
Um arquivo de sobrescrita passado com -Djava.security.properties pode remover TLS_RSA_* de jdk.tls.disabledAlgorithms para uma única JVM; copie o valor padrão completo e remova só o que for necessário. Essas cipher suites não têm forward secrecy, então mantenha a exceção restrita e temporária.
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
Erros 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)