Truques para depurar problemas de certificado TLS com openssl

1. Fundamentos da Depuração TLS com OpenSSL

A depuração de problemas de certificados TLS exige compreensão da estrutura X.509 e das cadeias de confiança. O OpenSSL fornece um conjunto de ferramentas de linha de comando que permitem inspecionar cada aspecto do ecossistema TLS. A diferença fundamental entre validação local e remota está no contexto: localmente verificamos arquivos de certificado estáticos, enquanto remotamente testamos o handshake completo com um servidor.

Os comandos essenciais para começar são:

# Verificar versão do OpenSSL e recursos disponíveis
openssl version -a

# Listar comandos disponíveis para certificados
openssl list -commands | grep -E "x509|s_client|verify|ocsp"

2. Inspecionando Certificados Locais com openssl x509

O comando openssl x509 é a ferramenta primária para examinar certificados armazenados localmente. Para extrair informações detalhadas:

# Visualizar todos os campos do certificado em formato legível
openssl x509 -in certificado.pem -text -noout

# Extrair apenas período de validade
openssl x509 -in certificado.pem -dates -noout

# Verificar Subject Alternative Names (SANs)
openssl x509 -in certificado.pem -ext subjectAltName -noout

# Obter fingerprint SHA256
openssl x509 -in certificado.pem -fingerprint -sha256 -noout

# Converter de PEM para DER
openssl x509 -in certificado.pem -outform DER -out certificado.der

# Extrair informações do emissor e sujeito
openssl x509 -in certificado.pem -issuer -subject -noout

3. Testando Conexões TLS Remotas com openssl s_client

Para depurar conexões remotas, openssl s_client simula um cliente TLS completo:

# Conexão básica com servidor HTTPS
openssl s_client -connect exemplo.com:443

# Especificar SNI para servidores com múltiplos hosts virtuais
openssl s_client -connect exemplo.com:443 -servername exemplo.com

# Visualizar apenas o certificado do servidor
openssl s_client -connect exemplo.com:443 -showcerts </dev/null 2>/dev/null | openssl x509 -text -noout

# Testar protocolo TLS específico (ex: TLS 1.2)
openssl s_client -connect exemplo.com:443 -tls1_2

# Listar cipher suites suportadas pelo servidor
openssl s_client -connect exemplo.com:443 -cipher 'ALL:COMPLEMENTOFALL' </dev/null 2>/dev/null | grep "Cipher is"

4. Verificando Cadeias de Certificados com openssl verify

A validação da cadeia de confiança é crítica para identificar problemas de encadeamento:

# Verificar certificado contra CA raiz
openssl verify -CAfile ca-root.pem certificado.pem

# Verificar com certificados intermediários
openssl verify -CAfile ca-bundle.pem -untrusted intermediario.pem certificado.pem

# Verificar cadeia completa a partir do servidor
openssl s_client -connect exemplo.com:443 -showcerts </dev/null 2>/dev/null | \
  sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > cadeia.pem
openssl verify -CAfile ca-bundle.pem cadeia.pem

# Ignorar erros específicos para debug (não use em produção)
openssl verify -CAfile ca-bundle.pem -partial_chain certificado.pem

Erros comuns identificados:

# Certificado expirado
error 10 at 0 depth lookup: certificate has expired

# Certificado auto-assinado
error 18 at 0 depth lookup: self signed certificate

# Problema de cadeia incompleta
error 2 at 1 depth lookup: unable to get issuer certificate

5. Depurando Problemas de Validade Temporal e CRL/OCSP

Problemas de tempo são frequentes em ambientes de desenvolvimento e teste:

# Verificar diferença entre data do sistema e validade do certificado
date
openssl x509 -in certificado.pem -enddate -noout | cut -d= -f2

# Testar revogação via OCSP
openssl ocsp -issuer ca.pem -cert certificado.pem -url http://ocsp.exemplo.com -resp_text

# Simular renovação com certificado auto-assinado de curta duração
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 30 -nodes

6. Detectando Problemas de Configuração de Servidor

Problemas de configuração do servidor são comuns e podem ser diagnosticados:

# Verificar mismatch entre CN/SAN e domínio
openssl s_client -connect exemplo.com:443 -servername exemplo.com </dev/null 2>/dev/null | \
  openssl x509 -noout -ext subjectAltName

# Verificar ordem correta da cadeia (leaf primeiro, depois intermediários)
openssl s_client -connect exemplo.com:443 -showcerts </dev/null 2>/dev/null | \
  grep -E "^\s+Subject:|^\s+Issuer:"

# Testar suporte a TLS 1.3
openssl s_client -connect exemplo.com:443 -tls1_3 </dev/null 2>/dev/null | grep "Protocol"

7. Usando OpenSSL para Debug de Certificados em Aplicações

Para simular requisições de aplicações específicas:

# Simular requisição com cipher suite específica
openssl s_client -connect exemplo.com:443 -cipher 'ECDHE-RSA-AES128-GCM-SHA256' </dev/null

# Extrair certificado de conexão ativa para análise offline
openssl s_client -connect exemplo.com:443 -showcerts </dev/null 2>/dev/null | \
  sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' | \
  head -n 30 > servidor_cert.pem

# Gerar certificado auto-assinado com SANs para testes
openssl req -x509 -newkey rsa:2048 -keyout test-key.pem -out test-cert.pem -days 365 -nodes \
  -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,DNS:test.local,IP:127.0.0.1"

8. Ferramentas Complementares e Automação com Scripts

Combinar OpenSSL com ferramentas Unix acelera a depuração:

# Monitorar expiração de certificados em lote
for cert in *.pem; do
  echo -n "$cert: "
  openssl x509 -in "$cert" -enddate -noout | cut -d= -f2
done

# Script para verificar expiração com alerta
#!/bin/bash
CERT="certificado.pem"
EXPIRE=$(openssl x509 -in "$CERT" -enddate -noout | cut -d= -f2)
EXPIRE_EPOCH=$(date -d "$EXPIRE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRE_EPOCH - $NOW_EPOCH) / 86400 ))
echo "Dias até expiração: $DAYS_LEFT"

# Combinar com curl para debug completo
curl -v https://exemplo.com 2>&1 | grep -E "SSL|TLS|certificate|error"

# Usar wget para análise de cadeia
wget --debug https://exemplo.com 2>&1 | grep -A5 "certificate"
# Pipeline completo de depuração
openssl s_client -connect exemplo.com:443 -servername exemplo.com -showcerts \
  </dev/null 2>/dev/null | \
  openssl x509 -noout -text | grep -E "Subject:|Issuer:|Not Before|Not After|DNS:"

Referências