Boa noite, segue publicação do tópico das falhas ocorridas, com informações obtidas de testes, relatos de diversos grupos e colegas do forum, de alguns grupos Whats e GT GNFSe, para auxiliar quem está experimentando problemas.
Grato também pela participação do Aured Rodrigues, Otávio Montemezzo, e Vinícius Bonfinger, que compartilharam experiências do problema que afetou a todos, muitos em aplicações JAVA e/ou Oracle, bem como outros clientes em outras plataformas, após o ajuste WAF no ADN, que seria transparente e sem efeitos colaterais.
Problema reportado — Comunicação com adn.nfse.gov.br após alteração no WAF
1. Contexto
Após alterações na infraestrutura de comunicação, incluindo a utilização do WAF/balanceador para acesso ao servidor adn.nfse.gov.br, alguns clientes passaram a enfrentar falhas na comunicação utilizando certificados digitais e-CNPJ A1.
Os problemas foram observados principalmente em aplicações Java, inclusive em ambientes Oracle/OJVM.
Certificados que funcionavam normalmente antes da alteração passaram a apresentar falhas durante o estabelecimento da conexão TLS.
2. Problema principal — Apresentação do certificado A1
Causa identificada
Após o Serpro instalar um sistema WAF (Web Application Firewall) para melhorar a segurança, inicaram os problemas de falhas TLS para quem usa o ADN. Quando um WAF é introduzido e configurado para exigir autenticação mútua TLS (mTLS), ele assume o papel de terminação TLS. E aí começaram os problemas…
Se o WAF enviar uma lista de Autoridades Certificadoras (CA) - Certificate Authorities - no handshake TLS que não dê uma correspondência exata com a cadeia emissora do certificado contido no .pfx/.p12 do cliente, o SunX509KeyManager do Java simplesmente ignora o certificado e envia uma resposta vazia ao servidor (Certificate Length: 0), quebrando a conexão.
Em aplicações Java que utilizam o KeyManager padrão (SunX509), a seleção do certificado cliente pode depender da correspondência entre a cadeia existente no .pfx/.p12 e as CAs anunciadas pelo servidor.
Quando o PFX contém somente o certificado A1, sem a cadeia intermediária necessária, o Java pode não encontrar uma correspondência e não apresentar o certificado cliente durante o handshake.
O servidor, aguardando o certificado A1, encerra a conexão.
Sintomas
Dependendo do ambiente, o cliente pode receber erros como:
-
bad record mac— OpenSSL; -
AEADBadTagException: Tag mismatch— Java; -
handshake_failure; -
erros criptográficos genéricos;
-
encerramento abrupto da conexão TLS 1.3, sem um alerta TLS suficientemente claro.
Isso dificulta a identificação da causa, pois o erro apresentado ao cliente pode aparentar ser uma falha de criptografia, quando, na realidade, o certificado cliente não foi apresentado durante o handshake.
3. Contorno 1 — Reempacotamento do certificado A1
Uma alternativa (FÁCIL e RÁPIDA) identificada foi exportar/reempacotar o certificado A1 contendo a cadeia completa de certificação, incluindo as autoridades intermediárias até a raiz ICP-Brasil.
Como referência, foram observados PFXs com aproximadamente:
-
3 a 4 KB: certificado sem as demais cadeias;
-
10 a 14 KB: certificado acompanhado da cadeia completa.
Com a cadeia completa, o Java consegue encontrar uma CA compatível com aquelas anunciadas pelo servidor e apresentar o certificado.
Essa alternativa, porém, possui impacto operacional, pois exige a correção dos arquivos PFX individualmente.
4. Contorno 2 — KeyManager customizado
Alguns clientes resolveram o problema alterando o comportamento de seleção do certificado no Java.
Foi implementado em um dos casos relatados, um KeyManager customizado. O uso de um KeyManager customizado (reescrevendo o método chooseClientAlias) combinado com a injeção forçada do hostname via SNIHostName nas SSLParameters é uma solução técnica robusta e comumente utilizada no ambiente Java para resolver problemas de autenticação mútua (mTLS) e roteamento de handshake TLS. Utilizaram a SSLSocketFactory capturando o hostname (adn.nfse.gov.br) da URL e o injeta forçadamente via SNIHostName diretamente nas SSLParameters de cada soquete aberto.
O SNI (Server Name Indication) é uma extensão do protocolo TLS. Ele permite que o cliente informe ao servidor, logo no início do handshake, qual hostname ele está tentando conectar.
Em vez de deixar o Java decidir exclusivamente com base nas CAs informadas pelo servidor, a implementação força o retorno do alias correspondente ao certificado A1 carregado pela aplicação. Com isso, o certificado configurado é apresentado mesmo quando a cadeia existente no PFX não corresponde à lista de CAs enviada pelo servidor.
Outra implementação equivalente pode utilizar um X509ExtendedKeyManager customizado, com o mesmo objetivo de controlar explicitamente a seleção do certificado, utilizada em outra abordagem para resolver o problema.
Quando um servidor solicita autenticação mútua (mTLS), ele envia um CertificateRequest contendo uma lista de Autoridades de Certificação (ACs) aceitas. O KeyManager padrão do Java analisa essa lista e, se o seu certificado foi assinado por uma AC que não está explicitamente ali, o Java simplesmente não envia o certificado, resultando em falha de conexão (geralmente um erro de Bad Certificate ou Handshake Failure). Substituir o KeyManager padrão por um customizado resolve isso na raiz.
Por padrão, o Java analisa a lista enviada pelo servidor e, se não encontrar um par de chaves correspondente àquelas ACs, o método chooseClientAlias retorna null, fazendo com que a autenticação falhe.
Ao estender X509ExtendedKeyManager este problema é resolvido porque você força o Java a ignorar essa filtragem, você deve estender X509ExtendedKeyManager (e não apenas X509KeyManager, para garantir suporte a extensões modernas e SNI) e sobreescrever os métodos de escolha de alias (chooseClientAlias e chooseEngineClientAlias).
Resultado
Essa abordagem resolveu, para os clientes que a implementaram, a rejeição do certificado durante a comunicação com a Sefaz/NFSe.
Entretanto, trata-se de uma adaptação realizada no lado do cliente e, portanto, exige alterações específicas em cada aplicação/ambiente Java.
5. Compatibilidade de SNI
Além do problema de seleção do certificado, um dos clientes identificou uma necessidade específica relacionada ao SNI (Server Name Indication) no ambiente Oracle/OJVM.
Foi implementada uma SSLSocketFactory customizada, denominada RastreandoSSLSocketFactory, responsável por capturar o hostname utilizado na URL e inseri-lo explicitamente no SSLParameters de cada socket.
Para o serviço em questão, o hostname utilizado é:
adn.nfse.gov.br
A implementação utiliza SNIHostName para garantir que o hostname seja enviado durante o handshake TLS.
Segundo o relato do cliente, essa implementação contornou uma limitação existente no ambiente Oracle utilizado.
Observação
Esse item deve ser tratado separadamente do problema de seleção do certificado A1.
A necessidade de forçar SNI parece estar relacionada à compatibilidade do ambiente Oracle/OJVM com a negociação TLS, enquanto o problema principal descrito anteriormente está relacionado à seleção/apresentação do certificado cliente.
6. Compatibilidade de Cipher Suites
Outro ajuste realizado foi a ampliação das suítes criptográficas oferecidas pelo cliente.
Foi criada uma lista de ciphers preferenciais, denominada CIPHERS_TLS12_PREFERIDAS, contendo suítes consideradas modernas e também aliases utilizados por versões/ambientes antigos do OJVM, incluindo nomes no formato:
SSL_RSA_WITH_...
Além disso, foi implementado um mecanismo de fallback no método escolherPerfilTls.
O objetivo é garantir que o cliente Java consiga oferecer um conjunto de suítes criptográficas compatível com aquelas aceitas pelo ambiente governamental.
Observação
Assim como o SNI, esse ajuste deve ser considerado uma questão de compatibilidade TLS do ambiente cliente, e não necessariamente parte da causa raiz do problema de apresentação do certificado.
Pessoalmente, esta opção restringe as ciphers que geralmente são negociadas pelo sistema operacional de forma automática, apesar de poder indicar, caso tenha mudanças, acaba limitado pela aplicação que sinaliza ao SO utilizar apenas algumas chaves. Podem testar, mas não entendo ser necessária.
7. Resiliência e retentativas
Outra abordagem para evitar falhas, foi a implementação de um mecanismo de retentativa para chamadas HTTP GET.
Quando ocorre uma falha considerada transitória, como:
-
timeout;
-
reset da conexão;
-
queda momentânea da comunicação;
a aplicação aguarda alguns milissegundos e realiza uma nova tentativa. O mecanismo permite até 3 tentativas antes de retornar o erro ao PL/SQL.
Essa implementação aumenta a resiliência da integração diante de falhas temporárias de rede ou de conexão.
Observação
A retentativa não corrige problemas determinísticos de handshake TLS ou seleção de certificado. Ela atua apenas sobre falhas consideradas potencialmente transitórias. Se o problema é corrigir a comunicação, não tente implementar neste momento.
8. Diagnóstico detalhado
Uma das sugestões foi a implementação de um mecanismo de diagnóstico denominado DIAGNOSTICO_COMPLETO.
O objetivo é aumentar a capacidade de identificar em qual etapa da comunicação ocorre a falha, permitindo diferenciar problemas relacionados a:
-
carregamento do certificado;
-
seleção do certificado cliente;
-
SNI;
-
versão TLS;
-
cipher suite;
-
estabelecimento do handshake;
-
conexão HTTP;
-
timeout/reset;
-
resposta do servidor;
-
retentativas.
Esse tipo de diagnóstico é especialmente importante porque alguns dos erros atualmente retornados pelo ambiente são genéricos e podem mascarar a verdadeira causa da falha.
9. Soluções identificadas nos diferentes clientes
A partir dos relatos recebidos, foram identificados diferentes níveis de tratamento:
| Item | Solução | Objetivo |
|---|---|---|
| Certificado A1 | PFX com cadeia completa | Permitir que o Java encontre uma CA compatível |
| undefined | -— | -— |
| Certificado A1 | CertificadoForcadoKeyManager / X509ExtendedKeyManager |
Forçar a apresentação do certificado A1 |
| undefined | -— | -— |
| SNI | RastreandoSSLSocketFactory |
Garantir o envio do hostname via SNI |
| undefined | -— | -— |
| Cipher Suites | CIPHERS_TLS12_PREFERIDAS + fallback |
Aumentar a compatibilidade TLS |
| undefined | -— | -— |
| Retentativas | Até 3 tentativas para GET | Tratar falhas transitórias |
| undefined | -— | -— |
| Diagnóstico | DIAGNOSTICO_COMPLETO |
Facilitar a identificação da etapa da falha |
| undefined | -— | -— |
10. Avaliação geral
Os relatos indicam que existem dois grupos de problemas que precisam ser diferenciados.
Grupo A — Problema de apresentação do certificado cliente
Esse é o problema mais diretamente relacionado à alteração no comportamento do servidor/WAF.
O envio de uma lista restritiva de CAs no CertificateRequest pode fazer com que o KeyManager padrão do Java não selecione o certificado A1, principalmente quando o PFX não contém a cadeia correspondente.
Os principais contornos identificados foram:
-
reempacotar o PFX com a cadeia completa; ou
-
substituir/customizar o
KeyManagerpara forçar a apresentação do certificado.
A correção preferencial deveria ocorrer no lado do servidor/balanceador, ajustando o CertificateRequest para não impor uma restrição incompatível com certificados válidos ou para anunciar corretamente as autoridades certificadoras intermediárias aceitas.
Grupo B — Compatibilidade do ambiente Java/Oracle
SNI, cipher suites, fallback e retentativas são ajustes adicionais realizados por determinados clientes para aumentar a compatibilidade e a resiliência da comunicação.
Esses mecanismos podem ser necessários em determinados ambientes, mas não devem ser confundidos automaticamente com a causa raiz do problema de certificado.
11. Recomendação
Considerando os relatos dos diferentes clientes, recomenda-se avaliar no WAF/balanceador, que depende somente do SERPRO:
-
Quais CAs estão sendo enviadas no
CertificateRequest; -
Se a lista de CAs está excessivamente restritiva;
-
Se as autoridades intermediárias utilizadas pelos certificados A1 estão sendo anunciadas corretamente;
-
Se é possível utilizar uma lista vazia de CAs quando não houver necessidade de restringir os certificados;
-
O comportamento quando o cliente não apresenta certificado;
-
Se o encerramento da conexão está retornando o alerta TLS apropriado;
-
A compatibilidade da negociação de TLS 1.2/TLS 1.3, SNI e cipher suites com ambientes Oracle/OJVM.
A correção no servidor/balanceador é preferível porque evita que cada integrador tenha que implementar soluções específicas, como KeyManager customizado, injeção manual de SNI, ampliação de cipher suites ou mecanismos próprios de diagnóstico.
Dessa forma, clientes Java, OpenSSL e outras tecnologias poderão utilizar certificados A1 válidos sem necessidade de adaptações específicas decorrentes do comportamento do WAF/balanceador.
Boa sorte.
At.te
Emir Toktar