Java PKIX 路径构建失败:无法找到到请求目标的有效认证路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4062307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:07:27  来源:igfitidea点击:

PKIX path building failed: unable to find valid certification path to requested target

javaweb-servicescertificatessl-certificate

提问by Muhammad Hewedy

I am calling some HTTPS web service which the following Client:

我正在调用以下客户端的一些 HTTPS Web 服务:

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

}

Test:

测试:

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

I got the following output:

我得到以下输出:

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

Do I need any certificate to be put at jdk/jre/lib/security??? Also, I have a xxx_IE.crt and xxx_FX.crt (for Firefox and IE respectively, and they don't work for the above Java client, so do I need a specific certificate for the Java client?

我需要将任何证书放在 jdk/jre/lib/security 吗???另外,我有一个 xxx_IE.crt 和 xxx_FX.crt(分别用于 Firefox 和 IE,它们不适用于上述 Java 客户端,所以我需要 Java 客户端的特定证书吗?

Thanks.

谢谢。

回答by Vipin Kumar

You need to set certificate to hit this url. use below code to set keystore:

您需要设置证书才能访问此网址。使用以下代码设置密钥库:

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

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

回答by Casey

I've run into this a few times and it was due to a certificate chain being incomplete. If you are using the standard java trust store, it may not have a certificate that is needed to complete the certificate chain which is required to validate the certificate of the SSL site you are connecting to.

我遇到过几次,这是由于证书链不完整。如果您使用的是标准 java 信任库,则它可能没有完成证书链所需的证书,该证书链是验证您连接到的 SSL 站点的证书所必需的。

I ran into this problem with some DigiCert certificates and had to manually add the intermediary cert myself.

我在使用一些 DigiCert 证书时遇到了这个问题,不得不自己手动添加中间证书。

回答by mel3kings

For me, I had encountered this error when invoking a webservice call, make sure that the site has a valid ssl, i.e the logo on the side of the url is checked, otherwise need to add the certificate to trusted key store in your machine

对我来说,我在调用 webservice 调用时遇到过这个错误,请确保该站点具有有效的 ssl,即检查 url 一侧的徽标,否则需要将证书添加到您机器中的受信任密钥库中

回答by Mike Makarov

On Mac OS I had to open the server's self-signed certificate with system Keychain Access tool, import it, dobubleclick it and then select "Always trust" (even though I set the same in importer). Before that, of course I ran java key took with -importcert to import same file to cacert storage.

在 Mac OS 上,我必须使用系统钥匙串访问工具打开服务器的自签名证书,导入它,双击它,然后选择“始终信任”(即使我在导入器中设置相同)。在此之前,当然我使用 -importcert 运行 java key take 将相同的文件导入 cacert 存储。

回答by sravan kumar

I also faced this type of issue.I am using tomcat server then i put endorsed folder in tomcat then its start working.And also i replaced JDK1.6 with 1.7 then also its working.Finally i learn SSL then I resolved this type of issues.First you need to download the certificates from that servie provider server.then you are handshake is successfull. 1.Try to put endorsed folder in your server Next way 2.use jdk1.7

我也遇到过这种类型的问题。我正在使用 tomcat 服务器,然后我将认可的文件夹放入 tomcat 然后它开始工作。而且我用 1.7 替换了 JDK1.6 然后它也可以工作。最后我学习了 SSL 然后我解决了这种类型的问题.首先,您需要从该服务提供商服务器下载证书。然后您握手成功。1.尝试将已背书文件夹放在您的服务器中 下一步 2.使用 jdk1.7

Next 3.Try to download valid certificates using SSL

下一步 3.尝试使用 SSL 下载有效证书

回答by entpnerd

Java 8 Solution: I just had this problem and solved it by adding the remote site's certificate to my Java keystore. My solution was based on the solution at the myshittycodeblog, which was based on a previous solution in mykong's blog. These blog article solutions boil down to downloading a program called InstallCert, which is a Java class you can run from the command line to obtain the certificate. You then proceed to install the certificate in Java's keystore.

Java 8 解决方案:我刚刚遇到了这个问题,并通过将远程站点的证书添加到我的 Java 密钥库来解决它。我的解决方案基于myshittycode博客中解决方案,该解决方案基于mykong博客中先前解决方案。这些博客文章解决方案归结为下载名为InstallCert的程序,这是一个 Java 类,您可以从命令行运行以获取证书。然后继续在 Java 的密钥库中安装证书。

The InstallCert Readmeworked perfectly for me. You just need to run the following commands:

InstallCert自述工作完美的我。您只需要运行以下命令:

  1. javac InstallCert.java
  2. java InstallCert [host]:[port](Enter the given list numberof the certificate you want to add in the list when you run the command - likely just 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
  1. javac InstallCert.java
  2. java InstallCert [host]:[port](在运行命令时输入要添加到列表中的证书的给定列表编号- 可能只是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

See the referenced README file for an example if need be.

如果需要,请参阅引用的 README 文件以获取示例。

回答by Ray Hunter

Here is the solution that I used for installing a site's public cert into the systems keystore for use.

这是我用于将站点的公共证书安装到系统密钥库中以供使用的解决方案。

Download the certificate with the following command:

使用以下命令下载证书:

unix, linux, mac

Unix、Linux、Mac

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

windows

视窗

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

That will create a crt that can be used to import into a keystore.

这将创建一个可用于导入密钥库的 crt。

Install the new certificate with the command:

使用以下命令安装新证书:

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

This will allow you to import the new cert from the site that is causing the exception.

这将允许您从导致异常的站点导入新证书。

回答by Rohit

I had hit this when I was trying to initiate a SOAP request from Java code. What worked for me was:

我在尝试从 Java 代码发起 SOAP 请求时遇到了这个问题。对我有用的是:

  1. Get the Server certificate by hitting the URL in browser: http://docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-websiteThis link has all the steps to get the server certificate

  2. Once you have the server certificate with you follow http://java.globinch.com/enterprise-java/security/pkix-path-building-failed-validation-sun-security-validatorexception/#Valid-Certification-Path-to-Requested-Target.

  1. 通过点击浏览器中的 URL 获取服务器证书:http: //docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-website此链接包含获取服务器的所有步骤证书

  2. 获得服务器证书后,请按照http://java.globinch.com/enterprise-java/security/pkix-path-building-failed-validation-sun-security-validatorexception/#Valid-Certification-Path-to-请求目标

Copying the text from the link, in case this link dies:

复制链接中的文本,以防此链接失效:

All you need to do to fix this error is to add the server certificate to your trusted Java key store. First You need to download the document from the server.

Once you have the certificate in your hard drive you can import it to the Java trust store. To import the certificate to the trusted Java key store, you can use the java ‘keytool‘ tool. On command prompt navigate to JRE bin folder, in my case the path is : C:\Program Files\Java\jdk1.7.0_75\jre\bin . Then use keytool command as follows to import the certificate to JRE.

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

It will ask for a password. By default the password is “changeit”. If the password is different you may not be able to import the certificate.

修复此错误所需要做的就是将服务器证书添加到受信任的 Java 密钥库。首先您需要从服务器下载文档。

一旦您的硬盘驱动器中有证书,您就可以将其导入 Java 信任存储。要将证书导入受信任的 Java 密钥库,您可以使用 java 'keytool' 工具。在命令提示符下导航到 JRE bin 文件夹,在我的情况下,路径是: C:\Program Files\Java\jdk1.7.0_75\jre\bin 。然后使用如下keytool命令将证书导入JRE。

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

它会要求输入密码。默认密码是“changeit”。如果密码不同,您可能无法导入证书。

回答by Wolfgang Fahl

If you do not need the SSL security then you might want to switch it off.

如果您不需要 SSL 安全性,那么您可能需要将其关闭。

 /**
   * 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();
    }
  }

回答by Danny Paul

This error can also happen if the server only sends its leaf certificate and does not send all the chain certificates needed to build the trust chain to the root CA. Unfortunately this is a common misconfiguration of servers.

如果服务器仅发送其叶证书,而不将构建信任链所需的所有链证书发送到根 CA,也会发生此错误。不幸的是,这是服务器的常见错误配置。

Most browsers work around this problem if they already know the missing chain certificate from earlier visits or maybe download the missing certificate if the leaf certificate contains a URL for CA issuers in Authority Information Access (AIA). But this behavior is usually restricted to desktop browsers and other tools simply fail because they cannot build the trust chain.

如果大多数浏览器已经知道先前访问中缺少的链证书,或者如果叶证书包含权威信息访问 (AIA) 中CA 颁发者的 URL,则可能会下载缺少的证书,则大多数浏览器都会解决此问题。但是这种行为通常仅限于桌面浏览器,而其他工具只是因为无法建立信任链而失败。

You can make the JRE to automatically download the intermediate certificate by setting com.sun.security.enableAIAcaIssuersto true

您可以通过设置com.sun.security.enableAIAcaIssuers为JRE 自动下载中间证书true

To verify if the server is sending all the chain certificates you can enter the host in the following SSL certificate validation tool https://www.digicert.com/help/

要验证服务器是否正在发送所有链证书,您可以在以下 SSL 证书验证工具中输入主机https://www.digicert.com/help/