web-dev-qa-db-fra.com

Le chemin PKIX ne s'enchaine pas avec l'une des erreurs d'ancrage de confiance dans l'environnement Windows

Je suis un peu idiot de la façon dont SSL et les Webservices fonctionnent au niveau de détail. Je développe un système qui appelle plusieurs services Web, certains avec des URL sécurisées et d'autres avec peu de problèmes. Cependant, je suis actuellement en train d’intégrer l’API Web LabelServer d’Endicia. Le service Web est utilisé pour calculer et imprimer les fonds d'affranchissement.

L'URL de test et le fichier WSDL se trouvent à: https://www.envmgr.com/LabelService/EwsLabelService.asmx

J'ai utilisé wsimport pour créer et configurer un client Java afin de me connecter à ce service Web, mais lorsque j'essaie de tout casser, l'erreur

Échec de la validation du chemin PKIX: Java.security.cert.CertPathValidatorException: le chemin ne s’enchaîne pas avec les ancres de confiance.

Cette erreur est documentée ici: Java7 Refus de faire confiance au certificat dans le magasin de confiance

dans lequel il est expliqué comment Java 7 force une erreur avec des certificats auto-signés avec "mauvais" keyusage. Mauvais dans cette situation est défini comme ne contenant pas keyCertSign. Le service Web fonctionne avec Java 6. Je peux penser que cette situation pourrait s'appliquer à ce certificat puisqu'il ne sert que de serveur de test, mais je ne sais pas comment le vérifier.

Il y a un rapport de bogue qui est résolu ( http://bugs.Java.com/bugdatabase/view_bug.do?bug_id=7018897 ), mais je ne suis pas sûr que tout cela se traduise par la résolution du problème. pour un environnement Windows Tomcat. J'ai exporté le certificat sur ma machine, mais je ne sais pas comment procéder à partir de là. 

EDIT: J'ai essayé d'utiliser OpenSSL pour modifier le certificat et l'ajouter à mon magasin de clés, comme décrit dans le lien "Refuser de faire confiance au certificat dans le magasin de confiance" et cela n'a pas fonctionné. Il semble que ce soit un processus effectué par le propriétaire du certificat, non? Je me demande s'il est possible de configurer mon environnement Java 7 pour laisser passer ce certificat.

7
IcedDante

Les contrôles de certificat Java par défaut sont assez stricts et sont apparemment devenus plus stricts. Une solution de contournement consiste à initialiser un SSLContext avec un X509TrustManager personnalisé. Un gestionnaire de confiance qui ne fait rien, c’est-à-dire qui manque complètement de sécurité, que j’avais écrit une fois pour les tests ressemble à ceci:

TrustManager[] trustAllCerts = new TrustManager[]{
   new X509TrustManager() {
      public Java.security.cert.X509Certificate[] getAcceptedIssuers()
         {
            return null;
         }
      public void checkClientTrusted(
         Java.security.cert.X509Certificate[] certs,
         String authType )
         {
         }
      public void checkServerTrusted(
         Java.security.cert.X509Certificate[] certs,
         String authType )
         {
         }
   }
};

Évidemment, vous voudriez vérifier réellement la chaîne de certificats dans un vrai programme. Vous pouvez ensuite essayer d’initialiser une SSLContext avec elle et appeler SSLContext.setDefault() si votre API n’a aucun autre moyen de configurer SSL. Si l'API utilise le contexte SSL par défaut, cela devrait fonctionner.

L'utilisation de la clé ne semble pas être le problème dans ce cas, car la chaîne de certificats n'est pas auto-signée. Le test de l'URL semble indiquer que le certificat feuille n'est pas auto-signé et (2) la signature de certificat semble activée pour les deux autres certificats de la chaîne. Une autre possibilité est que Java 6 et Java 7 aient des magasins de confiance distincts et que le certificat racine ne se trouve pas dans le magasin Java 7. Vous voudrez peut-être vérifier cela. Si vous avez accès à OpenSSL, vous pouvez obtenir la chaîne de certificats du serveur avec:

openssl s_client -Host www.example.com -port 443 -showcerts

Apparemment, la mise à jour du magasin de confiance était la clé (jeu de mots voulu). Le PO rapporte:

J'ai téléchargé OpenSSL pour Windows 64, puis utilisé cette commande pour télécharger la chaîne de certificats:

openssl s_client -Host www.webserviceurl.com -port 443 -showcerts > c:\temp\certchain_output.crt

Ensuite, je veux l'importer dans le magasin de clés de mon navigateur comme suit (à partir du répertoire personnel du JDK/jre/lib/security):

keytool -import -alias ca -file certchain_output.crt -keystore cacerts -storepass changeit

Je pense que l’utilisation de X509TrustManager pourrait également constituer une solution efficace.

10
rhashimoto

La logique de validation de la chaîne de certificats a bien changé entre Java 6 et Java 7. Il semble que la chaîne de certificats soit considérée comme non valide car la date de fin de validité du certificat intermédiaire est postérieure à la date de fin de validité du certificat racine. Ceci est un bogue Java qui a été corrigé avec JDK 1.7.0_72 et 1.8.0_25. 

Si vous ne pouvez pas mettre à niveau votre JDK, voici une solution de contournement puisque vous dites être dans un environnement de débogage et que vous avez le contrôle de votre magasin de clés. Bien entendu, vous ne pouvez modifier aucun des certificats (car vous n’avez pas les clés privées), mais vous pouvez importer le certificat intermédiaire ou le certificat de serveur dans un magasin de clés local, ce qui signifie qu’il sera approuvé par défaut, et le reste. de la chaîne valide sans aucun problème.

  1. Téléchargez le certificat pour www.envmgr.com ou www.starfieldtech.com en tant que Trusted_certificate.pem
  2. Utilisez keytool pour importer le certificat dans un magasin de clés local nommé my_keystore with keytool -keystore my_keystore -importcert -file trusted_certificate.pem
  3. Lancer wsimport -J-Djavax.net.ssl.trustStore=my_keystore https://www.envmgr.com/LabelService/EwsLabelService.asmx
7
rxg

Essayez d’importer le certificat dont vous avez besoin dans le magasin de clés de confiance Java situé dans jdk_xxx/jre/lib/security/cacerts à l’aide de keytool.

définissez le paramètre jvm Djavax.net.debug = ssl pour afficher plus d'informations de débogage

2
Simone

Rhashimoto m'a aidé à trouver la solution qui fonctionnait pour moi:

J'ai téléchargé OpenSSL pour Windows 64, puis utilisé cette commande pour télécharger la chaîne de certificats:

openssl s_client -Host www.webserviceurl.com -port 443 -showcerts > c:\temp\certchain_output.crt

Ensuite, je veux l'importer dans le magasin de clés de mon navigateur comme suit (à partir du répertoire personnel du JDK/jre/lib/security):

keytool -import -alias ca -file certchain_output.crt -keystore cacerts -storepass changeit

Je pense que l’utilisation de X509TrustManager pourrait également constituer une solution efficace.

1
IcedDante

Essayez ceci OUT, il accepte tout

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) { }

        } };

        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);
0
Rupesh Kumar