2010-10-31 19 views
33

sto chiamando qualche servizio web HTTPS che il seguente Cliente:PKIX edificio percorso non è riuscita: incapace di trovare valido percorso di certificazione al target richiesto

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

} 

prova:

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

ho ricevuto la seguente 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 

devo qualsiasi certificato da mettere a JDK/JRE/lib/security ??? Inoltre, ho un xxx_IE.crt e xxx_FX.crt (per Firefox e IE rispettivamente, e non funzionano per il client Java sopra, quindi ho bisogno di un certificato specifico per il client Java?

Grazie.

+0

Questo può aiutare: http://stackoverflow.com/questions/9210514/unable-to-find-valid-certification-path-to-requested-target-error-even-after-c – yegor256

risposta

18

è necessario impostare il certificato per colpire questo URL utilizzare sotto codice per impostare chiavi:..

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

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

Questo in realtà ha funzionato per me come ho impostato il fiduciario per essere il mio file 'whatever.jks', anche se non sono sicuro del perché. Ma grazie. – EpicPandaForce

+0

ha funzionato bene qui..anche se non so nemmeno cosa sia TrustStore:/ – aswzen

+0

Il truststore non contiene chiavi, quindi nominarlo .key non ha senso. – EJP

5

ho incontrato un paio di volte ed è stato a causa di una catena di certificati di essere incompleta Se si stanno utilizzando il java trust store standard, potrebbe non avere un certificato necessario per completare la catena di certificati necessaria per convalidare il certificato del sito SSL a cui ti stai connettendo.

Ho riscontrato questo problema con alcuni certificati DigiCert e ho dovuto aggiungere manualmente il certificato intermedio.

+1

Anche io ho un DigiCert e immagino abbia lo stesso problema che hai descritto. Nel mio caso non sono in grado di esportare dal browser l'intera catena di certificati per aggiungerli tutti al trust store. Potresti condividere come hai fatto? –

+0

Che browser stai usando? Credo di aver usato Firefox per farlo anche se non ricordo il metodo esatto. – Casey

+0

Ho usato IE prima. Ora potrei esportarlo con FireFox, aggiunto con successo al trust store ma con la stessa eccezione. Continuerò a provare. Grazie comunque! –

0

Per me, ho riscontrato questo errore durante il richiamo di una chiamata di servizio Web, assicurarsi che il sito abbia uno ssl valido, ovvero che il logo sul lato dell'url sia selezionato, altrimenti è necessario aggiungere il certificato all'archivio delle chiavi di fiducia nella vostra macchina

1

Su Mac OS ho dovuto aprire il certificato autofirmato del server con lo strumento Accesso ai portachiavi del sistema, importarlo, dobubleclicarlo e quindi selezionare "Fidati sempre" (anche se ho impostato lo stesso nell'importatore). Prima di ciò, ovviamente ho eseguito la chiave java con -importcert per importare lo stesso file nell'archiviazione cacert.

0

Ho anche affrontato questo tipo di problema. Sto usando il server Tomcat, quindi metto cartella approvata in tomcat quindi inizia a funzionare. Inoltre ho sostituito JDK1.6 con 1.7 e poi anche il suo funzionamento. Infine ho imparato SSL e ho risolto questo tipo di problemi. Per prima cosa è necessario scaricare i certificati da tale server provider di servizi. Quindi l'handshake ha esito positivo. 1.Try mettere cartella approvato nel server modo seguente 2.use jdk1.7

Avanti 3.Try scaricare certificati validi utilizzando SSL

+0

Questo non risponde alla domanda. Cosa intendi per cartella approvata? – Lucky

6

Java 8 Soluzione: Ho appena avuto questo problema e risolto con l'aggiunta del certificato del sito remoto al mio keystore Java. La mia soluzione era basata sullo solution at the myshittycode blog, che era basato su un previous solution in mykong's blog. Queste soluzioni di articoli del blog si riducono al download di un programma chiamato InstallCert, che è una classe Java che è possibile eseguire dalla riga di comando per ottenere il certificato. Quindi procedere con l'installazione del certificato nel keystore di Java.

Il InstallCert Readme ha funzionato perfettamente per me.Hai solo bisogno di eseguire i seguenti comandi:

  1. javac InstallCert.java
  2. java InstallCert [host]:[port] (entrare nella lista data numero del certificato che si desidera aggiungere alla lista quando si esegue il comando - probabilmente solo)
  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

Vedere il file README di riferimento per un esempio, se necessario.

+0

Si noti che il keystore del sistema è probabilmente in: '$ JAVA_HOME/jre/lib/security/cacerts'. – entpnerd

3

Ecco la soluzione che ho utilizzato per installare il certificato pubblico di un sito nel keystore del sistema per l'uso.

scaricare il certificato con il seguente comando:

UNIX, Linux, Mac

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

finestre

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

che creerà un CRT che può essere utilizzato per importare in un keystore.

Installare il nuovo certificato con il comando:

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

Questo vi permetterà di importare il nuovo cert dal sito che sta causando l'eccezione.

+1

Molti server moderni utilizzano SNI; in tal caso per 's_client' per ottenere i cert (s) corretti aggiungere' -servername $ host'. In java7 su, '-importcert' può gestire il testo estraneo in un file PEM in modo da non aver bisogno di' sed'; anche in j7 su, 'keytool -printcert -sslserver $ host [: $ port] -rfc' recupera la catena cert e stampa in PEM (come' s_client -showcerts' senza il testo estraneo) che è più facile se non si ha OpenSSL installato ad es Finestre. –

4

Avevo colpito quando stavo cercando di avviare una richiesta SOAP dal codice Java. Che cosa ha funzionato per me è stato:

  1. ottenere il certificato Server colpendo l'URL nel navigatore: http://docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-website Questo collegamento ha tutti i passi per ottenere il certificato del server

  2. Una volta ottenuto il certificato del server con voi seguire http://java.globinch.com/enterprise-java/security/pkix-path-building-failed-validation-sun-security-validatorexception/#Valid-Certification-Path-to-Requested-Target.

Copiare il testo dal collegamento, nel caso in cui questo link muore:

Tutto quello che dovete fare per correggere questo errore è quello di aggiungere il certificato del server al Java chiavi attendibili. Per prima cosa è necessario scaricare il documento dal server.

Una volta ottenuto il certificato nel disco rigido, è possibile importarlo in nell'archivio trust Java. Per importare il certificato nell'archivio chiavi Java affidabile , è possibile utilizzare lo strumento java 'keytool'. Al prompt dei comandi passare alla cartella bin JRE, nel mio caso il percorso è: C: \ Program Files \ Java \ jdk1.7.0_75 \ jre \ bin. Quindi utilizzare il comando keytool come segue per importare il certificato in JRE.

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

Ti verrà chiesto di inserire una password. Di default la password è "changeit". Se la password è diversa potresti non essere in grado di importare il certificato .

Problemi correlati