Tutorial completo: como usar `-Djavax.net.debug=ssl,handshake` para diagnosticar TLS/SSL em aplicações Java
Quando uma aplicação Java falha ao fazer uma conexão HTTPS, LDAPS, SMTPS, conexão JDBC sobre TLS ou qualquer outra comunicação baseada em TLS, a exceção normalmente é pouco esclarecedora:
javax.net.ssl.SSLHandshakeException: PKIX path building failed
ou:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
ou ainda:
javax.net.ssl.SSLException: Received fatal alert: protocol_version
Nesses casos, uma das ferramentas mais úteis do próprio Java é:
-Djavax.net.debug=ssl,handshake
Ela ativa o debug interno do JSSE (Java Secure Socket Extension), permitindo acompanhar praticamente passo a passo o estabelecimento da conexão TLS. A documentação oficial do Java descreve javax.net.debug como o mecanismo de dynamic debug tracing específico do JSSE. (Oracle Docs)
1. O que é javax.net.debug?
javax.net.debug é uma System Property da JVM usada para habilitar informações de diagnóstico do mecanismo SSL/TLS utilizado pelo Java.
Por exemplo:
java -Djavax.net.debug=ssl,handshake -jar minha-aplicacao.jar
O ponto importante é entender que:
-Djavax.net.debug=ssl,handshake
não é uma configuração do Spring Boot, Tomcat, Maven ou HTTP Client.
É uma propriedade da JVM.
Portanto, ela precisa ser passada antes da execução da aplicação.
2. O que significa cada parte?
Vamos decompor:
-Djavax.net.debug=ssl,handshake
-D
Indica que estamos definindo uma System Property da JVM.
É equivalente, dentro do Java, a:
System.setProperty("javax.net.debug", "ssl,handshake");
Mas existe uma diferença importante: colocar a propriedade na linha de comando é muito mais apropriado para diagnóstico, porque a JVM já inicia com o debug habilitado.
javax.net.debug
É o nome da propriedade reconhecida pelo JSSE.
ssl
Ativa o mecanismo de debug relacionado ao SSL/TLS.
handshake
Solicita que sejam exibidas as mensagens do TLS handshake.
Assim:
-Djavax.net.debug=ssl,handshake
pode ser interpretado conceitualmente como:
"Ative o diagnóstico do JSSE e mostre o que está acontecendo durante o handshake TLS."
A documentação atual do JSSE lista handshake como uma das categorias de debug disponíveis sob ssl. (Oracle Docs)
3. Antes de tudo: SSL x TLS
Apesar de o parâmetro se chamar:
javax.net.debug=ssl
isso não significa que sua aplicação esteja necessariamente usando SSL antigo.
O nome SSL permaneceu na API Java por compatibilidade histórica.
Por exemplo, uma aplicação moderna pode estar usando:
TLSv1.3
e ainda assim o debug será ativado através de:
-Djavax.net.debug=ssl
É comum encontrar no log coisas como:
ClientHello
ServerHello
TLSv1.3
Certificate
Finished
4. O que é o TLS handshake?
Antes de entender o log, é importante compreender o processo que ele está mostrando.
Imagine:
Java Application
|
| HTTPS
v
Servidor
Antes de transmitir os dados da aplicação, os dois lados precisam negociar diversos parâmetros de segurança.
Simplificadamente:
CLIENTE SERVIDOR
| -------- ClientHello ----------> |
| |
| <-------- ServerHello ---------- |
| <--------- Certificate ---------- |
| |
| -------- ClientKeyExchange ----> |
| |
| -------- Finished -------------> |
| |
| <--------- Finished ------------ |
| |
| ===== conexão segura =========== |
Em TLS 1.3 o processo é diferente e mais compacto, mas a ideia geral permanece: os lados negociam parâmetros criptográficos, autenticam o servidor e estabelecem chaves de sessão.
O JSSE é justamente a camada Java responsável por implementar esse processo. (Oracle Docs)
5. Primeiro teste: ssl,handshake
Para uma aplicação Java simples:
java -Djavax.net.debug=ssl,handshake -jar app.jar
Se você estiver executando uma aplicação Spring Boot:
java -Djavax.net.debug=ssl,handshake -jar minha-api.jar
Se estiver usando Maven:
mvn spring-boot:run \
-Dspring-boot.run.jvmArguments="-Djavax.net.debug=ssl,handshake"
No Gradle:
./gradlew bootRun \
--args=''
ou configure a JVM da tarefa bootRun para receber:
-Djavax.net.debug=ssl,handshake
6. Atenção: -D não é argumento da aplicação
Um erro bastante comum é colocar:
java -jar app.jar -Djavax.net.debug=ssl,handshake
Isso está errado para esse propósito.
O correto é:
java -Djavax.net.debug=ssl,handshake -jar app.jar
A diferença é:
java
|
+-- opções da JVM
| |
| +-- -Djavax.net.debug=...
|
+-- -jar
|
+-- aplicação
7. O primeiro nível: ssl
Você pode começar simplesmente com:
-Djavax.net.debug=ssl
Exemplo:
java -Djavax.net.debug=ssl -jar app.jar
Isso fornece informações gerais do mecanismo SSL/TLS, sem necessariamente mostrar todo o conteúdo detalhado do handshake.
A documentação define ssl como o modo de debug SSL que exclui determinados dumps mais detalhados, como data, packet e plaintext. (Oracle Docs)
8. ssl,handshake: o modo mais útil para começar
Na prática, este é um dos comandos que eu mais recomendo para investigação:
-Djavax.net.debug=ssl,handshake
Ele permite enxergar mensagens como:
ClientHello
ServerHello
Certificate
CertificateVerify
Finished
e informações relacionadas à negociação.
Por exemplo, você pode encontrar algo parecido com:
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "...",
"session id" : "...",
"cipher suites" : "[TLS_AES_256_GCM_SHA384, ...]",
"extensions" : [...]
}
Isso já permite responder perguntas extremamente importantes.
Por exemplo:
- Qual versão TLS o cliente está oferecendo?
- Qual cipher suite está sendo negociada?
- O servidor respondeu?
- O certificado foi recebido?
- O handshake chegou ao
Finished? - Em qual etapa ocorreu a falha?
9. Uma das variações mais importantes: trustmanager
Se o problema envolve certificado, eu normalmente aumentaria o nível de diagnóstico para:
-Djavax.net.debug=ssl,handshake,trustmanager
Exemplo:
java \
-Djavax.net.debug=ssl,handshake,trustmanager \
-jar app.jar
Essa combinação é extremamente útil para problemas como:
PKIX path building failed
unable to find valid certification path
unable to find valid certification path to requested target
SunCertPathBuilderException
10. Por que trustmanager é tão importante?
Durante uma conexão TLS, o servidor normalmente envia seu certificado:
Servidor
|
| Certificate
v
Java
O Java precisa decidir:
"Eu confio nesse certificado?"
Para isso entra em ação o TrustManager.
Simplificadamente:
Certificate recebido
|
v
TrustManager
|
v
Truststore Java
|
v
certificado confiável?
/ \
SIM NÃO
| |
v v
continua falha
O debug:
-Djavax.net.debug=ssl,handshake,trustmanager
pode revelar informações sobre a decisão do TrustManager.
Isso é particularmente importante quando você está trabalhando com:
- certificados internos;
- CA corporativa;
- certificados autoassinados;
- certificados intermediários;
- ambientes de homologação;
- proxies corporativos;
- TLS inspection;
- servidores LDAP/LDAPS;
- APIs internas.
11. Diagnóstico clássico: PKIX path building failed
Imagine:
javax.net.ssl.SSLHandshakeException:
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
Uma primeira tentativa seria:
java \
-Djavax.net.debug=ssl,handshake,trustmanager \
-jar app.jar
Procure no log por palavras como:
trust
TrustManager
certificate
X509
PKIX
trusted
server certificate
Você poderá descobrir, por exemplo, que o servidor apresentou:
CN=api.empresa.local
mas a CA que assinou esse certificado não está no truststore utilizado pela JVM.
12. Descobrindo qual truststore o Java está utilizando
Outra propriedade extremamente útil é:
javax.net.ssl.trustStore
Por exemplo:
-Djavax.net.ssl.trustStore=/opt/app/certs/truststore.p12
Você pode combinar:
java \
-Djavax.net.debug=ssl,handshake,trustmanager \
-Djavax.net.ssl.trustStore=/opt/app/certs/truststore.p12 \
-jar app.jar
Se for necessário informar o tipo:
-Djavax.net.ssl.trustStoreType=PKCS12
E eventualmente:
-Djavax.net.ssl.trustStorePassword=senha
Cuidado: evitar colocar senha diretamente na linha de comando em ambientes compartilhados, porque ela pode ficar exposta em informações de processo ou histórico.
13. keymanager: quando o problema é certificado do cliente
Agora imagine o cenário inverso.
O servidor exige:
"Cliente, apresente um certificado."
Isso é mTLS (Mutual TLS).
Nesse caso:
TLS
Java <----------------> Servidor
| |
| certificado cliente |
+------------------------>|
Você pode precisar investigar o KeyManager.
Use:
-Djavax.net.debug=ssl,handshake,keymanager
Por exemplo:
java \
-Djavax.net.debug=ssl,handshake,keymanager \
-jar app.jar
Isso ajuda a investigar problemas relacionados a:
- certificado de cliente;
- keystore;
- chave privada;
- seleção do alias;
- certificado incompatível;
- ausência de certificado apropriado.
14. keymanager x trustmanager
Essa distinção é fundamental.
TrustManager
Pergunta:
"Em quem eu confio?"
Normalmente relacionado ao certificado recebido do servidor.
Servidor
|
| certificado
v
TrustManager
KeyManager
Pergunta:
"Qual certificado/chave eu devo apresentar?"
Normalmente relacionado ao certificado do próprio cliente.
KeyManager
|
| certificado + chave privada
v
Servidor
Portanto:
| Problema | Debug |
|---|---|
| Não confia no certificado do servidor | trustmanager |
| Não consegue escolher certificado do cliente | keymanager |
| mTLS | keymanager + trustmanager |
| Negociação TLS | handshake |
15. sslctx
Outra opção interessante:
-Djavax.net.debug=ssl,sslctx
ou:
-Djavax.net.debug=ssl,handshake,sslctx
Ela permite investigar informações relacionadas ao SSLContext.
Isso é útil quando você suspeita que a aplicação está utilizando uma configuração diferente daquela que você imaginava.
Por exemplo:
SSLContext
|
+-- KeyManager
|
+-- TrustManager
|
+-- protocolos
|
+-- cipher suites
16. defaultctx
Para investigar a inicialização do contexto SSL padrão:
-Djavax.net.debug=ssl,defaultctx
Pode ser útil quando você está tentando entender:
"De onde o Java está pegando essa configuração SSL?"
17. session
Use:
-Djavax.net.debug=ssl,session
ou:
-Djavax.net.debug=ssl,handshake,session
Isso ajuda a investigar informações relacionadas às sessões TLS.
É particularmente interessante quando você está analisando:
- reutilização de sessão;
- criação de sessões;
- comportamento de conexões persistentes;
- diferenças entre primeira conexão e conexões subsequentes.
18. sessioncache
Relacionado ao cache de sessões:
-Djavax.net.debug=ssl,sessioncache
Pode ser útil em problemas mais avançados de performance e reutilização de sessões TLS.
19. record
Agora começamos a entrar em um nível mais baixo.
-Djavax.net.debug=ssl,record
Enquanto:
handshake
mostra as mensagens do handshake, record mostra informações sobre os TLS records.
A estrutura conceitual é:
Aplicação
|
v
TLS Handshake
|
v
TLS Records
|
v
TCP
Portanto:
handshake
é geralmente mais amigável para diagnóstico.
Já:
record
é mais detalhado.
20. packet
Você pode adicionar:
-Djavax.net.debug=ssl,record,packet
Isso permite visualizar informações de pacotes TLS em nível mais baixo.
Por exemplo:
java \
-Djavax.net.debug=ssl,record,packet \
-jar app.jar
É útil principalmente quando você já está investigando um problema complexo de protocolo.
Para problemas comuns de certificado, normalmente não é necessário.
21. plaintext
Existe também:
-Djavax.net.debug=ssl,record,plaintext
Isso pode produzir dumps do conteúdo de plaintext relacionado aos TLS records.
É uma opção que exige muito cuidado.
Dependendo do contexto, informações sensíveis podem aparecer nos logs.
Nunca trate esse nível de debug como algo apropriado para produção.
22. data
Outra opção:
-Djavax.net.debug=ssl,handshake,data
Ela adiciona dumps hexadecimais das mensagens de handshake.
Exemplo conceitual:
0000: 16 03 03 ...
0010: 01 00 ...
0020: ...
Isso é útil quando você precisa analisar os bytes reais de uma mensagem TLS.
Para a maioria dos desenvolvedores Java:
ssl,handshake
é suficiente.
23. verbose
Você também pode usar:
-Djavax.net.debug=ssl,handshake,verbose
Isso aumenta a quantidade de detalhes exibidos durante o handshake.
Uma combinação possível:
-Djavax.net.debug=ssl,handshake,verbose
E ainda mais detalhada:
-Djavax.net.debug=ssl,handshake,verbose,data
24. all
Existe:
-Djavax.net.debug=all
Esse é o modo "metralhadora".
Ele pode produzir uma quantidade enorme de informações.
A documentação oficial define all como a ativação de todo o debug disponível. (Oracle Docs)
Eu recomendo não começar com all.
Prefira:
-Djavax.net.debug=ssl,handshake
e vá aumentando conforme a necessidade.
25. help
Existe uma opção especialmente útil:
-Djavax.net.debug=help
Por exemplo:
java -Djavax.net.debug=help MinhaAplicacao
Ela mostra as opções disponíveis na implementação JSSE daquele JDK.
Um detalhe importante: quando help é usado, a aplicação não continua normalmente; o mecanismo de debug imprime as opções e encerra. A documentação oficial também alerta para esse comportamento. (Oracle Docs)
Isso é importante porque você pode estar usando Java 17, 21, 25 etc., e as opções disponíveis podem variar entre versões/implementações.
26. ssl,handshake x ssl:handshake
Você pode encontrar os dois formatos:
-Djavax.net.debug=ssl,handshake
e:
-Djavax.net.debug=ssl:handshake
Ambos são aceitos.
Também é possível encontrar:
-Djavax.net.debug=SSL,handshake
A documentação indica que separadores como vírgula ou dois-pontos podem ser utilizados e que a ordem das opções não é relevante. (Oracle Docs)
Eu prefiro:
-Djavax.net.debug=ssl,handshake
por ser mais fácil de ler.
27. A combinação que eu mais recomendo
Para problemas comuns de HTTPS:
-Djavax.net.debug=ssl,handshake
Para problemas de certificado:
-Djavax.net.debug=ssl,handshake,trustmanager
Para mTLS:
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
Para investigação mais profunda:
-Djavax.net.debug=ssl,handshake,verbose
Para análise de protocolo:
-Djavax.net.debug=ssl,handshake,record,packet
Para investigação extremamente detalhada:
-Djavax.net.debug=all
28. Tabela prática das principais opções
| Opção | O que mostra | Quando usar |
|---|---|---|
ssl |
Debug geral JSSE | Primeiro diagnóstico |
handshake |
Mensagens TLS handshake | Quase sempre |
trustmanager |
Validação de certificados | PKIX/certificados |
keymanager |
Seleção de certificados/chaves locais | mTLS |
sslctx |
SSLContext | Configuração SSL |
defaultctx |
Inicialização do contexto padrão | Configuração padrão |
session |
Sessões TLS | Reuso de sessão |
sessioncache |
Cache de sessões | Performance/sessões |
record |
TLS records | Diagnóstico avançado |
packet |
Pacotes TLS | Baixo nível |
data |
Hex dump do handshake | Análise de protocolo |
plaintext |
Dados plaintext | Diagnóstico extremamente detalhado |
verbose |
Mais detalhes | Investigação avançada |
all |
Tudo | Último recurso |
help |
Lista opções | Descobrir recursos disponíveis |
As categorias acima são documentadas pelo JSSE, incluindo handshake, keymanager, trustmanager, record, session, sslctx, data, verbose, packet e plaintext. (Oracle Docs)
29. Como interpretar o ClientHello
Um dos primeiros pontos importantes no log será algo relacionado a:
ClientHello
Esse é o cliente Java dizendo ao servidor:
"Estas são as versões TLS, extensões e cipher suites que eu consigo utilizar."
Você pode encontrar informações como:
ClientHello
client version
random
session id
cipher suites
compression methods
extensions
As extensões são especialmente importantes.
Por exemplo:
server_name
supported_groups
signature_algorithms
supported_versions
key_share
30. supported_versions
Em versões modernas do TLS, você pode encontrar algo semelhante a:
"supported_versions": [
TLSv1.3,
TLSv1.2
]
Isso significa que o cliente está anunciando suporte a essas versões.
Se o servidor só suporta:
TLSv1.0
por exemplo, pode ocorrer incompatibilidade.
31. Identificando problemas de versão TLS
Imagine:
Client:
TLSv1.3
TLSv1.2
e o servidor:
TLSv1.0
Dependendo das configurações de segurança do JDK, a conexão pode falhar.
Você poderá encontrar:
SSLHandshakeException
ou:
protocol_version
ou:
handshake_failure
Nesse caso, o debug permite descobrir que o problema aconteceu durante a negociação do protocolo, antes mesmo de uma possível validação normal do certificado.
32. Identificando problemas de cipher suite
Outro ponto importante do ClientHello são as cipher suites.
Você pode encontrar algo como:
cipher suites:
[
TLS_AES_256_GCM_SHA384,
TLS_AES_128_GCM_SHA256,
TLS_CHACHA20_POLY1305_SHA256
]
O servidor precisa conseguir selecionar uma combinação compatível.
Se não houver interseção:
Java Servidor
AES/GCM <----X----> cipher incompatível
ChaCha20 <----X----> cipher incompatível
...
pode aparecer:
handshake_failure
O debug ajuda a descobrir que o problema está na negociação criptográfica.
33. Identificando o certificado do servidor
Durante o handshake você verá uma mensagem:
Certificate
A partir dela você consegue investigar coisas como:
Subject
Issuer
Validity
Key type
Certificate chain
Por exemplo:
Subject: CN=api.exemplo.com
Issuer: CN=Minha CA Corporativa
Isso é extremamente útil quando:
curl funciona
mas:
Java não funciona
porque pode haver diferenças entre as autoridades certificadoras confiáveis pelos dois ambientes.
34. O erro mais comum: Java não confia na CA
Um cenário extremamente frequente:
Servidor
|
+-- certificado
|
+-- CA corporativa
O navegador funciona.
O curl funciona.
Mas Java retorna:
PKIX path building failed
Nesse caso, investigue:
-Djavax.net.debug=ssl,handshake,trustmanager
e descubra:
- Qual certificado o servidor enviou.
- Qual é o
Issuer. - Qual cadeia foi construída.
- Qual truststore foi utilizado.
- Qual certificado/CA está faltando.
35. Cadeia de certificados
Considere:
Root CA
|
v
Intermediate CA
|
v
api.exemplo.com
O Java precisa conseguir construir uma cadeia confiável:
api.exemplo.com
|
v
Intermediate CA
|
v
Root CA
|
v
Truststore
Se faltar:
Intermediate CA
ou a CA raiz não for confiável, a validação poderá falhar.
O trustmanager é particularmente útil para enxergar esse processo.
36. Outro problema clássico: certificado expirado
No handshake você poderá encontrar informações indicando:
NotBefore
NotAfter
Se o certificado estiver fora do período de validade, o handshake poderá ser encerrado.
Esse tipo de problema pode ser especialmente confuso quando:
- a aplicação está em um servidor;
- o servidor possui relógio incorreto;
- o certificado acabou de ser renovado;
- existem múltiplos servidores atrás de um load balancer.
37. SNI: um detalhe importante
Quando uma aplicação acessa:
https://api.exemplo.com
o nome do host pode ser enviado no TLS através da extensão:
server_name
Isso é conhecido como SNI — Server Name Indication.
O debug pode mostrar algo semelhante a:
server_name
type=host_name
value=api.exemplo.com
Isso é importante porque servidores modernos podem hospedar vários certificados no mesmo IP.
Por exemplo:
IP 10.0.0.10
|
+-----------+-----------+
| |
api.foo.com api.bar.com
| |
certificado certificado
Se houver algum problema de SNI, o servidor pode entregar um certificado inesperado.
38. Um caso clássico de diagnóstico
Imagine:
RestClient
|
v
https://api.empresa.com
e você recebe:
SSLHandshakeException:
PKIX path building failed
Comece:
-Djavax.net.debug=ssl,handshake
Se ainda não estiver claro:
-Djavax.net.debug=ssl,handshake,trustmanager
Depois procure:
ClientHello
ServerHello
Certificate
TrustManager
O raciocínio é:
ClientHello
|
v
Servidor respondeu?
|
+-- NÃO --> problema de rede/protocolo
|
+-- SIM
|
v
Certificate
|
v
TrustManager
|
+-- rejeitou --> problema de confiança
|
+-- aceitou
|
v
Finished
Essa abordagem é muito mais eficiente do que simplesmente procurar a última linha da stack trace.
39. Como localizar rapidamente a causa em um log gigantesco
Suponha que você execute:
java -Djavax.net.debug=ssl,handshake,trustmanager -jar app.jar \
> ssl.log 2>&1
Depois:
grep -Ei "exception|fatal|error|failed|unable|trust|certificate" ssl.log
Ou:
grep -Ei "PKIX|certificate|handshake_failure|protocol_version|unknown_ca" ssl.log
No Linux, isso é muito útil.
Você também pode:
less ssl.log
e procurar com:
/handshake_failure
40. Salvando o debug em arquivo
Uma estratégia que recomendo:
java \
-Djavax.net.debug=ssl,handshake,trustmanager \
-jar app.jar \
> ssl-debug.log 2>&1
Agora você tem:
ssl-debug.log
Para acompanhar em tempo real:
tail -f ssl-debug.log
Ou:
tail -f ssl-debug.log | grep -Ei "certificate|trust|error|fatal"
41. Cuidado com informações sensíveis
Esse é um ponto muito importante.
O debug TLS pode revelar:
- nomes de hosts;
- certificados;
- detalhes da infraestrutura;
- informações de negociação;
- dados hexadecimais;
- eventualmente informações sensíveis, dependendo das opções ativadas.
Por isso:
não deixe javax.net.debug=all permanentemente habilitado em produção.
Especialmente evite:
plaintext
sem uma justificativa clara.
42. Como usar em Spring Boot
Suponha:
java -jar minha-api.jar
Use:
java \
-Djavax.net.debug=ssl,handshake,trustmanager \
-jar minha-api.jar
Se estiver usando Docker:
ENTRYPOINT [
"java",
"-Djavax.net.debug=ssl,handshake,trustmanager",
"-jar",
"app.jar"
]
Mas, para diagnóstico temporário, prefiro configurar através da execução:
docker run \
... \
minha-imagem
ou por uma variável/configuração específica do ambiente, evitando deixar a imagem permanentemente em modo debug.
43. Spring Boot + Maven
Durante desenvolvimento:
mvn spring-boot:run \
-Dspring-boot.run.jvmArguments="-Djavax.net.debug=ssl,handshake"
Para incluir TrustManager:
mvn spring-boot:run \
-Dspring-boot.run.jvmArguments="-Djavax.net.debug=ssl,handshake,trustmanager"
44. IntelliJ IDEA
No IntelliJ, você pode colocar:
-Djavax.net.debug=ssl,handshake
no campo:
VM options
Não coloque em:
Program arguments
A distinção é:
VM options
↓
-Djavax.net.debug=ssl,handshake
Program arguments
↓
argumentos da sua aplicação
45. Eclipse
Na configuração de execução da aplicação:
Run Configurations
↓
Arguments
↓
VM arguments
adicione:
-Djavax.net.debug=ssl,handshake
46. Kubernetes
Em Kubernetes, se você estiver usando uma aplicação Java:
java -Djavax.net.debug=ssl,handshake -jar app.jar
é importante considerar que o volume de logs pode aumentar bastante.
Para uma investigação temporária, é melhor habilitar o debug somente no pod/ambiente necessário e desativá-lo depois.
47. Uma abordagem profissional de diagnóstico
Eu recomendo seguir esta sequência.
Nível 1 — handshake
-Djavax.net.debug=ssl,handshake
Pergunta:
Onde o handshake está falhando?
Nível 2 — certificados
-Djavax.net.debug=ssl,handshake,trustmanager
Pergunta:
O Java confia no certificado apresentado?
Nível 3 — mTLS
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
Pergunta:
O cliente apresentou o certificado correto e o servidor é confiável?
Nível 4 — detalhes
-Djavax.net.debug=ssl,handshake,verbose
Pergunta:
Qual informação adicional está faltando?
Nível 5 — protocolo
-Djavax.net.debug=ssl,handshake,record,packet
Pergunta:
O que exatamente está acontecendo no nível dos TLS records?
Nível 6 — tudo
-Djavax.net.debug=all
Somente quando realmente necessário.
48. Diagnóstico por tipo de erro
Uma "cola" útil:
| Erro | Primeira tentativa |
|---|---|
PKIX path building failed |
ssl,handshake,trustmanager |
unable to find valid certification path |
ssl,handshake,trustmanager |
certificate_unknown |
ssl,handshake,trustmanager |
handshake_failure |
ssl,handshake |
protocol_version |
ssl,handshake |
no appropriate protocol |
ssl,handshake |
no cipher suites in common |
ssl,handshake |
bad_certificate |
ssl,handshake,trustmanager |
| problema de certificado cliente | ssl,handshake,keymanager |
| mTLS | ssl,handshake,keymanager,trustmanager |
| problema de sessão | ssl,handshake,session |
| problema muito baixo nível | ssl,handshake,record,packet |
49. Uma observação importante sobre Java 21
Como você utiliza Java 21 em seus projetos, vale observar que o comportamento e a quantidade/formatação do debug podem variar entre versões do JDK.
A própria documentação do JSSE alerta que o output do debug é não padronizado e pode mudar entre releases. Além disso, a implementação SunJSSE é a principal referência para essas opções; outros providers podem ter comportamento diferente. (Oracle Docs)
Por isso, se estiver investigando um problema em:
Java 21
é uma boa prática realizar o diagnóstico utilizando o mesmo JDK 21 que executa a aplicação, e não necessariamente outro Java instalado na máquina.
50. Uma diferença importante: debug Java x captura de rede
Existem duas formas complementares de investigar TLS.
Debug do Java
-Djavax.net.debug=ssl,handshake
Mostra:
o que o JSSE está fazendo
Captura de rede
Ferramentas como Wireshark mostram:
o que efetivamente passou pela rede
Conceitualmente:
JAVA
|
javax.net.debug
|
v
JSSE/TLS
|
|
v
TCP
|
captura de rede
|
v
SERVIDOR
Quando um problema é muito difícil, usar ambos pode ser extremamente poderoso.
51. Um "kit" de comandos para guardar
Diagnóstico básico
-Djavax.net.debug=ssl,handshake
Certificados
-Djavax.net.debug=ssl,handshake,trustmanager
mTLS
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
Handshake detalhado
-Djavax.net.debug=ssl,handshake,verbose
Hexadecimal
-Djavax.net.debug=ssl,handshake,data
TLS records
-Djavax.net.debug=ssl,record
Pacotes
-Djavax.net.debug=ssl,record,packet
Tudo
-Djavax.net.debug=all
Descobrir opções disponíveis
-Djavax.net.debug=help
52. Minha recomendação prática para desenvolvedores Java
Não comece assim:
-Djavax.net.debug=all
Comece assim:
-Djavax.net.debug=ssl,handshake
Se aparecer algo relacionado a certificado:
-Djavax.net.debug=ssl,handshake,trustmanager
Se for mTLS:
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
Só depois avance para:
-Djavax.net.debug=ssl,handshake,verbose,record
e, em último caso:
-Djavax.net.debug=all
A ideia é aumentar progressivamente o nível de informação, em vez de produzir milhares de linhas de log desde o início.
53. Fluxograma mental para usar o javax.net.debug
Guarde este raciocínio:
Aplicação Java
|
v
Conexão TLS
|
v
-Djavax.net.debug=
ssl,handshake
|
v
ClientHello?
/ \
NÃO SIM
| |
problema de v
conexão/protocolo ServerHello?
/ \
NÃO SIM
| |
protocolo v
Certificate?
/ \
NÃO SIM
| |
protocolo v
TrustManager
|
certificado aceito?
/ \
NÃO SIM
| |
PKIX v
KeyManager?
|
(se mTLS)
|
v
Finished
|
v
TLS OK
Esse modelo mental é muito mais útil do que tentar decorar centenas de linhas do log.
54. Resumo final
O parâmetro:
-Djavax.net.debug=ssl,handshake
é uma das ferramentas mais importantes para diagnosticar problemas TLS em aplicações Java.
As quatro combinações que eu deixaria salvas são:
# 1. Diagnóstico geral
-Djavax.net.debug=ssl,handshake
# 2. Problemas de certificado
-Djavax.net.debug=ssl,handshake,trustmanager
# 3. mTLS / certificado do cliente
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
# 4. Investigação avançada
-Djavax.net.debug=ssl,handshake,verbose,record
E lembre-se da regra mais importante:
handshakemostra como a negociação TLS está acontecendo;trustmanagerajuda a descobrir por que o Java confia ou não no certificado;keymanagerajuda a descobrir qual certificado o próprio cliente está tentando apresentar.
A documentação oficial do Oracle Java/JSSE é a referência para as opções disponíveis e seus significados. (Oracle Docs)