Сбой построения пути PKIX: невозможно найти действительный путь сертификации для запрошенной цели - PullRequest
40 голосов
/ 31 октября 2010

Я звоню в какой-нибудь HTTPS веб-сервис, который следующий клиент:

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

}

Тест:

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

Я получил следующий вывод:

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

Нужно ли размещать какой-либо сертификат в jdk / jre / lib / security ??? Кроме того, у меня есть xxx_IE.crt и xxx_FX.crt (для Firefox и IE соответственно, и они не работают для вышеуказанного клиента Java, поэтому мне нужен специальный сертификат для клиента Java?

Спасибо.

Ответы [ 9 ]

23 голосов
/ 10 мая 2013

Вам нужно установить сертификат, чтобы попасть по этому URL. используйте код ниже для установки хранилища ключей:

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

System.setProperty("javax.net.ssl.trustStorePassword","qwerty");
16 голосов
/ 07 апреля 2016

Java 8 Решение: у меня возникла эта проблема, и я решил ее, добавив сертификат удаленного сайта в хранилище ключей Java.Мое решение было основано на решении в myshittycode blog , которое было основано на предыдущем решении в блоге mykong .Эти решения для статей блога сводятся к загрузке программы под названием InstallCert , которая является классом Java, который можно запустить из командной строки для получения сертификата.Затем вы переходите к установке сертификата в хранилище ключей Java.

InstallCert Readme отлично сработал для меня.Вам просто нужно выполнить следующие команды:

  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

См. файл README, на который есть ссылкаНапример, если это необходимо.

5 голосов
/ 12 июля 2013

Я сталкивался с этим несколько раз, и это было из-за неполной цепочки сертификатов. Если вы используете стандартное хранилище доверенных сертификатов Java, у него может не быть сертификата, необходимого для завершения цепочки сертификатов, которая требуется для проверки сертификата сайта SSL, к которому вы подключаетесь.

Я столкнулся с этой проблемой с некоторыми сертификатами DigiCert, и мне пришлось самому добавлять промежуточный сертификат.

4 голосов
/ 01 марта 2017

Я столкнулся с этим, когда пытался инициировать запрос SOAP из кода Java. То, что сработало для меня, было:

  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-Requested-Target.

Копирование текста по ссылке, в случае, если эта ссылка умирает:

Все, что вам нужно сделать, чтобы исправить эту ошибку, это добавить сертификат сервера в ваше доверенное хранилище ключей Java. Сначала вам нужно скачать документ с сервера.

Если у вас есть сертификат на жестком диске, вы можете импортировать его в хранилище доверия Java. Чтобы импортировать сертификат в доверенную Java хранилище ключей, вы можете использовать инструмент Java Java Keytool. В командной строке перейдите в папку bin JRE, в моем случае это путь: C: \ Program Файлы \ Java \ jdk1.7.0_75 \ jre \ bin. Затем используйте команду keytool следующим образом импортировать сертификат в JRE.

keytool -import -alias _alias_name_ -keystore .. \ lib \ security \ cacerts -файл _path_to_cer_file

Будет запрошен пароль. По умолчанию пароль «changeit». Если пароль другой, вы не сможете импортировать сертификат.

4 голосов
/ 21 февраля 2017

Вот решение, которое я использовал для установки открытого сертификата сайта в хранилище ключей системы для использования.

Загрузите сертификат с помощью следующей команды:

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

Это создаст crt, который можно использовать для импорта в хранилище ключей.

Установите новый сертификат с помощью команды:

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

Это позволит вам импортировать новый сертификат с сайта, который вызывает исключение.

2 голосов
/ 01 сентября 2018

Если вам не нужна безопасность 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();
    }
  }
2 голосов
/ 03 июля 2015

В Mac OS мне пришлось открыть самозаверяющий сертификат сервера с помощью системного инструмента Keychain Access, импортировать его, кликнуть по нему и затем выбрать «Всегда доверять» (даже если я установил то же самое в импортере).Перед этим, конечно, я запустил java-ключ, взятый с -importcert, чтобы импортировать тот же файл в хранилище cacert.

0 голосов
/ 25 августа 2015

Я также столкнулся с этим типом проблемы. Я использую сервер Tomcat, затем я положил одобренную папку в Tomcat, после чего она начала работать. И также я заменил JDK1.6 на 1.7, а затем и на него. Тип проблем. Сначала вам необходимо загрузить сертификаты с этого сервера поставщика услуг. После этого рукопожатие будет успешным. 1. Попробуйте поместить одобренную папку на ваш сервер Следующий путь 2.use jdk1.7

Следующий 3. Попробуйте загрузить действительные сертификаты, используя SSL

0 голосов
/ 24 ноября 2014

Для меня, я столкнулся с этой ошибкой при вызове веб-сервиса, убедитесь, что на сайте есть действительный ssl, т.е. проверен логотип на стороне URL, в противном случае необходимо добавить сертификат в хранилище доверенных ключей вваша машина

...