webentwicklung-frage-antwort-db.com.de

PKIX Path kettet nicht mit einem der Vertrauensankerfehler in der Windows-Umgebung

Ich bin ein Idiot, wie SSL und Webservices auf feiner Ebene funktionieren. Ich entwickle ein System, das mehrere Webdienste aufruft, einige mit gesicherten URLs und andere, die kein Problem darstellen. Momentan mache ich jedoch eine Integration mit der LabelServer-Web-API von Endicia. Mit dem Webservice werden Porto berechnet und gedruckt.

Die Test-URL und WSDL finden Sie unter: https://www.envmgr.com/LabelService/EwsLabelService.asmx

Ich habe wsimport verwendet, um einen Java-Client für das Herstellen einer Verbindung zu diesem Webservice zu erstellen und einzurichten. Wenn ich jedoch alles probiere, erhalte ich den Fehler

PKIX-Pfadüberprüfung fehlgeschlagen: Java.security.cert.CertPathValidatorException: Pfad kettet nicht mit einem der Vertrauensanker

Dieser Fehler ist hier dokumentiert: Java7 Zertifikat im Truststore nicht vertrauen

in diesem Abschnitt wird erläutert, wie Java 7 einen Fehler bei selbstsignierten Zertifikaten mit "schlechter" Schlüsselverwendung erzwingt. Schlecht in dieser Situation ist definiert als nicht keyCertSign enthalten. Der Webservice funktioniert mit Java 6. Ich glaube, dass diese Situation für dieses Zertifikat zutreffen könnte, da es nur als Testserver verwendet wird, aber ich weiß nicht, wie ich das überprüfen kann.

Es gibt einen Fehlerbericht, der behoben wurde ( http://bugs.Java.com/bugdatabase/view_bug.do?bug_id=7018897 ), aber ich bin nicht sicher, wie dies zur Behebung des Problems führt für eine Windows Tomcat-Umgebung. Ich habe das Zertifikat auf meine Maschine exportiert, bin aber nicht sicher, wie es von dort weitergeht. 

BEARBEITEN: Ich habe mit OpenSSL versucht, das Zertifikat zu ändern und es meinem Keystore hinzuzufügen, wie im Link "Zertifikat im Truststore nicht vertrauen" beschrieben, und es funktionierte nicht. Es scheint, dass dies ein Vorgang ist, der vom Inhaber des Zertifikats durchgeführt wird, richtig? Ich frage mich, ob es eine Möglichkeit gibt, meine Java 7-Umgebung so zu konfigurieren, dass dieses Zertifikat durchgelassen wird.

7
IcedDante

Die Standardprüfungen für Java-Zertifikate sind ziemlich streng und wurden anscheinend strenger. Eine Problemumgehung besteht darin, eine SSLContext mit einem benutzerdefinierten X509TrustManager zu initialisieren. Ein Vertrauensmanager, der nichts tut, d. H. Völlig unsicher ist und das ich einmal zum Testen geschrieben habe, sieht folgendermaßen aus:

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

Natürlich möchten Sie die Zertifikatskette tatsächlich in einem echten Programm überprüfen. Sie könnten dann versuchen, eine SSLContext damit zu initialisieren und SSLContext.setDefault() aufzurufen, wenn Ihre API keine andere Möglichkeit hat, SSL zu konfigurieren. Wenn die API den Standard-SSL-Kontext verwendet, sollte dies funktionieren.

Die Schlüsselverwendung scheint in diesem Fall nicht das Problem zu sein, da die Zertifikatskette nicht selbstsigniert ist. Das Testen der URL scheint zu zeigen, dass das Blattzertifikat nicht selbstsigniert ist. (2) Bei den anderen beiden Zertifikaten in der Kette scheint die Zertifikatsignierung aktiviert zu sein. Eine alternative Möglichkeit ist, dass Java 6 und Java 7 separate Vertrauensspeicher haben und das Stammzertifikat nicht im Java 7-Speicher gespeichert ist. Vielleicht möchten Sie das noch einmal überprüfen. Wenn Sie Zugriff auf OpenSSL haben, können Sie die Zertifikatskette vom Server erhalten mit:

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

Anscheinend war die Aktualisierung des Truststores der Schlüssel (Wortspiel beabsichtigt). Das OP berichtet:

Ich habe OpenSSL für Windows 64 heruntergeladen und dann die Zertifikatskette mit diesem Befehl heruntergeladen:

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

Dann möchte ich es wie folgt in den Keystore meines Browsers importieren (aus dem JDK-Home-Verzeichnis/jre/lib/security):

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

Ich glaube, der Einsatz von X509TrustManager könnte ebenfalls eine effektive Lösung darstellen.

10
rhashimoto

Die Validierungslogik der Zertifikatskette hat sich in der Tat zwischen Java 6 und Java 7 geändert. Es scheint, dass die Zertifikatskette als ungültig gilt, da das Gültigkeitsende des Zwischenzertifikats nach dem Gültigkeitsende des Stammzertifikats liegt. Dies ist ein Java-Fehler , der mit JDK 1.7.0_72 und 1.8.0_25 behoben wurde. 

Wenn Sie Ihr JDK nicht aktualisieren können, finden Sie hier eine Problemumgehung, da Sie sich in einer Debug-Umgebung befinden und die Kontrolle über Ihren Keystore haben. Sie können natürlich keines der Zertifikate ändern (da Sie nicht über die privaten Schlüssel verfügen), aber Sie können das Zwischen- oder das Serverzertifikat in einen lokalen Schlüsselspeicher importieren, was bedeutet, dass es standardmäßig als vertrauenswürdig eingestuft wird der Kette validiert problemlos.

  1. Laden Sie das Zertifikat für www.envmgr.com oder www.starfieldtech.com als trusted_certificate.pem herunter.
  2. Verwenden Sie keytool, um das Zertifikat in einen lokalen Schlüsselspeicher mit dem Namen my_keystore mit keytool -keystore my_keystore -importcert -file trusted_certificate.pem zu importieren.
  3. wsimport -J-Djavax.net.ssl.trustStore=my_keystore https://www.envmgr.com/LabelService/EwsLabelService.asmx starten
7
rxg

Versuchen Sie, das erforderliche Zertifikat in den Java-Truststore zu importieren, der sich in jdk_xxx/jre/lib/security/cacerts befindet, indem Sie keytool verwenden

setzen Sie den jvm-Parameter Djavax.net.debug = ssl, um weitere Debug-Informationen anzuzeigen

2
Simone

Rhashimoto hat mir geholfen, die Lösung zu finden, die für mich funktioniert hat:

Ich habe OpenSSL für Windows 64 heruntergeladen und dann die Zertifikatskette mit diesem Befehl heruntergeladen:

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

Dann möchte ich es wie folgt in den Keystore meines Browsers importieren (aus dem JDK-Home-Verzeichnis/jre/lib/security):

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

Ich glaube, der Einsatz von X509TrustManager könnte ebenfalls eine effektive Lösung darstellen.

1
IcedDante

Probieren Sie es aus, es akzeptiert alles

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