Saltar al contenido
ecdsa.com
Java (JSSE, SunX509 trust manager)Java

Mensaje de error

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

También se muestra 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

JDK 21 y 25 anteponen la alerta TLS: «javax.net.ssl.SSLHandshakeException: (certificate_unknown) PKIX path building failed: …». Los registros de JDK más antiguos muestran «javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: …». Los frameworks y las herramientas de compilación (Spring, Maven, Gradle, los IDE) lo envuelven en sus propios mensajes, pero conservan el texto PKIX en la causa.

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

Qué significa

El constructor de rutas de certificación PKIX de Java no pudo construir una cadena desde el certificado del servidor hasta ninguna ancla de confianza del almacén de confianza que usa la JVM. «Requested target» es el certificado del servidor. Java solo confía en su propio archivo cacerts (o en el almacén indicado con javax.net.ssl.trustStore), no en el almacén del sistema operativo, así que aquí falla un certificado de una CA de empresa, de un proxy que inspecciona TLS o de un servidor que no envía su certificado intermedio.

Por qué ocurre

Cómo solucionarlo

  1. 1.

    Ver la cadena y el almacén de confianza en uso

    openssl s_client muestra lo que envía el servidor. javax.net.debug=ssl:handshake:verbose hace que Java imprima la ruta del almacén de confianza que cargó y cada certificado que recibió.

    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 un almacén de confianza de la aplicación que incluya tu raíz

    Copia el cacerts del JDK (para que las CA públicas sigan funcionando), importa la raíz de la empresa o del proxy con keytool y apunta la aplicación a esa copia con javax.net.ssl.trustStore y trustStorePassword (o con JAVA_TOOL_OPTIONS para las herramientas que no arrancas tú mismo).

    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 la raíz en el cacerts del JDK

    keytool -cacerts actúa sobre el almacén predeterminado del JDK que ejecuta keytool (contraseña «changeit» por defecto). Todas las aplicaciones de ese JDK confían en la raíz; el cambio se pierde cuando se sustituye el JDK.

    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.

    Contenedores: dejar que la imagen importe tu CA

    Cuando USE_SYSTEM_CA_CERTS está definida, el entrypoint de las imágenes de Eclipse Temurin añade al arrancar los archivos de certificado *.crt montados en /certificates al cacerts de la JVM (solo se ejecuta con el entrypoint predeterminado de la imagen). Las demás imágenes necesitan el paso de keytool en el 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 un cliente su propio almacén de confianza

    Construye un SSLContext a partir de un TrustManagerFactory inicializado con tu almacén de confianza y pásalo a HttpClient (o a OkHttp, Apache HttpClient, Netty). Nunca instales un gestor de confianza que acepte cualquier 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();

Errores relacionados

Explorar toda la base de datos de errores de firma