PKIX Path does not chain with any of the trust anchors error in Windows Environment

谁说我不能喝 提交于 2019-11-27 12:31:18

The default Java certificate checks are pretty strict, and have apparently gotten stricter. One workaround is to initialize an SSLContext with a custom X509TrustManager. A trust manager that does nothing, i.e. is completely insecure, that I once wrote for testing looks like this:

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

Obviously you would want to actually check the certificate chain in a real program. You could then try to initialize an SSLContext with it and call SSLContext.setDefault() if your API has no other way of configuring SSL. If the API uses the default SSL context then this should work.

Key usage does not appear to be the issue in this case as the certificate chain is not self-signed. Testing the URL appears to show that the leaf certificate is not self-signed and (2) the other two certificates in the chain appear to have certificate signing enabled. An alternative possibility is that Java 6 and Java 7 have separate trust stores and the root certificate is not in the Java 7 store. You may want to double-check that. If you have access to OpenSSL, you can get the certificate chain from the server with:

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

Apparently updating the trust store was the key (pun intended). The OP reports:

I downloaded OpenSSL for Windows 64 and then used this command to download the certificate chain:

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

Then I want to import it into my browser's keystore like so (from the JDK's home directory/jre/lib/security):

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

I believe using X509TrustManager could provide an effective solution as well.

The certificate chain validation logic has indeed changed between Java 6 and Java 7. It seems that the certificate chain is considered to be invalid because the validity end date of the intermediate certificate is after the validity end date of the root certificate. This is a Java bug which was fixed with JDK 1.7.0_72 and 1.8.0_25.

If you can't upgrade your JDK, here is is a workaround since you say are in a debug environment and you have control over your keystore. You can't change any of the certificates of course (since you don't have the private keys), but you can import the intermediate or the server certificate into a local keystore, which means it will be trusted by default, and the rest of the chain validates without any problem.

  1. Download the certificate for www.envmgr.com or www.starfieldtech.com as trusted_certificate.pem
  2. Use keytool to import the certificate into a local keystore named my_keystore with keytool -keystore my_keystore -importcert -file trusted_certificate.pem
  3. Launch wsimport -J-Djavax.net.ssl.trustStore=my_keystore https://www.envmgr.com/LabelService/EwsLabelService.asmx

Try import the certificate you need into java truststore located into jdk_xxx/jre/lib/security/cacerts using keytool

set the jvm parameter Djavax.net.debug=ssl to see more debug information

Rhashimoto helped me find the solution that worked for me:

I downloaded OpenSSL for Windows 64 and then used this command to download the certificate chain:

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

Then I want to import it into my browser's keystore like so (from the JDK's home directory/jre/lib/security):

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

I believe using X509TrustManager could provide an effective solution as well.

Try this OUT, it accepts all

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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!