Aller au contenu
ecdsa.com
Java (JSSE, SunX509 trust manager)Java

Message d’erreur

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

Également affiché sous la forme

  • 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

Les JDK 21 et 25 font précéder le message de l’alerte TLS : « javax.net.ssl.SSLHandshakeException: (certificate_unknown) PKIX path building failed: … ». Les journaux des JDK plus anciens affichent « javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: … ». Les frameworks et les outils de build (Spring, Maven, Gradle, IDE) l’enveloppent dans leurs propres messages, mais conservent le texte PKIX dans la cause.

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

Ce que cela signifie

Le constructeur de chemins de certificats PKIX de Java n’a pas pu bâtir de chaîne allant du certificat du serveur à l’une des ancres de confiance du magasin de confiance qu’utilise la JVM. La mention « requested target » désigne le certificat du serveur. Java ne fait confiance qu’à son propre fichier cacerts (ou au magasin indiqué par javax.net.ssl.trustStore), et non au magasin du système d’exploitation : un certificat émis par une AC d’entreprise ou par un proxy d’inspection TLS, ou présenté par un serveur sans son certificat intermédiaire, échoue donc ici.

Pourquoi cela se produit

Comment corriger l’erreur

  1. 1.

    Afficher la chaîne et le magasin de confiance utilisé

    openssl s_client montre ce que le serveur envoie. Avec javax.net.debug=ssl:handshake:verbose, Java affiche le chemin du magasin de confiance qu’il a chargé et chaque certificat qu’il a reçu.

    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.

    Utiliser un magasin de confiance applicatif qui contient votre racine

    Copiez le cacerts du JDK (pour que les AC publiques fonctionnent toujours), importez la racine de l’entreprise ou du proxy avec keytool, puis indiquez ce magasin à l’application avec javax.net.ssl.trustStore et trustStorePassword (ou JAVA_TOOL_OPTIONS pour les outils que vous ne lancez pas vous-même).

    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.

    Importer la racine dans le cacerts du JDK

    keytool -cacerts cible le magasin par défaut du JDK qui exécute keytool (mot de passe « changeit » par défaut). Toutes les applications de ce JDK font alors confiance à la racine ; la modification est perdue lorsque le JDK est remplacé.

    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.

    Conteneurs : laisser l’image importer votre AC

    Lorsque USE_SYSTEM_CA_CERTS est défini, le point d’entrée des images Eclipse Temurin ajoute au démarrage les fichiers *.crt montés dans /certificates au cacerts de la JVM (cela ne fonctionne qu’avec le point d’entrée par défaut de l’image). Les autres images nécessitent l’étape keytool dans le 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.

    Donner à un client son propre magasin de confiance

    Construisez un SSLContext à partir d’une TrustManagerFactory initialisée avec votre magasin de confiance et passez-le à HttpClient (ou à OkHttp, Apache HttpClient, Netty). N’installez jamais de gestionnaire de confiance (trust manager) qui accepte tous les certificats.

    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();

Erreurs associées

Parcourir toute la base de données des erreurs de signature