2010-10-31 134 views
33

我打電話一些HTTPS的Web服務,它下面的客戶端:PKIX路徑建設失敗:無法找到有效的認證路徑要求的目標

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客戶端指定一個特定證書嗎?

謝謝。

+0

這可能會幫助:http://stackoverflow.com/questions/9210514/unable-to-find-valid-certification-path-to-requested-target-error-even-after-c – yegor256 2012-10-31 07:14:06

回答

18

您需要設置證書來打這個URL中使用下面的代碼來設置密鑰庫:。

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

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

這實際上工作對我來說,因爲我將信任存儲設置爲我的'whatever.jks'文件,儘管我不確定原因。但是,謝謝。 – EpicPandaForce 2014-10-20 09:48:45

+0

在這裏工作得很好..明白我甚至不知道什麼信任商店是:/ – aswzen 2016-11-10 05:40:25

+0

信任庫不包含密鑰,因此命名它.key是毫無意義的。 – EJP 2017-02-04 07:28:30

5

我碰到的這幾次,這是由於證書鏈不完整。如果你正在使用標準的Java信任存儲,它可能沒有完成驗證證書所需的證書鏈所需的證書您要連接到的SSL站點的名稱。

我遇到了一些DigiCert證書的問題,必須自己手動添加中介證書。

+1

我也有一個DigiCert,我猜你遇到了同樣的問題。在我的情況下,我無法從瀏覽器中導出整個證書鏈,將其全部添加到信任庫中。你能分享你的方式嗎? – 2014-01-14 03:15:05

+0

你使用什麼瀏覽器?我相信我使用Firefox來做到這一點,儘管我不記得確切的方法。 – Casey 2014-01-14 03:16:08

+0

我之前使用過IE。現在我可以用FireFox導出它,成功添加到信任存儲區,但仍然有相同的異常。我會繼續嘗試。不管怎麼說,還是要謝謝你! – 2014-01-14 03:38:49

0

對我來說,我在調用web服務調用時遇到了這個錯誤,請確保該站點有一個有效的ssl,即檢查url側面的徽標,否則需要將證書添加到受信任的密鑰存儲區在您的機器上

1

在Mac OS上,我必須使用系統鑰匙串訪問工具打開服務器的自簽名證書,導入它,dobubleclick它,然後選擇「始終信任」(即使我在導入器中設置相同)。 在此之前,當然我運行java密鑰與-importcert將同一個文件導入cacert存儲。

0

我也遇到了這種類型的問題。我正在使用tomcat服務器,然後我把在tomcat背書的文件夾,然後它開始work.And我也取代了JDK1.6 1.7然後它的工作。最後我學習SSL,然後我解決了這種類型的問題。首先,您需要從該服務提供商服務器下載證書。然後您握手成功。 1.Try把批准文件夾中的服務器 接下來方式 2.使用jdk1.7

下一頁 3.Try使用SSL

+0

這不回答這個問題。通過認可的文件夾是什麼意思? – Lucky 2017-02-17 12:13:39

6

的Java 8解決方案下載有效的證書:我只是有這個問題,通過將遠程站點的證書添加到我的Java密鑰庫來解決此問題。我的解決方案基於solution at the myshittycode blog,它基於previous solution in mykong's blog。這些博客文章解決方案歸結爲下載一個名爲InstallCert的程序,這是一個可從命令行運行以獲取證書的Java類。然後繼續在Java的密鑰庫中安裝證書。

InstallCert Readme適合我。你只需要運行下面的命令:

  1. javac InstallCert.java
  2. java InstallCert [host]:[port](當你運行該命令輸入給定的列表要在列表中添加證書的 - 可能只是)
  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

如果需要,請參閱參考自述文件的示例。

+0

請注意,系統的密鑰庫可能位於:'$ JAVA_HOME/jre/lib/security/cacerts'。 – entpnerd 2016-04-13 20:33:53

3

以下是我用於將站點的公共證書安裝到系統密鑰庫中以供使用的解決方案。

下載使用以下命令證書:

UNIX,LINUX,MAC

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

窗口

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 

這將允許你從引起異常的網站導入新證書。

+1

許多現代服務器使用SNI;如果是's_client'來獲得正確的證書,則添加'-servername $ host'。在java7中,'-importcert'可以處理PEM文件中的無關文本,所以你不需要'sed';在j7中,'keytool -printcert -sslserver $ host [:$ port] -rfc'獲取證書鏈並在PEM中打印(如's_client -showcerts',不帶無關文本),如果沒有OpenSSL安裝例如視窗。 – 2017-10-31 07:55:44

4

我在嘗試從Java代碼發起SOAP請求時遇到了這種情況。什麼工作對我來說是:

  1. 通過點擊瀏覽器的網址,以獲取服務器證書: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」。如果 密碼不同,則可能無法導入 證書。

相關問題