2010-10-31 11 views
33

Estoy llamando a algún servicio web HTTPS, que el siguiente cliente:edificio ruta PKIX falló: no puede encontrar la ruta de certificación válida al destino solicitado

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

} 

prueba:

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

me dieron el siguiente resultado :

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 

¿Necesito algún certificado en jdk/jre/lib/security ??? Además, tengo xxx_IE.crt y xxx_FX.crt (para Firefox e IE respectivamente, y no funcionan para el cliente Java anterior, entonces ¿necesito un certificado específico para el cliente Java?

Gracias.

+0

Esto puede ayudar: http://stackoverflow.com/questions/9210514/unable-to-find-valid-certification-path-to-requested-target-error-even-after-c – yegor256

Respuesta

18

es necesario configurar el certificado para golpear esta url utilizar a continuación código para establecer claves:..

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

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

Esto efectivamente trabajadas para mí, como configuré la tienda de confianza como mi archivo 'whatever.jks', aunque no estoy seguro de por qué. Pero gracias. – EpicPandaForce

+0

funcionó bien aquí ... aunque ni siquiera sé qué es trustStore:/ – aswzen

+0

El truststore no contiene claves, por lo que nombrarlo .key no tiene sentido. – EJP

5

me he encontrado con esto unas cuantas veces y fue debido a una cadena de certificados siendo incompleta si están utilizando el almacén de confianza java estándar, puede no tener un certificado que se necesita para completar la cadena de certificados que se requiere para validar el certi ficato del sitio SSL al que se está conectando.

Me encontré con este problema con algunos certificados DigiCert y tuve que agregar manualmente el certificado intermediario.

+1

También tengo un DigiCert y supongo que tengo el mismo problema que usted describió. En mi caso, no puedo exportar desde el navegador toda la cadena de certificados para agregarlos a la tienda de confianza. ¿Podrías compartir la forma en que lo hiciste? –

+0

¿Qué navegador estás usando? Creo que usé Firefox para hacerlo, aunque no recuerdo el método exacto. – Casey

+0

Utilicé IE antes. Ahora podría exportarlo con Firefox, agregado exitosamente al almacén de confianza pero teniendo la misma excepción. Continuaré intentándolo. ¡Gracias de cualquier manera! –

0

Para mí, me encontré con este error al invocar una llamada al servicio web, asegúrese de que el sitio tenga un ssl válido, es decir, el logotipo en el lateral de la url está marcado; de lo contrario, necesito agregar el certificado al almacén de claves de confianza en su máquina

1

En Mac OS tuve que abrir el certificado autofirmado del servidor con la herramienta System Keychain Access, importarlo, dobubleclic y seleccionar "Confiar siempre" (aunque configuré lo mismo en el importador). Antes de eso, por supuesto, ejecuté la clave java con -importcert para importar el mismo archivo al almacenamiento cacert.

0

También me enfrenté a este tipo de problema. Estoy usando el servidor Tomcat luego puse la carpeta endosada en Tomcat, entonces está comenzando a funcionar.Y también reemplacé JDK1.6 con 1.7, entonces también funciona. Finalmente, aprendo SSL, luego resolví este tipo de problemas.En primer lugar, debe descargar los certificados de ese servidor proveedor de servicios.entonces su apretón de manos es exitoso. 1.Try poner carpeta respaldado en su servidor siguiente manera 2.use jdk1.7

Siguiente 3.Try para descargar certificados válidos utilizando SSL

+0

Esto no responde la pregunta. ¿Qué quieres decir con una carpeta endosada? – Lucky

6

Java 8 Solución: acabo de tener este problema y lo resolvió agregando el certificado del sitio remoto a mi almacén de claves Java. Mi solución se basó en el solution at the myshittycode blog, que se basó en un previous solution in mykong's blog. Estas soluciones de artículos de blog se reducen a la descarga de un programa llamado InstallCert, que es una clase de Java que puede ejecutar desde la línea de comandos para obtener el certificado. A continuación, procede a instalar el certificado en el almacén de claves de Java.

El InstallCert Readme funcionó perfectamente para mí.Sólo tiene que ejecutar los siguientes comandos:

  1. javac InstallCert.java
  2. java InstallCert [host]:[port] (entrar en la lista dada número del certificado que desea agregar en la lista cuando se ejecuta el comando - probablemente sólo)
  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

Consulte el archivo README al que se hace referencia para un ejemplo si es necesario.

+0

Tenga en cuenta que el almacén de claves del sistema probablemente esté en: '$ JAVA_HOME/jre/lib/security/cacerts'. – entpnerd

3

Aquí está la solución que utilicé para instalar el certificado público de un sitio en el almacén de claves de los sistemas para su uso.

descargar el certificado con el siguiente comando:

Unix, Linux, Mac

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

ventanas

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

que va a crear un CRT que puede ser utilizado para importar a un almacén de claves

Instalar el nuevo certificado con el comando:

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

Esto le permitirá importar el nuevo certificado desde el sitio que está causando la excepción.

+1

Muchos servidores modernos usan SNI; si es así para que 's_client' obtenga el (los) cert (es) correcto (s) add' -servername $ host'. En java7 up, '-importcert' puede manejar texto extraño en un archivo PEM para que no necesite el' sed'; también en j7, 'keytool -printcert -sslserver $ host [: $ port] -rfc' recupera la cadena de certificados e imprime en PEM (como' s_client -showcerts' sin el texto extraño) que es más fácil si no tiene OpenSSL instalado, por ejemplo Windows. –

4

Me había golpeado esto cuando estaba tratando de iniciar una solicitud SOAP desde el código de Java. Lo que funcionó para mí fue:

  1. Obtener el certificado del servidor al golpear la URL en el navegador: http://docs.bvstools.com/home/ssl-documentation/exporting-certificate-authorities-cas-from-a-website Este enlace tiene todos los pasos para obtener el certificado

  2. servidor Una vez que tenga el certificado de servidor con usted siga http://java.globinch.com/enterprise-java/security/pkix-path-building-failed-validation-sun-security-validatorexception/#Valid-Certification-Path-to-Requested-Target.

copiar el texto del enlace, en caso de que este enlace muere:

Todo lo que necesita hacer para corregir este error es añadir el certificado servidor a su almacén de claves de Java de confianza. Primero, debe descargar el documento del servidor.

Una vez que tenga el certificado en su disco duro, puede importarlo al el almacén de confianza de Java. Para importar el certificado al almacén de claves Java de confianza, puede usar la herramienta java 'keytool'. En el símbolo del sistema vaya a la carpeta JRE bin, en mi caso, la ruta es: C: \ Program Files \ Java \ jdk1.7.0_75 \ jre \ bin. A continuación, utilice el comando keytool de la siguiente manera para importar el certificado a JRE.

herramienta de claves -import -alias _alias_name_ -keystore .. \ lib \ security \ cacerts -file _path_to_cer_file

Se le pedirá una contraseña. Por defecto, la contraseña es "changeit". Si la contraseña es diferente, es posible que no pueda importar el certificado .

Cuestiones relacionadas