Pular para o conteúdo
ecdsa.com
Java (JSSE, SunX509 trust manager)Java

Mensagem de erro

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Também aparece como

  • javax.net.ssl.SSLHandshakeException: (certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
  • javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
  • unable to find valid certification path to requested target

Os JDKs 21 e 25 acrescentam o alerta TLS como prefixo: “javax.net.ssl.SSLHandshakeException: (certificate_unknown) PKIX path building failed: …”. Logs de JDKs mais antigos mostram “javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: …”. Frameworks e ferramentas de build (Spring, Maven, Gradle, IDEs) encapsulam o erro nas próprias mensagens, mas mantêm o texto PKIX na causa.

Java (JSSE, SunX509 trust manager) — javax.net.ssl.SSLHandshakeException caused by sun.security.validator.ValidatorException

O que significa

O construtor de caminhos de certificação PKIX do Java não conseguiu montar uma cadeia que leve do certificado do servidor a alguma âncora de confiança do trust store que a JVM está usando. O “requested target” é o certificado do servidor. O Java confia apenas no próprio arquivo cacerts (ou no repositório indicado com javax.net.ssl.trustStore), e não no repositório do sistema operacional; por isso, um certificado de uma CA da empresa, de um proxy com inspeção de TLS ou de um servidor que não envia o intermediário falha aqui.

Por que acontece

Como corrigir

  1. 1.

    Ver a cadeia e o trust store em uso

    O openssl s_client mostra o que o servidor envia. Com javax.net.debug=ssl:handshake:verbose, o Java imprime o caminho do trust store que carregou e cada certificado que recebeu.

    bash
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'
    # Or from Java itself: prints the chain and the trust store in use
    java -Djavax.net.debug=ssl:handshake:verbose -jar app.jar 2>&1 | grep -E 'trustStore is|Subject:|Issuer:'
  2. 2.

    Usar um trust store da aplicação que inclua sua raiz

    Copie o cacerts do JDK (para que as CAs públicas continuem funcionando), importe a raiz da empresa ou do proxy com o keytool e aponte a aplicação para essa cópia com javax.net.ssl.trustStore e trustStorePassword (ou JAVA_TOOL_OPTIONS para ferramentas que não são iniciadas por você).

    bash
    # A copy of the JDK's cacerts plus your root: public sites keep working
    cp "$JAVA_HOME/lib/security/cacerts" app-truststore.p12
    keytool -importcert -noprompt -alias corp-root -file corp-root-ca.pem \
      -keystore app-truststore.p12 -storepass changeit
    java -Djavax.net.ssl.trustStore=app-truststore.p12 -Djavax.net.ssl.trustStorePassword=changeit -jar app.jar
  3. 3.

    Importar a raiz no cacerts do JDK

    O comando keytool -cacerts atua sobre o repositório padrão do JDK que executa o keytool (senha “changeit” por padrão). Todas as aplicações desse JDK passam a confiar na raiz; a alteração se perde quando o JDK é substituído.

    bash
    # Add the root to this JDK's default trust store (applies to every app on this JDK;
    # repeat after each JDK upgrade)
    sudo keytool -importcert -noprompt -cacerts -alias corp-root -file corp-root-ca.pem -storepass changeit
  4. 4.

    Contêineres: deixar a imagem importar sua CA

    Quando USE_SYSTEM_CA_CERTS está definida, o entrypoint das imagens Eclipse Temurin adiciona os arquivos *.crt montados em /certificates ao cacerts da JVM na inicialização (isso só acontece com o entrypoint padrão da imagem). Outras imagens precisam da etapa do keytool no Dockerfile.

    bash
    # Eclipse Temurin images: mount your CA(s) as *.crt and let the entrypoint add them to cacerts
    docker run -e USE_SYSTEM_CA_CERTS=1 \
      -v "$PWD/certs:/certificates/" eclipse-temurin:25.0.4.1_1-jdk-noble java -jar /app/app.jar
  5. 5.

    Dar a um único cliente o próprio trust store

    Crie um SSLContext a partir de um TrustManagerFactory inicializado com seu trust store e passe-o para o HttpClient (ou OkHttp, Apache HttpClient, Netty). Nunca instale um trust manager que aceite qualquer certificado.

    java
    // One client with its own trust store (verification stays on)
    KeyStore ts = KeyStore.getInstance("PKCS12");
    try (InputStream in = Files.newInputStream(Path.of("app-truststore.p12"))) { ts.load(in, "changeit".toCharArray()); }
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(ts);
    SSLContext ssl = SSLContext.getInstance("TLS");
    ssl.init(null, tmf.getTrustManagers(), null);
    HttpClient client = HttpClient.newBuilder().sslContext(ssl).build();

Erros relacionados

Ver toda a base de erros de assinatura