web-dev-qa-db-ja.com

PKIXパスの構築に失敗しました:要求されたターゲットへの有効な証明書パスが見つかりません

私は次のクライアントの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;
    }

}

テスト:

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クライアントに特定の証明書が必要ですか?

ありがとう。

40
Muhammad Hewedy

このURLにアクセスするには、証明書を設定する必要があります。以下のコードを使用してキーストアを設定します。

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

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

Java 8の解決策:この問題が発生し、リモートサイトの証明書をJavaキーストアに追加して解決しました。私のソリューションはmyshittycodeの solutionに基づいていましたblog 、これはmykongのブログの previousソリューションに基づいていました 。これらのブログ記事のソリューションは、 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ファイルを参照してください。

16
entpnerd

これに何度か遭遇しましたが、これは証明書チェーンが不完全であったためです。標準のJavaトラストストアを使用している場合、接続先のSSLサイトの証明書を検証するために必要な証明書チェーンを完了するために必要な証明書がない場合があります。

いくつかのDigiCert証明書でこの問題に遭遇し、自分で中間証明書を手動で追加する必要がありました。

5
Casey

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 '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」です。パスワードが異なる場合、証明書をインポートできない場合があります。

4
Rohit

以下は、サイトの公開証明書をシステムキーストアにインストールして使用するために使用したソリューションです。

次のコマンドで証明書をダウンロードします:

nix、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

これにより、例外の原因となっているサイトから新しい証明書をインポートできます。

4
Ray Hunter

Mac OSでは、システムのキーチェーンアクセスツールを使用してサーバーの自己署名証明書を開き、それをインポートし、それをダブルクリックして、「インポーターで同じ設定を行っても」「常に信頼する」を選択する必要がありました。その前に、もちろん、Javaキーを-importcertで使用して、同じファイルをcacertストレージにインポートしました。

2
Mike Makarov

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
Wolfgang Fahl

私にとっては、Webサービス呼び出しを呼び出すときにこのエラーが発生しました。サイトに有効なSSLがあることを確認してください、つまりURLの側のロゴがチェックされていることを確認してください

0
mel3kings

また、このタイプの問題に直面しました.Tomcatサーバーを使用しており、Tomcatに承認されたフォルダを入れて動作します。また、JDK1.6を1.7に置き換えてから動作します。最初に、そのサービスプロバイダーサーバーから証明書をダウンロードする必要があります。その後、ハンドシェイクは成功します。 1.サーバーに承認済みのフォルダーを配置してみてください2.jdk1.7を使用します

次へ3.SSLを使用して有効な証明書をダウンロードしてみてください

0
sravan kumar