299 votes

Impossible de trouver un chemin de certification valide vers la cible demandée - erreur même après l'importation du certificat

J'ai un client Java qui essaie d'accéder à un serveur avec un certificat auto-signé.

Lorsque j'essaie de poster sur le serveur, je reçois l'erreur suivante:

unable to find valid certification path to requested target

Ayant fait quelques recherches sur le problème, j'ai ensuite fait ce qui suit.

  1. Enregistré le nom de domaine de mes serveurs sous forme de fichier root.cer.

  2. Dans le JRE de mon serveur Glassfish, j'ai exécuté ceci:

    keytool -import -alias example -keystore cacerts -file root.cer
  3. Pour vérifier que le certificat a bien été ajouté à mon cacert, j'ai fait ceci:

    keytool -list -v -keystore cacerts

    Je peux voir que le certificat est présent.

  4. J'ai ensuite redémarré Glassfish et réessayé le 'post'.

Je reçois toujours la même erreur.

J'ai l'impression que c'est parce que mon Glassfish ne lit pas réellement le fichier cacert que j'ai modifié mais peut-être un autre.

Avez-vous déjà rencontré ce problème et pouvez-vous me guider dans la bonne direction?

2 votes

Juste pour clarifier "J'ai un client Java qui essaie d'accéder à un serveur avec un certificat auto-signé.": vous parlez d'utiliser des certificats client qui sont auto-signés, n'est-ce pas? Y a-t-il une configuration spécifique pour les paramètres de votre connecteur sur Glassfish (paramètres du magasin de confiance, en particulier)?

0 votes

"J'ai un client Java essayant d'accéder à un serveur avec un certificat auto-signé." : tu parles d'utiliser des certificats de client qui sont auto-signés, n'est-ce pas ? - oui.

1 votes

J'ai trouvé 2 paramètres dans Glassfish JVM : -Djavax.net.ssl.keyStore=${com.sun.aas.instanceRoot}/config/‌​keystore.jks et -Djavax.net.ssl.trustStore=${com.sun.aas.instanceRoot}/confi‌​g/cacerts.jks. Maintenant, je dois ajouter mon certificat à l'un d'eux. Pouvez-vous confirmer que c'est le keystore auquel je dois l'ajouter ?

219voto

Dirk-Willem van Gulik Points 3552

Malheureusement - cela pourrait être beaucoup de choses - et de nombreux serveurs d'applications et autres 'enveloppes' Java ont tendance à jouer avec les propriétés et leur propre interprétation des trousseaux et ainsi de suite. Donc, cela peut être quelque chose de totalement différent.

À défaut de truss-ing - je recommanderais :

java -Djavax.net.debug=all -Djavax.net.ssl.trustStore=trustStore ...

pour voir si cela aide. Au lieu de 'all', on peut également le régler sur 'ssl', gestionnaire de clés et gestionnaire de confiance - ce qui peut vous aider dans votre cas. Le régler sur 'help' affichera quelque chose comme ci-dessous sur la plupart des plates-formes.

Quoi qu'il en soit - assurez-vous de bien comprendre la différence entre le magasin de clés (dans lequel vous avez la clé privée et le certificat avec lesquels vous prouvez votre propre identité) et le magasin de confiance (qui détermine qui vous faites confiance) - et le fait que votre propre identité a également une 'chaîne' de confiance jusqu'à la racine - qui est distincte de toute chaîne jusqu'à une racine à laquelle vous devez déterminer à qui vous faites confiance.

all            active tous les débogages
ssl            active le débogage SSL

Les options suivantes peuvent être utilisées avec ssl :
    record       permet de suivre les traces par enregistrement
    handshake    imprime chaque message de poignée de main
    keygen       imprime les données de génération de clé
    session      imprime l'activité de session
    defaultctx   imprime l'initialisation SSL par défaut
    sslctx       imprime la trace de SSLContext
    sessioncache imprime la trace du cache de session
    keymanager   imprime la trace de gestionnaire de clés
    trustmanager imprime la trace du gestionnaire de confiance
    pluggability imprime la trace de pluggability

    Le débogage de poignée de main peut être élargi avec :
    data         dumping hexadécimal de chaque message de poignée de main
    verbose      impression détaillée des messages de poignée de main

    Le débogage d'enregistrement peut être élargi avec :
    plaintext    dumping hexadécimal du texte en clair de l'enregistrement
    packet       affiche des paquets SSL/TLS bruts

Source: # Voirhttp://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#Debug

9 votes

Merci beaucoup! -Djavax.net.ssl.trustStore=/emplacement_du/trustStore a résolu mon problème et les informations de débogage étaient vraiment utiles aussi.

8 votes

Java -Djavax.net.debug=all -Djavax.net.ssl.trustStore=trustStore ... donne l'erreur suivante: Erreur: Impossible de trouver ou de charger la classe principale ...

2 votes

Bien sûr, vous pouvez également avoir besoin de spécifier le mot de passe du truststore avec -Djavax.net.ssl.trustStorePassword=changeit

34voto

user6258309 Points 281

Voici la solution, suivez le lien ci-dessous pas à pas :

http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/

FICHIER JAVA : qui manque dans le blog

/*
 * Copyright 2006 Sun Microsystems, Inc.  Tous droits réservés.
 *
 * La redistribution et l'utilisation sous forme source et binaire, avec ou sans
 * modification, sont autorisées à condition que les conditions suivantes
 * soient remplies :
 *
 *   - Les redistributions du code source doivent conserver le droit d'auteur ci-dessus
 *     avis, cette liste de conditions et la clause de non-responsabilité suivante.
 *
 *   - Les redistributions sous forme binaire doivent reproduire le droit d'auteur ci-dessus
 *     avis, cette liste de conditions et la clause de non-responsabilité suivante dans le
 *     documentation et/ou autres documents fournis avec la distribution.
 *
 *   - Ni le nom de Sun Microsystems ni les noms de ses
 *     contributeurs ne peuvent être utilisés pour endosser ou promouvoir des produits dérivés
 *     de ce logiciel sans autorisation écrite préalable spécifique.
 *
 * CE LOGICIEL EST FOURNI PAR LES TITULAIRES DU DROIT D'AUTEUR ET DES CONTRIBUTEURS "TEL QUEL"
 * EST" ET TOUTE GARANTIE EXPRESSE OU IMPLICITE, Y COMPRIS, MAIS SANS S'Y LIMITER,
 * LES GARANTIES IMPLICITES DE QUALITÉ MARCHANDE ET D'ADÉQUATION À UN USAGE PARTICULIER
 * SONT EXCLU.  EN AUCUN CAS, LE PROPRIÉTAIRE DU DROIT D'AUTEUR OU
 * LES CONTRIBUTEURS NE PEUVENT ÊTRE TENUS RESPONSABLES DES DOMMAGES DIRECTS, INDIRECTS, ACCESSOIRES, SPÉCIAUX,
 * EXEMPLARY OU CONSÉCUTIFS (Y COMPRIS, MAIS SANS S'Y LIMITER À,
 * L'ACHAT DE BIENS OU DE SERVICES DE REMPLACEMENT; PERTE D'UTILISATION, DE DONNÉES OU
 * BÉNÉFICES; OU INTERRUPTION DES ACTIVITÉS COMMERCIALES) CAUSÉS ET SUR TOUTE THÉORIE DE
 * RESPONSABILITÉ, QU'IL S'AGISSE DE CONTRAT, DE RESPONSABILITÉ STRICTE OU DE TORT (Y COMPRIS
 * NÉGLIGENCE OU AUTREMENT) DÉCOULANT DE L'UTILISATION DE CE
 * LOGICIEL, MÊME SI AVISÉ DE LA POSSIBILITÉ DE CES DOMMAGES.
 */

import java.io.*;
import java.net.URL;

import java.security.*;
import java.security.cert.*;

import javax.net.ssl.*;

public class InstallCert {

    public static void main(String[] args) throws Exception {
    String host;
    int port;
    char[] passphrase;
    if ((args.length == 1) || (args.length == 2)) {
        String[] c = args[0].split(":");
        host = c[0];
        port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
        String p = (args.length == 1) ? "changeit" : args[1];
        passphrase = p.toCharArray();
    } else {
        System.out.println("Utilisation : java InstallCert [:port] [mot de passe]");
        return;
    }

    File file = new File("jssecacerts");
    if (file.isFile() == false) {
        char SEP = File.separatorChar;
        File dir = new File(System.getProperty("java.home") + SEP
            + "lib" + SEP + "security");
        file = new File(dir, "jssecacerts");
        if (file.isFile() == false) {
        file = new File(dir, "cacerts");
        }
    }
    System.out.println("Chargement du KeyStore " + file + "...");
    InputStream in = new FileInputStream(file);
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(in, passphrase);
    in.close();

    SSLContext context = SSLContext.getInstance("TLS");
    TrustManagerFactory tmf =
        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(ks);
    X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
    SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
    context.init(null, new TrustManager[] {tm}, null);
    SSLSocketFactory factory = context.getSocketFactory();

    System.out.println("Ouverture de la connexion à " + host + ":" + port + "...");
    SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
    socket.setSoTimeout(10000);
    try {
        System.out.println("Démarrage de la poignée de main SSL...");
        socket.startHandshake();
        socket.close();
        System.out.println();
        System.out.println("Pas d'erreurs, le certificat est déjà approuvé");
    } catch (SSLException e) {
        System.out.println();
        e.printStackTrace(System.out);
    }

    X509Certificate[] chain = tm.chain;
    if (chain == null) {
        System.out.println("Impossible d'obtenir la chaîne de certificats serveur");
        return;
    }

    BufferedReader reader =
        new BufferedReader(new InputStreamReader(System.in));

    System.out.println();
    System.out.println("Le serveur a envoyé " + chain.length + " certificat(s) :");
    System.out.println();
    MessageDigest sha1 = MessageDigest.getInstance("SHA1");
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    for (int i = 0; i < chain.length; i++) {
        X509Certificate cert = chain[i];
        System.out.println
            (" " + (i + 1) + " Sujet " + cert.getSubjectDN());
        System.out.println("   Émetteur  " + cert.getIssuerDN());
        sha1.update(cert.getEncoded());
        System.out.println("   sha1    " + toHexString(sha1.digest()));
        md5.update(cert.getEncoded());
        System.out.println("   md5     " + toHexString(md5.digest()));
        System.out.println();
    }

    System.out.println("Entrez le certificat à ajouter au truststore ou 'q' pour quitter : [1]");
    String line = reader.readLine().trim();
    int k;
    try {
        k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
    } catch (NumberFormatException e) {
        System.out.println("TrustStore non modifié");
        return;
    }

    X509Certificate cert = chain[k];
    String alias = host + "-" + (k + 1);
    ks.setCertificateEntry(alias, cert);

    OutputStream out = new FileOutputStream("jssecacerts");
    ks.store(out, passphrase);
    out.close();

    System.out.println();
    System.out.println(cert);
    System.out.println();
    System.out.println
        ("Certificat ajouté au truststore 'jssecacerts' en utilisant l'alias '"
        + alias + "'");
    }

    private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();

    private static String toHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 3);
        for (int b : bytes) {
            b &= 0xff;
            sb.append(HEXDIGITS[b >> 4]);
            sb.append(HEXDIGITS[b & 15]);
            sb.append(' ');
        }
        return sb.toString();
    }

    private static class SavingTrustManager implements X509TrustManager {

    private final X509TrustManager tm;
    private X509Certificate[] chain;

    SavingTrustManager(X509TrustManager tm) {
        this.tm = tm;
    }

    public X509Certificate[] getAcceptedIssuers() {
        throw new UnsupportedOperationException();
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType)
        throws CertificateException {
        throw new UnsupportedOperationException();
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException {
        this.chain = chain;
        tm.checkServerTrusted(chain, authType);
    }
    }

}

4 votes

Cette solution a fonctionné pour moi, mais elle nécessite une petite modification dans la classe privée SavingTrustManager : public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0];}

1 votes

@Richard, @Paul, @user6258309 J'ai reçu l'erreur Exception dans le thread "main" java.net.SocketTimeoutException: Lecture de la socket expirée à java.net.SocketInputStream.socketRead0(Méthode native) à java.net.SocketInputStream.socketRead(Source inconnue) Comment puis-je résoudre ce problème

14 votes

Cette «solution» est radicalement insécurisée. Ne pas utiliser.

17voto

Vic Points 82

Vous devez configurer les propriétés système JSSE, en particulier pour indiquer le magasin de certificats client.

Via la ligne de commande:

java -Djavax.net.ssl.trustStore=truststores/client.ts com.progress.Client

ou via le code Java:

import java.util.Properties;
    ...
    Properties systemProps = System.getProperties();
    systemProps.put("javax.net.ssl.keyStorePassword","motDePassePourLeKeystore");
    systemProps.put("javax.net.ssl.keyStore","cheminVersLeKeystore.ks");
    systemProps.put("javax.net.ssl.trustStore", "cheminVersLeTruststore.ts");
    systemProps.put("javax.net.ssl.trustStorePassword","motDePassePourLeTrustStore");
    System.setProperties(systemProps);
    ...

Pour plus de détails, consultez le site de RedHat.

0 votes

Ayant rencontré le même problème avec Spring Boot, les microservices Spring Cloud et un certificat SSL auto-signé. J'ai pu définir keyStore et keyStorePassword dans application.properties et le faire fonctionner de cette manière dès la sortie de la boîte, mais je n'ai pas réussi à faire la même chose avec trustStore et trustStorePassword. Cette réponse a fonctionné pour moi pour le trust store.

0 votes

Le code Java a fonctionné pour moi. Merci.

15voto

(repost de ma autre réponse)
Utilisez l'utilitaire en ligne de commande keytool de la distribution logicielle Java pour importer (et confirmer!) les certificats nécessaires

Exemple:

  1. Depuis la ligne de commande, changez de répertoire vers jre\bin

  2. Vérifiez le keystore (fichier trouvé dans le répertoire jre\bin)
    keytool -list -keystore ..\lib\security\cacerts
    Le mot de passe est changeit

  3. Téléchargez et enregistrez tous les certificats de la chaîne du serveur nécessaire.

  4. Ajoutez les certificats (avant de devoir supprimer l'attribut "lecture seule" sur le fichier ..\lib\security\cacerts), exécutez:

    keytool -alias REPLACE_TO_ANY_UNIQ_NAME -import -keystore.\lib\security\cacerts -file "r:\root.crt"

J'ai découvert par accident un conseil aussi simple. D'autres solutions nécessitent l'utilisation de InstallCert.Java et JDK

source: http://www.java-samples.com/showtutorial.php?tutorialid=210

0 votes

Génial, merci! avec l'aide de keytool -alias REPLACE_TO_ANY_UNIQ_NAME -import -keystore.\lib\security\cacerts -file "r:\root.crt", je n'ai pas besoin de modifier mon code Java CloseableHttpClient httpClient = HttpClients.createDefault();

10voto

Deb Points 64

J'ai rencontré cette erreur en essayant d'accéder à une URL https depuis mon application qui utilisait un certificat auto-signé. Ce qu'ils fournissent est un fichier .cert et je ne savais pas où le mettre. J'ai résolu le problème de la manière suivante :

L'emplacement de keytool se trouve sous le dossier JDK/bin

Méthode 1 : Ajouter le certificat au Truststore Java par défaut - cacerts :

keytool -import -alias myCert -file C://certificate.cert -keystore C://Program Files//Java//jdk1.8.0_271//jre//lib//security//cacerts

Mot de passe : changeit

Méthode 2:

Créer un Trust Store :

keytool -import -alias myCert -file C://certificate.cert -keystore myTrustStore

Il vous donne les invites suivantes, que vous pouvez remplir comme suit :

Enter keystore password:changeit
Re-enter new password:changeit
Trust this certificate?yes

Cela créera un fichier myTrustStore dans un dossier où vous avez exécuté cette commande. Copiez ce "myTrustStore" dans un endroit pratique.

Utiliser le Trust Store :

Pendant que vous exécutez votre application/serveur, passez ces arguments JVM :

-Djavax.net.ssl.trustStore=C://myTrustStore -Djavax.net.ssl.trustStorePassword=changeit

1 votes

J'ai essayé la deuxième méthode et cela a fonctionné pour moi.

0 votes

@Deb As-tu exécuté les commandes sur le client ou sur le serveur ? Je suppose que cela devrait être sur le client ?

0 votes

C'est pour le côté client.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X