web-dev-qa-db-fra.com

Échec de la création du chemin PKIX: impossible de trouver un chemin de certification valide vers la cible demandée

J'appelle un service Web HTTPS dont le client suivant:

import Java.io.ByteArrayOutputStream;
import Java.io.FileInputStream;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.OutputStream;
import Java.io.PrintStream;
import Java.net.HttpURLConnection;
import Java.net.URL;

import javax.net.ssl.HttpsURLConnection;

/**
 * Handles http and https connections. It sends XML request over http (or https)
 * to SOAP web service and receive the XML reply.
 * 
 * @author mhewedy
 * @date 30.10.2010
 */
public class HttpWSXmlClient
{
    private final String ws_url;
    private byte[] requestData;

    public HttpWSXmlClient(String wsUrl)
    {
        this.ws_url = wsUrl;
    }

    public void readRequest(String xmlRequestFilePath)
    {
        try
        {
            InputStream istream = new FileInputStream(xmlRequestFilePath);
            byte[] data = stream2Bytes(istream);
            istream.close();
            this.requestData = data;
        } catch (Exception e)
        {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 
     * @param ps
     *            PrintStream object to send the debugging info to.
     * @return
     * @throws IOException
     */
    public byte[] sendAndRecieve(PrintStream ps) throws IOException
    {
        if (requestData == null)
            throw new RuntimeException(
                    "the request data didn't initialized yet.");
        if (ps != null)
            ps.println("Request:\n" + new String(requestData));
        URL url = new URL(ws_url);
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        // or HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setRequestProperty("content-type", "text/xml");
        connection.connect();
        OutputStream os = connection.getOutputStream();
        os.write(requestData);
        InputStream is = connection.getInputStream();
        byte[] rply = stream2Bytes(is);
        if (ps != null)
            ps.println("Response:\n" + new String(rply));
        os.close();
        is.close();
        connection.disconnect();
        return rply;
    }

    public byte[] sendAndRecieve() throws IOException
    {
        return sendAndRecieve(null);
    }

    private byte[] stream2Bytes(InputStream istream) throws IOException
    {
        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
        int c;
        while ((c = istream.read()) != -1)
        {
            if (c != 0x0A && c != 0x0D) // prevent new line character from being
            // written
            {
                if (c == 0x09)
                    c = 0x20; // prevent tab character from being written,
                // instead write single space char
                outstream.write(c);
            }
        }
        byte[] ret = outstream.toByteArray();
        outstream.close();
        return ret;
    }

}

Tester:

public class Test
{
    private static final String WS_URL = "https://some_server/path/to/ws";

    public static void main(String[] args) throws Exception
    {
        HttpWSXmlClient client = new HttpWSXmlClient(WS_URL);
        client.readRequest("request.xml");
        client.sendAndRecieve(System.out);
    }
}

J'ai obtenu la sortie suivante:

Exception in thread "Main Thread" 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
    at com.Sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.Java:174)
    at com.Sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.Java:1591)
    at com.Sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.Java:187)
    at com.Sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.Java:181)
    at com.Sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.Java:1035)
    at com.Sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.Java:124)
    at com.Sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.Java:516)
    at com.Sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.Java:454)
    at com.Sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.Java:884)
    at com.Sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.Java:1096)
    at com.Sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1123)
    at com.Sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.Java:1107)
    at Sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.Java:415)
    at Sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.Java:166)
    at Sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.Java:133)
    at com.se.swstest.HttpWSXmlClient.sendAndRecieve(HttpWSXmlClient.Java:63)
    at com.se.swstest.Test.main(Test.Java:11)
Caused by: Sun.security.validator.ValidatorException: PKIX path building failed: Sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at Sun.security.validator.PKIXValidator.doBuild(PKIXValidator.Java:285)
    at Sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.Java:191)
    at Sun.security.validator.Validator.validate(Validator.Java:218)
    at com.Sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.Java:126)
    at com.Sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.Java:209)
    at com.Sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.Java:249)
    at com.Sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.Java:1014)
    ... 12 more
Caused by: Sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at Sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.Java:174)
    at Java.security.cert.CertPathBuilder.build(CertPathBuilder.Java:238)
    at Sun.security.validator.PKIXValidator.doBuild(PKIXValidator.Java:280)
    ... 18 more

Ai-je besoin d'un certificat à mettre dans jdk/jre/lib/security ??? De plus, j'ai un xxx_IE.crt et xxx_FX.crt (pour Firefox et IE respectivement, et ils ne fonctionnent pas pour le Java Java, donc ai-je besoin d'un certificat spécifique pour le client Java?

Merci.

40
Muhammad Hewedy

Vous devez définir un certificat pour atteindre cette URL. utilisez le code ci-dessous pour définir le magasin de clés:

System.setProperty("javax.net.ssl.trustStore","clientTrustStore.key");

System.setProperty("javax.net.ssl.trustStorePassword","qwerty");
23
Vipin Kumar

Solution Java 8: Je viens de rencontrer ce problème et je l'ai résolu en ajoutant le certificat du site distant à mon magasin de clés Java. Ma solution était basée sur la solution à la myshittycode blog , qui était basé sur un solution précédente dans le blog de mykong . Ces solutions d'articles de blog se résument au téléchargement d'un programme appelé - InstallCert , qui est une classe Java que vous pouvez exécuter à partir de la ligne de commande pour obtenir le certificat. Vous devez ensuite installer le certificat dans le magasin de clés de Java.

Le InstallCert Readme a parfaitement fonctionné pour moi. Il vous suffit d'exécuter les commandes suivantes:

  1. javac InstallCert.Java
  2. Java InstallCert [Host]:[port] (Entrez la liste donnée numéro du certificat que vous souhaitez ajouter dans la liste lorsque vous exécutez la commande - probablement juste 1 )
  3. keytool -exportcert -alias [Host]-1 -keystore jssecacerts -storepass changeit -file [Host].cer
  4. Sudo keytool -importcert -alias [Host] -keystore [path to system keystore] -storepass changeit -file [Host].cer

Voir le fichier référencé README pour un exemple si besoin est.

16
entpnerd

Je l'ai rencontré plusieurs fois et c'était dû à une chaîne de certificats incomplète. Si vous utilisez le magasin de confiance standard Java, il peut ne pas avoir de certificat nécessaire pour terminer la chaîne de certificats requise pour valider le certificat du site SSL auquel vous vous connectez.

J'ai rencontré ce problème avec certains certificats DigiCert et j'ai dû ajouter manuellement le certificat intermédiaire moi-même.

5
Casey

Je l'avais rencontré lorsque j'essayais de lancer une demande SOAP de Java. Ce qui a fonctionné pour moi était:

  1. Obtenez le certificat de serveur en cliquant sur l'URL dans le navigateur: http://docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-website Ce lien a toutes les étapes pour obtenir le certificat du serveur

  2. Une fois que vous avez le certificat de serveur avec vous, suivez http://Java.globinch.com/enterprise-Java/security/pkix-path-building-failed-validation-Sun-security-validatorexception/#Valid-Certification- Chemin vers la cible demandée .

Copie du texte du lien, au cas où ce lien mourrait:

Tout ce que vous devez faire pour corriger cette erreur consiste à ajouter le certificat de serveur à votre magasin de clés de confiance Java. Vous devez d'abord télécharger le document à partir du serveur.

Une fois le certificat sur votre disque dur, vous pouvez l'importer dans le magasin de confiance Java. Pour importer le certificat dans le magasin de clés de confiance Java, vous pouvez utilisez l'outil Java 'keytool'. Sur l'invite de commande, accédez au dossier JRE bin, dans mon cas, le chemin est: C:\Program Files\Java\jdk1.7.0_75\jre\bin. Utilisez ensuite la commande keytool comme suit pour importer le certificat dans JRE.

keytool -import -alias _alias_name_ -keystore ..\lib\security\cacerts -file _path_to_cer_file

Il vous demandera un mot de passe. Par défaut, le mot de passe est "changeit". Si le mot de passe est différent, vous ne pourrez peut-être pas importer le certificat.

4
Rohit

Voici la solution que j'ai utilisée pour installer le certificat public d'un site dans le magasin de clés du système à utiliser.

Téléchargez le certificat avec la commande suivante:

nix, linux, mac

openssl s_client -connect [Host]:[port|443] < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > [Host].crt

fenêtres

openssl s_client -connect [Host]:[port|443] < NUL | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > [Host].crt

Cela créera un crt qui peut être utilisé pour importer dans un magasin de clés.

Installez le nouveau certificat avec la commande:

keytool -import -alias "[Host]" -keystore [path to keystore] -file [Host].crt

Cela vous permettra d'importer le nouveau certificat à partir du site à l'origine de l'exception.

4
Ray Hunter

Sur Mac OS, je devais ouvrir le certificat auto-signé du serveur avec l'outil d'accès au trousseau système, l'importer, le dobublecliquer puis sélectionner "Toujours faire confiance" (même si je l'ai défini dans l'importateur). Avant cela, bien sûr, j'ai exécuté Java a pris avec -importcert pour importer le même fichier dans le stockage cacert.

2
Mike Makarov

Si vous n'avez pas besoin de la sécurité SSL, vous souhaiterez peut-être la désactiver.

 /**
   * disable SSL
   */
  private void disableSslVerification() {
    try {
      // Create a trust manager that does not validate certificate chains
      TrustManager[] trustAllCerts = new TrustManager[] {
          new X509TrustManager() {
            public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
              return null;
            }

            public void checkClientTrusted(X509Certificate[] certs,
                String authType) {
            }

            public void checkServerTrusted(X509Certificate[] certs,
                String authType) {
            }
          } };

      // Install the all-trusting trust manager
      SSLContext sc = SSLContext.getInstance("SSL");
      sc.init(null, trustAllCerts, new Java.security.SecureRandom());
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

      // Create all-trusting Host name verifier
      HostnameVerifier allHostsValid = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
          return true;
        }
      };

      // Install the all-trusting Host verifier
      HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
    } catch (KeyManagementException e) {
      e.printStackTrace();
    }
  }
2
Wolfgang Fahl

Pour moi, j'avais rencontré cette erreur lors de l'appel d'un appel de service Web, assurez-vous que le site a un ssl valide, c'est-à-dire que le logo sur le côté de l'url est vérifié, sinon vous devez ajouter le certificat au magasin de clés de confiance de votre machine

0
mel3kings

J'ai également fait face à ce type de problème.J'utilise le serveur Tomcat, puis j'ai mis le dossier approuvé dans Tomcat, puis son travail a commencé.Et j'ai également remplacé JDK1.6 par 1.7 puis également son fonctionnement.Enfin, j'apprends SSL, puis j'ai résolu ce type de problèmes .Tout d'abord, vous devez télécharger les certificats à partir de ce serveur de fournisseur de services. Ensuite, vous êtes en contact avec succès. 1.Essayez de mettre le dossier approuvé dans votre serveur Prochaine manière 2.Utilisez jdk1.7

Suivant 3.Essayez de télécharger des certificats valides à l'aide de SSL

0
sravan kumar