# 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:

```text
javax.net.ssl.SSLHandshakeException: PKIX path building failed
```

ou:

```text
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
```

ou ainda:

```text
javax.net.ssl.SSLException: Received fatal alert: protocol_version
```

Nesses casos, uma das ferramentas mais úteis do próprio Java é:

```bash
-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])

---

# 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:

```bash
java -Djavax.net.debug=ssl,handshake -jar minha-aplicacao.jar
```

O ponto importante é entender que:

```text
-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:

```text
-Djavax.net.debug=ssl,handshake
```

### `-D`

Indica que estamos definindo uma **System Property da JVM**.

É equivalente, dentro do Java, a:

```java
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:

```bash
-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][1])

---

# 3. Antes de tudo: SSL x TLS

Apesar de o parâmetro se chamar:

```text
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:

```text
TLSv1.3
```

e ainda assim o debug será ativado através de:

```bash
-Djavax.net.debug=ssl
```

É comum encontrar no log coisas como:

```text
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:

```text
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:

```text
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][1])

---

# 5. Primeiro teste: `ssl,handshake`

Para uma aplicação Java simples:

```bash
java -Djavax.net.debug=ssl,handshake -jar app.jar
```

Se você estiver executando uma aplicação Spring Boot:

```bash
java -Djavax.net.debug=ssl,handshake -jar minha-api.jar
```

Se estiver usando Maven:

```bash
mvn spring-boot:run \
  -Dspring-boot.run.jvmArguments="-Djavax.net.debug=ssl,handshake"
```

No Gradle:

```bash
./gradlew bootRun \
  --args=''
```

ou configure a JVM da tarefa `bootRun` para receber:

```text
-Djavax.net.debug=ssl,handshake
```

---

# 6. Atenção: `-D` não é argumento da aplicação

Um erro bastante comum é colocar:

```bash
java -jar app.jar -Djavax.net.debug=ssl,handshake
```

Isso está errado para esse propósito.

O correto é:

```bash
java -Djavax.net.debug=ssl,handshake -jar app.jar
```

A diferença é:

```text
java
  |
  +-- opções da JVM
  |      |
  |      +-- -Djavax.net.debug=...
  |
  +-- -jar
         |
         +-- aplicação
```

---

# 7. O primeiro nível: `ssl`

Você pode começar simplesmente com:

```bash
-Djavax.net.debug=ssl
```

Exemplo:

```bash
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][1])

---

# 8. `ssl,handshake`: o modo mais útil para começar

Na prática, este é um dos comandos que eu mais recomendo para investigação:

```bash
-Djavax.net.debug=ssl,handshake
```

Ele permite enxergar mensagens como:

```text
ClientHello
ServerHello
Certificate
CertificateVerify
Finished
```

e informações relacionadas à negociação.

Por exemplo, você pode encontrar algo parecido com:

```text
"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:

```bash
-Djavax.net.debug=ssl,handshake,trustmanager
```

Exemplo:

```bash
java \
  -Djavax.net.debug=ssl,handshake,trustmanager \
  -jar app.jar
```

Essa combinação é extremamente útil para problemas como:

```text
PKIX path building failed
```

```text
unable to find valid certification path
```

```text
unable to find valid certification path to requested target
```

```text
SunCertPathBuilderException
```

---

# 10. Por que `trustmanager` é tão importante?

Durante uma conexão TLS, o servidor normalmente envia seu certificado:

```text
Servidor
   |
   | Certificate
   v
Java
```

O Java precisa decidir:

> "Eu confio nesse certificado?"

Para isso entra em ação o `TrustManager`.

Simplificadamente:

```text
Certificate recebido
        |
        v
    TrustManager
        |
        v
  Truststore Java
        |
        v
  certificado confiável?
      /       \
    SIM        NÃO
     |          |
     v          v
 continua     falha
```

O debug:

```bash
-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:

```text
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:

```bash
java \
  -Djavax.net.debug=ssl,handshake,trustmanager \
  -jar app.jar
```

Procure no log por palavras como:

```text
trust
TrustManager
certificate
X509
PKIX
trusted
server certificate
```

Você poderá descobrir, por exemplo, que o servidor apresentou:

```text
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 é:

```text
javax.net.ssl.trustStore
```

Por exemplo:

```bash
-Djavax.net.ssl.trustStore=/opt/app/certs/truststore.p12
```

Você pode combinar:

```bash
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:

```bash
-Djavax.net.ssl.trustStoreType=PKCS12
```

E eventualmente:

```bash
-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:

```text
             TLS
Java <----------------> Servidor
 |                         |
 | certificado cliente     |
 +------------------------>|
```

Você pode precisar investigar o `KeyManager`.

Use:

```bash
-Djavax.net.debug=ssl,handshake,keymanager
```

Por exemplo:

```bash
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**.

```text
Servidor
   |
   | certificado
   v
TrustManager
```

---

## `KeyManager`

Pergunta:

> "Qual certificado/chave eu devo apresentar?"

Normalmente relacionado ao certificado **do próprio cliente**.

```text
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:

```bash
-Djavax.net.debug=ssl,sslctx
```

ou:

```bash
-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:

```text
SSLContext
   |
   +-- KeyManager
   |
   +-- TrustManager
   |
   +-- protocolos
   |
   +-- cipher suites
```

---

# 16. `defaultctx`

Para investigar a inicialização do contexto SSL padrão:

```bash
-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:

```bash
-Djavax.net.debug=ssl,session
```

ou:

```bash
-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:

```bash
-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.

```bash
-Djavax.net.debug=ssl,record
```

Enquanto:

```text
handshake
```

mostra as mensagens do handshake, `record` mostra informações sobre os **TLS records**.

A estrutura conceitual é:

```text
Aplicação
    |
    v
TLS Handshake
    |
    v
TLS Records
    |
    v
TCP
```

Portanto:

```text
handshake
```

é geralmente mais amigável para diagnóstico.

Já:

```text
record
```

é mais detalhado.

---

# 20. `packet`

Você pode adicionar:

```bash
-Djavax.net.debug=ssl,record,packet
```

Isso permite visualizar informações de pacotes TLS em nível mais baixo.

Por exemplo:

```bash
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:

```bash
-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:

```bash
-Djavax.net.debug=ssl,handshake,data
```

Ela adiciona dumps hexadecimais das mensagens de handshake.

Exemplo conceitual:

```text
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:

```text
ssl,handshake
```

é suficiente.

---

# 23. `verbose`

Você também pode usar:

```bash
-Djavax.net.debug=ssl,handshake,verbose
```

Isso aumenta a quantidade de detalhes exibidos durante o handshake.

Uma combinação possível:

```bash
-Djavax.net.debug=ssl,handshake,verbose
```

E ainda mais detalhada:

```bash
-Djavax.net.debug=ssl,handshake,verbose,data
```

---

# 24. `all`

Existe:

```bash
-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][1])

Eu recomendo **não começar com `all`**.

Prefira:

```bash
-Djavax.net.debug=ssl,handshake
```

e vá aumentando conforme a necessidade.

---

# 25. `help`

Existe uma opção especialmente útil:

```bash
-Djavax.net.debug=help
```

Por exemplo:

```bash
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][1])

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:

```bash
-Djavax.net.debug=ssl,handshake
```

e:

```bash
-Djavax.net.debug=ssl:handshake
```

Ambos são aceitos.

Também é possível encontrar:

```bash
-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][1])

Eu prefiro:

```bash
-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:

```bash
-Djavax.net.debug=ssl,handshake
```

Para problemas de certificado:

```bash
-Djavax.net.debug=ssl,handshake,trustmanager
```

Para mTLS:

```bash
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
```

Para investigação mais profunda:

```bash
-Djavax.net.debug=ssl,handshake,verbose
```

Para análise de protocolo:

```bash
-Djavax.net.debug=ssl,handshake,record,packet
```

Para investigação extremamente detalhada:

```bash
-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][1])

---

# 29. Como interpretar o `ClientHello`

Um dos primeiros pontos importantes no log será algo relacionado a:

```text
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:

```text
ClientHello
    client version
    random
    session id
    cipher suites
    compression methods
    extensions
```

As extensões são especialmente importantes.

Por exemplo:

```text
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:

```text
"supported_versions": [
    TLSv1.3,
    TLSv1.2
]
```

Isso significa que o cliente está anunciando suporte a essas versões.

Se o servidor só suporta:

```text
TLSv1.0
```

por exemplo, pode ocorrer incompatibilidade.

---

# 31. Identificando problemas de versão TLS

Imagine:

```text
Client:
TLSv1.3
TLSv1.2
```

e o servidor:

```text
TLSv1.0
```

Dependendo das configurações de segurança do JDK, a conexão pode falhar.

Você poderá encontrar:

```text
SSLHandshakeException
```

ou:

```text
protocol_version
```

ou:

```text
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:

```text
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:

```text
Java                  Servidor

AES/GCM       <----X---->    cipher incompatível
ChaCha20      <----X---->    cipher incompatível
...
```

pode aparecer:

```text
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:

```text
Certificate
```

A partir dela você consegue investigar coisas como:

```text
Subject
Issuer
Validity
Key type
Certificate chain
```

Por exemplo:

```text
Subject: CN=api.exemplo.com
Issuer: CN=Minha CA Corporativa
```

Isso é extremamente útil quando:

```text
curl funciona
```

mas:

```text
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:

```text
Servidor
   |
   +-- certificado
       |
       +-- CA corporativa
```

O navegador funciona.

O `curl` funciona.

Mas Java retorna:

```text
PKIX path building failed
```

Nesse caso, investigue:

```bash
-Djavax.net.debug=ssl,handshake,trustmanager
```

e descubra:

1. Qual certificado o servidor enviou.
2. Qual é o `Issuer`.
3. Qual cadeia foi construída.
4. Qual truststore foi utilizado.
5. Qual certificado/CA está faltando.

---

# 35. Cadeia de certificados

Considere:

```text
Root CA
   |
   v
Intermediate CA
   |
   v
api.exemplo.com
```

O Java precisa conseguir construir uma cadeia confiável:

```text
api.exemplo.com
       |
       v
Intermediate CA
       |
       v
Root CA
       |
       v
Truststore
```

Se faltar:

```text
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:

```text
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:

```text
https://api.exemplo.com
```

o nome do host pode ser enviado no TLS através da extensão:

```text
server_name
```

Isso é conhecido como **SNI — Server Name Indication**.

O debug pode mostrar algo semelhante a:

```text
server_name
    type=host_name
    value=api.exemplo.com
```

Isso é importante porque servidores modernos podem hospedar vários certificados no mesmo IP.

Por exemplo:

```text
                 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:

```java
RestClient
   |
   v
https://api.empresa.com
```

e você recebe:

```text
SSLHandshakeException:
PKIX path building failed
```

Comece:

```bash
-Djavax.net.debug=ssl,handshake
```

Se ainda não estiver claro:

```bash
-Djavax.net.debug=ssl,handshake,trustmanager
```

Depois procure:

```text
ClientHello
ServerHello
Certificate
TrustManager
```

O raciocínio é:

```text
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:

```bash
java -Djavax.net.debug=ssl,handshake,trustmanager -jar app.jar \
  > ssl.log 2>&1
```

Depois:

```bash
grep -Ei "exception|fatal|error|failed|unable|trust|certificate" ssl.log
```

Ou:

```bash
grep -Ei "PKIX|certificate|handshake_failure|protocol_version|unknown_ca" ssl.log
```

No Linux, isso é muito útil.

Você também pode:

```bash
less ssl.log
```

e procurar com:

```text
/handshake_failure
```

---

# 40. Salvando o debug em arquivo

Uma estratégia que recomendo:

```bash
java \
  -Djavax.net.debug=ssl,handshake,trustmanager \
  -jar app.jar \
  > ssl-debug.log 2>&1
```

Agora você tem:

```text
ssl-debug.log
```

Para acompanhar em tempo real:

```bash
tail -f ssl-debug.log
```

Ou:

```bash
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:

```text
plaintext
```

sem uma justificativa clara.

---

# 42. Como usar em Spring Boot

Suponha:

```bash
java -jar minha-api.jar
```

Use:

```bash
java \
  -Djavax.net.debug=ssl,handshake,trustmanager \
  -jar minha-api.jar
```

Se estiver usando Docker:

```dockerfile
ENTRYPOINT [
  "java",
  "-Djavax.net.debug=ssl,handshake,trustmanager",
  "-jar",
  "app.jar"
]
```

Mas, para diagnóstico temporário, prefiro configurar através da execução:

```bash
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:

```bash
mvn spring-boot:run \
  -Dspring-boot.run.jvmArguments="-Djavax.net.debug=ssl,handshake"
```

Para incluir TrustManager:

```bash
mvn spring-boot:run \
  -Dspring-boot.run.jvmArguments="-Djavax.net.debug=ssl,handshake,trustmanager"
```

---

# 44. IntelliJ IDEA

No IntelliJ, você pode colocar:

```text
-Djavax.net.debug=ssl,handshake
```

no campo:

```text
VM options
```

Não coloque em:

```text
Program arguments
```

A distinção é:

```text
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:

```text
Run Configurations
    ↓
Arguments
    ↓
VM arguments
```

adicione:

```text
-Djavax.net.debug=ssl,handshake
```

---

# 46. Kubernetes

Em Kubernetes, se você estiver usando uma aplicação Java:

```text
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

```bash
-Djavax.net.debug=ssl,handshake
```

Pergunta:

> Onde o handshake está falhando?

---

## Nível 2 — certificados

```bash
-Djavax.net.debug=ssl,handshake,trustmanager
```

Pergunta:

> O Java confia no certificado apresentado?

---

## Nível 3 — mTLS

```bash
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
```

Pergunta:

> O cliente apresentou o certificado correto e o servidor é confiável?

---

## Nível 4 — detalhes

```bash
-Djavax.net.debug=ssl,handshake,verbose
```

Pergunta:

> Qual informação adicional está faltando?

---

## Nível 5 — protocolo

```bash
-Djavax.net.debug=ssl,handshake,record,packet
```

Pergunta:

> O que exatamente está acontecendo no nível dos TLS records?

---

## Nível 6 — tudo

```bash
-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][1])

Por isso, se estiver investigando um problema em:

```text
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

```bash
-Djavax.net.debug=ssl,handshake
```

Mostra:

```text
o que o JSSE está fazendo
```

### Captura de rede

Ferramentas como Wireshark mostram:

```text
o que efetivamente passou pela rede
```

Conceitualmente:

```text
                 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

```bash
-Djavax.net.debug=ssl,handshake
```

### Certificados

```bash
-Djavax.net.debug=ssl,handshake,trustmanager
```

### mTLS

```bash
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
```

### Handshake detalhado

```bash
-Djavax.net.debug=ssl,handshake,verbose
```

### Hexadecimal

```bash
-Djavax.net.debug=ssl,handshake,data
```

### TLS records

```bash
-Djavax.net.debug=ssl,record
```

### Pacotes

```bash
-Djavax.net.debug=ssl,record,packet
```

### Tudo

```bash
-Djavax.net.debug=all
```

### Descobrir opções disponíveis

```bash
-Djavax.net.debug=help
```

---

# 52. Minha recomendação prática para desenvolvedores Java

Não comece assim:

```bash
-Djavax.net.debug=all
```

Comece assim:

```bash
-Djavax.net.debug=ssl,handshake
```

Se aparecer algo relacionado a certificado:

```bash
-Djavax.net.debug=ssl,handshake,trustmanager
```

Se for mTLS:

```bash
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
```

Só depois avance para:

```bash
-Djavax.net.debug=ssl,handshake,verbose,record
```

e, em último caso:

```bash
-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:

```text
              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:

```bash
-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:

```bash
# 1. Diagnóstico geral
-Djavax.net.debug=ssl,handshake
```

```bash
# 2. Problemas de certificado
-Djavax.net.debug=ssl,handshake,trustmanager
```

```bash
# 3. mTLS / certificado do cliente
-Djavax.net.debug=ssl,handshake,keymanager,trustmanager
```

```bash
# 4. Investigação avançada
-Djavax.net.debug=ssl,handshake,verbose,record
```

E lembre-se da regra mais importante:

> **`handshake` mostra como a negociação TLS está acontecendo; `trustmanager` ajuda a descobrir por que o Java confia ou não no certificado; `keymanager` ajuda 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][1])

[Java Secure Socket Extension (JSSE) Reference Guide](https://docs.oracle.com/en/java/javase/25/security/java-secure-socket-extension-jsse-reference-guide.html?utm_source=chatgpt.com)

[Java SE 21 Security Developer's Guide](https://docs.oracle.com/en/java/javase/21/security/?utm_source=chatgpt.com)

[1]: https://docs.oracle.com/en/java/javase/25/security/java-secure-socket-extension-jsse-reference-guide.html?utm_source=chatgpt.com "Java Secure Socket Extension (JSSE) Reference Guide"

