Mensagem de erro
PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed
Também aparece como
- javax.net.ssl.SSLHandshakeException: (certificate_expired) PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed
A partir do JDK 21, o alerta TLS vem na frente: “(certificate_expired) PKIX path validation failed: …”. A linha da causa raiz é “java.security.cert.CertificateExpiredException: NotAfter: <date>” (ou CertificateNotYetValidException: NotBefore: <date>), com a data no fuso horário da JVM.
Java (JSSE) — SSLHandshakeException caused by CertPathValidatorException / CertificateExpiredException
O que significa
O Java montou um caminho de certificados até uma âncora de confiança, mas a validação desse caminho falhou na verificação de datas: um certificado do caminho está fora do período de validade no horário atual da JVM. “Path validation” (e não “path building”) indica que a confiança estava em ordem; as datas, não. A CertificateExpiredException ou CertificateNotYetValidException aninhada indica qual limite foi violado.
Por que acontece
O certificado do servidor (ou o intermediário) expirou
comumA renovação não aconteceu, ou o certificado renovado não foi implantado no endpoint com que o Java se comunica (muitas vezes um balanceador de carga interno ou um servidor Java com o próprio keystore).
A cadeia foi montada passando por um certificado expirado em um trust store personalizado
ocasionalTrust stores que fixam diretamente um intermediário antigo ou um certificado de servidor continuam validando com base nele depois que ele expira.
O relógio do host da JVM está errado
ocasionalMáquinas virtuais e contêineres cujo relógio do host se desviou podem fazer certificados em dia parecerem expirados ou ainda não válidos.
Um certificado recém-emitido e um relógio atrasado
raraCertificados válidos a partir de “agora” falham em clientes com o relógio alguns minutos atrasado; por isso, a maioria das CAs retrocede um pouco o notBefore, mas CAs privadas muitas vezes não fazem isso.
Como corrigir
- 1.
Ler a causa mais interna
A data em NotAfter ou NotBefore mostra se um certificado expirou ou se o relógio está errado.
text Caused by: java.security.cert.CertificateExpiredException: NotAfter: Tue Apr 01 00:00:00 UTC 2025 -> a certificate in the chain expired on that date Caused by: java.security.cert.CertificateNotYetValidException: NotBefore: ... -> not valid yet: check the clock of this machine - 2.
Verificar cada certificado que o servidor envia
Imprima a data de término de cada certificado da cadeia servida; substitua o que tiver expirado.
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts 2>/dev/null \ | awk '/BEGIN CERT/{n++; f="c" n ".pem"} /BEGIN CERT/,/END CERT/{print > f}' for f in c*.pem; do openssl x509 -in "$f" -noout -subject -enddate; done - 3.
Limpar trust stores personalizados
Liste as entradas do trust store com a validade de cada uma e remova ou substitua os certificados expirados que foram fixados ali.
bash # Expired or pinned certificates in a custom trust store keytool -list -v -keystore app-truststore.p12 -storepass changeit | grep -E 'Alias name|Valid until|Owner' keytool -delete -alias old-corp-root -keystore app-truststore.p12 -storepass changeit