Java: sun.security.provider.certpath.SunCertPathBuilderException: no se puede encontrar la ruta de certificación válida para el objetivo solicitado

249

Tengo una clase que descargará un archivo de un servidor https . Cuando lo ejecuto, devuelve muchos errores. Parece que tengo un problema con mi certificado. ¿Es posible ignorar la autenticación cliente-servidor? ¿Si es así, cómo?

package com.da;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.CharBuffer;
import java.util.concurrent.Future;

import org.apache.http.HttpResponse;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.impl.nio.client.DefaultHttpAsyncClient;
import org.apache.http.nio.IOControl;
import org.apache.http.nio.client.HttpAsyncClient;
import org.apache.http.nio.client.methods.AsyncCharConsumer;
import org.apache.http.nio.client.methods.HttpAsyncGet;
import org.apache.http.nio.client.methods.HttpAsyncPost;

public class RSDDownloadFile {
    static FileOutputStream fos;

    public void DownloadFile(String URI, String Request) throws Exception
    {
        java.net.URI uri = URIUtils.createURI("https", "176.66.3.69:6443", -1, "download.aspx",
                "Lang=EN&AuthToken=package", null);
        System.out.println("URI Query: " + uri.toString());

        HttpAsyncClient httpclient = new DefaultHttpAsyncClient();
        httpclient.start();
        try {
            Future<Boolean> future = httpclient.execute(
                    new HttpAsyncGet(uri),
                    new ResponseCallback(), null);

            Boolean result = future.get();
            if (result != null && result.booleanValue()) {
                System.out.println("\nRequest successfully executed");
            } else {
                System.out.println("Request failed");
            }              
        } 
        catch(Exception e){
            System.out.println("[DownloadFile] Exception: " + e.getMessage());
        }
        finally {
            System.out.println("Shutting down");
            httpclient.shutdown();
        }
        System.out.println("Done");  

    }

    static class ResponseCallback extends AsyncCharConsumer<Boolean> {

        @Override
        protected void onResponseReceived(final HttpResponse response) {
             System.out.println("Response: " + response.getStatusLine());
             System.out.println("Header: " + response.toString());
             try {   
                 //if(response.getStatusLine().getStatusCode()==200)
                     fos = new FileOutputStream( "Response.html" );
             }catch(Exception e){
                 System.out.println("[onResponseReceived] Exception: " + e.getMessage());
             }
        }

        @Override
        protected void onCharReceived(final CharBuffer buf, final IOControl ioctrl) throws IOException {
            try
            {
                while (buf.hasRemaining()) 
                {
                    //System.out.print(buf.get());
                    fos.write(buf.get());
                }
            }catch(Exception e)
            {
                System.out.println("[onCharReceived] Exception: " + e.getMessage());
            }
        }

        @Override
        protected void onCleanup() {
            try
            {             
                if(fos!=null)
                    fos.close();
            }catch(Exception e){
                System.out.println("[onCleanup] Exception: " + e.getMessage());         
            }
             System.out.println("onCleanup()");
        }

        @Override
        protected Boolean buildResult() {
            return Boolean.TRUE;
        }

    }
}

Errores:

URI Query: https://176.66.3.69:6443/download.aspx?Lang=EN&AuthToken=package
Aug 2, 2011 3:47:57 PM org.apache.http.impl.nio.client.NHttpClientProtocolHandler exception
SEVERE: I/O error: General SSLEngine problem
javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(Unknown Source)
    at javax.net.ssl.SSLEngine.wrap(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:154)
    at org.apache.http.impl.nio.reactor.SSLIOSession.isAppInputReady(SSLIOSession.java:276)
    at org.apache.http.impl.nio.client.InternalClientEventDispatch.inputReady(InternalClientEventDispatch.java:79)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:161)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:335)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:275)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:542)
    at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.net.ssl.internal.ssl.Handshaker$DelegatedTask.run(Unknown Source)
    at org.apache.http.impl.nio.reactor.SSLIOSession.doHandshake(SSLIOSession.java:180)
    ... 9 more
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(Unknown Source)
    at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
    at sun.security.validator.Validator.validate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
    at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(Unknown Source)
    ... 16 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(Unknown Source)
    ... 21 more
onCleanup()

[DownloadFile] Exception: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
Shutting down
Done
neztreh
fuente
2
Una vez recibí este error y contacté a nuestro equipo de seguridad, y resultó que tenía que parchear el JAR que estábamos usando, ya que nuestro equipo estaba usando uno obsoleto provisto por la compañía. Solo un FYI para cualquier otra persona que pueda estar en una situación similar.
kayleeFrye_onDeck

Respuestas:

215

El problema aparece cuando su servidor tiene un certificado autofirmado. Para solucionarlo, puede agregar este certificado a la lista de certificados de confianza de su JVM.

En este artículo, el autor describe cómo obtener el certificado de su navegador y agregarlo al archivo cacerts de su JVM. Puede editar el JAVA_HOME/jre/lib/security/cacertsarchivo o ejecutar su aplicación con el -Djavax.net.ssl.trustStoreparámetro. Verifique qué JDK / JRE está utilizando también, ya que esto a menudo es una fuente de confusión.

Consulte también: ¿Cómo se resuelven los nombres del servidor de certificados SSL / ¿Puedo agregar nombres alternativos usando keytool? Si te topas con la java.security.cert.CertificateException: No name matching localhost foundexcepción.

Maxim Mazin
fuente
3
Esto no me ha funcionado. Tengo la raíz y el certificado de la cadena instalados, pero Tomcat-7 todavía informa validatorException causada por "no se puede encontrar la ruta de certificación válida para el objetivo solicitado" alguna forma de depurar esto?
Cheruvim
El problema también aparece con un certificado firmado por otra persona que no es de confianza.
Marqués de Lorne
¡Excelente! ¡Funciona! Simplemente no olvides que podrías tener tanto jre como jdk, y ambos cacertsdeben actualizarse
Dima Fomin
En mi caso, la CA raíz estaba allí pero no la siguiente CA inactiva. Agregar el siguiente CA hizo el truco, gracias.
java-addict301
1
En mi caso, estoy usando Netbeans + Apache Tomcat (integrado), por lo tanto, agrego .cer a la tienda de confianza "cacerts" en Jdk / jre (C: \ Archivos de programa \ Java \ jdk1.8.0_152 \ jre \ lib \ seguridad) y Jre (C: \ Archivos de programa \ Java \ jre1.8.0_91 \ lib \ security) me funcionan
Jnn
149

Esto es lo que funciona de manera confiable para mí en macOS. Asegúrese de reemplazar example.com y 443 con el nombre de host y el puerto reales al que intenta conectarse, y proporcione un alias personalizado. El primer comando descarga el certificado proporcionado del servidor remoto y lo guarda localmente en formato x509. El segundo comando carga el certificado guardado en el almacén de confianza SSL de Java.

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2>/dev/null) -out ~/example.crt
sudo keytool -importcert -file ~/example.crt -alias example -keystore $(/usr/libexec/java_home)/jre/lib/security/cacerts -storepass changeit
Gabe Martin-Dempesy
fuente
3
Funciona para mi ¿por qué? Necesitas dar una explicación.
Marqués de Lorne
openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2> / dev / null) -out ~ / example.crt: ¿qué es example.crt en el comando? Tengo un certificado .pem que tengo que dar eso aquí ??
Vishnu Ranganathan
3
.crt y .pem son extensiones de archivo de uso común para el mismo formato de archivo. Si ya tiene el archivo, simplemente ejecute el segundo comando y páselo al argumento -file.
Gabe Martin-Dempesy
1
Buena cosa. Lo único es que tuve que usar el último openssl 1.0.Xx por alguna razón, el viejo 9.X.Xx no funcionaba.
zbstof
1
Esto no funciona con el punto final SNI. Para ese caso, debe agregar: -servername example.com al obtener el certificado
Patrik Beck
46

Tuve el mismo problema con un certificado comodín firmado válido de Symantec.

Primero intente ejecutar su aplicación Java con -Djavax.net.debug = SSL para ver qué está sucediendo realmente.

Terminé importando el certificado intermedio que estaba causando la ruptura de la cadena de certificados .

Descargué el certificado intermedio faltante de Symantec (puede ver el enlace de descarga del certificado faltante en el registro de protocolo de enlace SSL: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer en mi caso).

E importé el certificado en el almacén de claves de Java. Después de importar el certificado intermedio, mi certificado SSL comodín finalmente comenzó a funcionar:

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer
Stephan Oudmaijer
fuente
Este fue el caso:
Kisna
2
Para evitar confusiones, ejecute java (o jcurl) con los parámetros de depuración para ver la "cadena de certificados" remota en los registros, luego coloque el "CN" en el almacén de confianza aprobado explícitamente (en lugar del predeterminado) de la siguiente manera, si no está presente, debe agregarlo. ssllabs.com/ssltest/analyze.html mostrará si los certificados del lado del servidor tienen una cadena incompleta e incluye certificados de ruta de certificación intermedios que deben agregarse. -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12 -Djavax.net.ssl.keyStore=our-client-certs -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=their-server-certs
kisna
Y, por supuesto, el artículo oficial para depurar problemas de SSL: docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/… blogs.oracle.com/java-platform-group/entry/…
kisna
Tuve el mismo problema, esto es muy útil, pero en mi caso solo tuve que agregar el certificado del servidor al archivo cacerts de la versión JDK
Pigritia
Tenga en cuenta que existe otra herramienta llamada portecle que puede abrir el archivo cacert (almacén de certificados) e importar el certificado fácilmente. Solo recuerde guardar el archivo cacert después.
will824 hace
41
  1. Exporte el certificado SSL usando Firefox. Puede exportarlo presionando la URL en el navegador y luego seleccionar la opción para exportar el certificado. Supongamos que el nombre del archivo cert es your.ssl.server.name.crt
  2. Ve a tu JRE_HOME/binoJDK/JRE/bin
  3. Escribe el comando
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. Reinicia tu proceso Java
Robin
fuente
13
Si se le solicita una contraseña, use la contraseña predeterminada del almacén de claves cacerts changeit( stackoverflow.com/a/22782035/1304830 ). También asegúrese de ejecutar cmd como administrador.
Fr4nz
22

La respuesta de @Gabe Martin-Dempesy me ayudó. Y escribí un pequeño guión relacionado con él. El uso es muy simple.

Instale un certificado del host:

> sudo ./java-cert-importer.sh example.com

Elimine el certificado que ya se instaló.

> sudo ./java-cert-importer.sh example.com --delete

java-cert-importer.sh

#!/usr/bin/env bash

# Exit on error
set -e

# Ensure script is running as root
if [ "$EUID" -ne 0 ]
  then echo "WARN: Please run as root (sudo)"
  exit 1
fi

# Check required commands
command -v openssl >/dev/null 2>&1 || { echo "Required command 'openssl' not installed. Aborting." >&2; exit 1; }
command -v keytool >/dev/null 2>&1 || { echo "Required command 'keytool' not installed. Aborting." >&2; exit 1; }

# Get command line args
host=$1; port=${2:-443}; deleteCmd=${3:-${2}}

# Check host argument
if [ ! ${host} ]; then
cat << EOF
Please enter required parameter(s)

usage:  ./java-cert-importer.sh <host> [ <port> | default=443 ] [ -d | --delete ]

EOF
exit 1
fi;

if [ "$JAVA_HOME" ]; then
    javahome=${JAVA_HOME}
elif [[ "$OSTYPE" == "linux-gnu" ]]; then # Linux
    javahome=$(readlink -f $(which java) | sed "s:bin/java::")
elif [[ "$OSTYPE" == "darwin"* ]]; then # Mac OS X
    javahome="$(/usr/libexec/java_home)/jre"
fi

if [ ! "$javahome" ]; then
    echo "WARN: Java home cannot be found."
    exit 1
elif [ ! -d "$javahome" ]; then
    echo "WARN: Detected Java home does not exists: $javahome"
    exit 1
fi

echo "Detected Java Home: $javahome"

# Set cacerts file path
cacertspath=${javahome}/lib/security/cacerts
cacertsbackup="${cacertspath}.$$.backup"

if ( [ "$deleteCmd" == "-d" ] || [ "$deleteCmd" == "--delete" ] ); then
    sudo keytool -delete -alias ${host} -keystore ${cacertspath} -storepass changeit
    echo "Certificate is deleted for ${host}"
    exit 0
fi

# Get host info from user
#read -p "Enter server host (E.g. example.com) : " host
#read -p "Enter server port (Default 443) : " port

# create temp file
tmpfile="/tmp/${host}.$$.crt"

# Create java cacerts backup file
cp ${cacertspath} ${cacertsbackup}

echo "Java CaCerts Backup: ${cacertsbackup}"

# Get certificate from speficied host
openssl x509 -in <(openssl s_client -connect ${host}:${port} -prexit 2>/dev/null) -out ${tmpfile}

# Import certificate into java cacerts file
sudo keytool -importcert -file ${tmpfile} -alias ${host} -keystore ${cacertspath} -storepass changeit

# Remove temp certificate file
rm ${tmpfile}

# Check certificate alias name (same with host) that imported successfully
result=$(keytool -list -v -keystore ${cacertspath} -storepass changeit | grep "Alias name: ${host}")

# Show results to user
if [ "$result" ]; then
    echo "Success: Certificate is imported to java cacerts for ${host}";
else
    echo "Error: Something went wrong";
fi;
bhdrk
fuente
Funciona perfectamente. ¡Gran trabajo! . Así es como funciona: inicie su servicio SSL (si no se está ejecutando) y ejecute el comando como se explica (por ejemplo ./java-cert-importer.sh example.com 1234). Eso es.
lepe
1
Funciona genial. Estaba recibiendo el error en un servidor Jenkins que se conectaba a una API externa que cambia su certificado y falla mis construcciones. Esto resuelve mi problema
user9869932
Oracle debería haber proporcionado algo como esto en primer lugar o nunca haber creado su propia horrible solución SSL. El manejo del certificado SSL debe ser el trabajo de un sistema operativo.
Wolfgang Fahl el
17

Citando de No más "no se puede encontrar la ruta de certificación válida para el objetivo solicitado"

cuando intente abrir una conexión SSL a un host utilizando JSSE. Lo que esto generalmente significa es que el servidor está usando un certificado de prueba (posiblemente generado usando keytool) en lugar de un certificado de una Autoridad de Certificación comercial bien conocida como Verisign o GoDaddy. Los navegadores web muestran cuadros de diálogo de advertencia en este caso, pero dado que JSSE no puede asumir que un usuario interactivo está presente, solo arroja una excepción por defecto.

La validación de certificados es una parte muy importante de la seguridad SSL, pero no estoy escribiendo esta entrada para explicar los detalles. Si está interesado, puede comenzar leyendo la propaganda de Wikipedia. Estoy escribiendo esta entrada para mostrar una manera simple de hablar con ese host con el certificado de prueba, si realmente lo desea.

Básicamente, desea agregar el certificado del servidor al KeyStore con sus certificados de confianza

Pruebe el código provisto allí. Podría ayudar.

Nishant
fuente
55
La parte sobre "La validación de certificados es una parte muy importante de la seguridad SSL" no es necesariamente cierta. SSL le brinda dos garantías: (1) que su comunicación es privada y (2) que está hablando con un servidor conocido por la NSA. (:-) A veces solo le importa la privacidad de la conversación, y luego La certificación autofirmada está bien. Ver social-biz.org/2011/10/16/the-anti-ssl-conspiracy
AgilePro el
@AgilePro SSL le brinda cuatro garantías: autenticación, privacidad, integridad y la posibilidad de autorización. No , no le otorga ninguna garantía de que usted está hablando con un servidor sabe que la NSA. Cuidar solo la privacidad sin autenticación es una contradicción en los términos.
Marqués de Lorne
@EJP De acuerdo en que si usa un certificado de cliente puede obtener autenticación y supongo que existe la posibilidad de autorización ... pero la mayoría de los usos no son con un certificado de cliente. ¿Cómo llamaría la diferencia entre un certificado "autofirmado" y un certificado de una autoridad de firma? ¿La autoridad firmante da "integridad"? Mi broma sobre la NSA es que todas las autoridades firmantes no pueden garantizar positivamente la independencia de todo. En realidad, no es tan paranoico, pero el punto es que su certificado es SOLO tan secreto como la autoridad de firma puede hacerlo. Autofirmado puede ser más secreto.
AgilePro
@AgilePro El uso de un certificado de servidor autentica el servidor y es necesario para asegurar SSL, como se indica en RFC 2246. Los certificados no son secretos en absoluto: por lo tanto, el resto de su comentario no tiene sentido.
Marqués de Lorne
6

Esto resolvió mi problema,

Necesitamos importar el certificado en el Java local. Si no, podríamos obtener la siguiente excepción.

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: error en la construcción de la ruta PKIX: sun.security.provider.certpath.SunCertPathBuilderException: no se puede encontrar la ruta de certificación válida para el objetivo solicitado
        en sun.security.ssl.Alerts.getSSLException (Alerts.java:192)
        en sun.security.ssl.SSLSocketImpl.fatal (SSLSocketImpl.java:1949)
        en sun.security.ssl.Handshaker.fatalSE (Handshaker.java:302)

SSLPOKE es una herramienta donde puede probar la conectividad https desde su máquina local.

Comando para probar la conectividad:

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
    sun.security.validator.ValidatorException: error en la construcción de la ruta PKIX: 
    sun.security.provider.certpath.SunCertPathBuilderException: no se puede encontrar la ruta de certificación válida para el objetivo solicitado
        en sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:387)
        en sun.security.validator.PKIXValidator.engineValidate (PKIXValidator.java:292)
        en sun.security.validator.Validator.validate (Validator.java:260)
        en sun.security.ssl.X509TrustManagerImpl.validate (X509TrustManagerImpl.java:324)
        en sun.security.ssl.X509TrustManagerImpl.checkTrusted (X509TrustManagerImpl.java:229)
        en sun.security.ssl.X509TrustManagerImpl.checkServerTrusted (X509TrustManagerImpl.java:124)
        en sun.security.ssl.ClientHandshaker.serverCertificate (ClientHandshaker.java:1496)
        en sun.security.ssl.ClientHandshaker.processMessage (ClientHandshaker.java:216)
        en sun.security.ssl.Handshaker.processLoop (Handshaker.java:1026)
        en sun.security.ssl.Handshaker.process_record (Handshaker.java:961)
        en sun.security.ssl.SSLSocketImpl.readRecord (SSLSocketImpl.java:1062)
        en sun.security.ssl.SSLSocketImpl.performInitialHandshake (SSLSocketImpl.java:1375)
        en sun.security.ssl.SSLSocketImpl.writeRecord (SSLSocketImpl.java:747)
        en sun.security.ssl.AppOutputStream.write (AppOutputStream.java:123)
        en sun.security.ssl.AppOutputStream.write (AppOutputStream.java:138)
        en SSLPoke.main (SSLPoke.java:31)
    Causado por: sun.security.provider.certpath.SunCertPathBuilderException: no se puede encontrar una ruta de certificación válida para 
    objetivo solicitado
        en sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)
        en sun.security.provider.certpath.SunCertPathBuilder.engineBuild (SunCertPathBuilder.java:126)
        en java.security.cert.CertPathBuilder.build (CertPathBuilder.java:280)
        en sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:382)
        ... 15 más
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

esto primero indicaría "Ingresar contraseña del almacén de claves:" changeites la contraseña predeterminada. y finalmente un mensaje "¿Confía en este certificado? [no]:", proporcione "sí" para agregar el certificado al almacén de claves.

Verificación:

C:\tools>"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
Successfully connected    
Naveen
fuente
5

Pude hacerlo funcionar solo con código, es decir, no es necesario usar keytool:

import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class Test
{
    private static final DynamicIntProperty MAX_TOTAL_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty ROUTE_CONNECTIONS = DynamicPropertyFactory.getInstance().getIntProperty("X.total.connections", 40);
    private static final DynamicIntProperty CONNECT_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connect.timeout", 60000);
    private static final DynamicIntProperty SOCKET_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.socket.timeout", -1);
    private static final DynamicIntProperty CONNECTION_REQUEST_TIMEOUT = DynamicPropertyFactory.getInstance().getIntProperty("X.connectionrequest.timeout", 60000);
    private static final DynamicBooleanProperty STALE_CONNECTION_CHECK = DynamicPropertyFactory.getInstance().getBooleanProperty("X.checkconnection", true);

    public static void main(String[] args) throws Exception
    {

        SSLContext sslcontext = SSLContexts.custom()
                .useTLS()
                .loadTrustMaterial(null, new TrustStrategy()
                {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException
                    {
                        return true;
                    }
                })
                .build();
        SSLIOSessionStrategy sslSessionStrategy = new SSLIOSessionStrategy(sslcontext, new AllowAll());

        Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder.<SchemeIOSessionStrategy>create()
                .register("http", NoopIOSessionStrategy.INSTANCE)
                .register("https", sslSessionStrategy)
                .build();

        DefaultConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(IOReactorConfig.DEFAULT);
        PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor, sessionStrategyRegistry);
        connectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.get());
        connectionManager.setDefaultMaxPerRoute(ROUTE_CONNECTIONS.get());

        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(SOCKET_TIMEOUT.get())
                .setConnectTimeout(CONNECT_TIMEOUT.get())
                .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT.get())
                .setStaleConnectionCheckEnabled(STALE_CONNECTION_CHECK.get())
                .build();

        CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
                .setSSLStrategy(sslSessionStrategy)
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();

        httpClient.start();

        // use httpClient...
    }

    private static class AllowAll implements X509HostnameVerifier
    {
        @Override
        public void verify(String s, SSLSocket sslSocket) throws IOException
        {}

        @Override
        public void verify(String s, X509Certificate x509Certificate) throws SSLException {}

        @Override
        public void verify(String s, String[] strings, String[] strings2) throws SSLException
        {}

        @Override
        public boolean verify(String s, SSLSession sslSession)
        {
            return true;
        }
    }
}
Jonas Bergström
fuente
1
Por cierto, estoy usando httpasyncclient: 4.0.1
Jonas Bergström
Necesitaba algo similar, @ JonasBergström, su solución con SSLContext ayuda mucho.
EnterSB
8
Tenga en cuenta que esta solución es insegura.
Marqués de Lorne
Gracias Jonas, tu solución resolvió el problema. Pero descubrí que cuesta mucho tiempo (3 - 5s) crear la primera conexión, después de eso cada conexión solo necesita 300-400 ms.
twcai
5

El origen de este error en mi instancia de Apache 2.4 (usando un certificado comodín Comodo) fue una ruta incompleta al certificado raíz firmado SHA-1. Había varias cadenas en el certificado emitido, y la cadena que conducía a un certificado raíz SHA-1 no tenía un certificado intermedio . Los navegadores modernos saben cómo manejar esto, pero Java 7 no lo maneja de manera predeterminada (aunque hay algunas formas complicadas de lograr esto en el código). El resultado son mensajes de error que parecen idénticos al caso de los certificados autofirmados:

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:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 22 more

En este caso, se está produciendo el mensaje "no se puede encontrar la ruta de certificación válida para el objetivo solicitado" debido a la falta del certificado intermedio. Puede verificar qué certificado falta con la prueba SSL Labs en el servidor. Una vez que encuentre el certificado apropiado, descárguelo y (si el servidor está bajo su control) agréguelo al paquete de certificados. Alternativamente, puede importar el certificado que falta localmente. Acomodar este problema en el servidor es una solución más general al problema.

vallismortis
fuente
ssllabs.com/ssltest es un salvador, solo tiene que compararlo con una validación de certificado de trabajo.
kisna
5

Solo para Windows, siga estos pasos:

  1. En Chrome ve a la configuración.
  2. En Configuración, haga clic en Mostrar configuración avanzada.
  3. En HTTPS / SSL, haga clic en Administrar certificados.
  4. Exporte su certificado.
  5. En las búsquedas de Windows (presionando la tecla de Windows en el teclado) escriba java.
  6. Seleccione la opción (Configurar Java) que abrirá el Panel de control de Java
  7. Seleccione la pestaña Seguridad en el Panel de control de Java
  8. Seleccione Administrar certificados
  9. Haga clic en Importar
  10. En la pestaña (Usuario) seleccionada y tipo de certificado como (Certificados de confianza)
  11. Haga clic en el botón Importar y busque el certificado descargado e impórtelo.
Praveen
fuente
4

Para quienes gustan de Debian y Java preempaquetado:

sudo mkdir /usr/share/ca-certificates/test/  # don't mess with other certs
sudo cp ~/tmp/test.loc.crt /usr/share/ca-certificates/test/
sudo dpkg-reconfigure --force ca-certificates  # check your cert in curses GUI!
sudo update-ca-certificates --fresh --verbose

No olvides verificar /etc/default/cacertspor:

# enable/disable updates of the keystore /etc/ssl/certs/java/cacerts
cacerts_updates=yes

Para eliminar cert:

sudo rm /usr/share/ca-certificates/test/test.loc.crt
sudo rm /etc/ssl/certs/java/cacerts
sudo update-ca-certificates --fresh --verbose
gavenkoa
fuente
2

Esto también puede deberse al uso de certificados GoDaddy con Java 7 que están firmados con SHA2.

Chrome y todos los demás navegadores están comenzando a desaprobar los certificados SSL firmados con SHA1, ya que no es tan seguro.

Puede encontrar más información sobre el problema aquí , así como sobre cómo resolverlo en su servidor si lo necesita ahora.

Brad Parks
fuente
2

Tuve el mismo problema con el error de certificados y fue debido a SNI, y el cliente http que usé no tenía SNI implementado. Entonces, una actualización de versión hizo el trabajo

   <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>
Radu Toader
fuente
2

ACTUALIZACIÓN: Que un reinicio ayudó fue una coincidencia (¡eso esperaba, hooray!). La verdadera causa del problema fue esta: cuando se le indica a Gradle que use un almacén de claves específico, ese almacén de claves también debe contener todos los certificados raíz oficiales. De lo contrario, no puede acceder a bibliotecas desde repositorios regulares. Lo que tuve que hacer fue esto:

Importe el certificado autofirmado:

keytool -import -trustcacerts -alias myselfsignedcert -file /Users/me/Desktop/selfsignedcert.crt -keystore ./privateKeystore.jks

Agregue los certificados raíz oficiales:

keytool -importkeystore -srckeystore <java-home>/lib/security/cacerts -destkeystore ./privateKeystore.jks

Tal vez el demonio Gradle también se interpuso en el camino. Podría valer la pena matar a todos los demonios en ejecución encontrados con./gradlew --status si las cosas comienzan a verse sombrías.

PUBLICACIÓN ORIGINAL:

Nadie lo creerá, lo sé. Aún así, si todo lo demás falla, pruébalo: después de reiniciar mi Mac, el problema desapareció. Grrr.

Antecedentes: ./gradlew jar me seguía dando "no se puede encontrar la ruta de certificación válida para el objetivo solicitado"

Estoy atascado con un certificado autofirmado, guardado desde el navegador, importado en privateKeystore.jks. Luego le indicó a Gradle que trabajara con privateKeystore.jks:

org.gradle.jvmargs=-Djavax.net.debug=SSL -Djavax.net.ssl.trustStore="/Users/me/IntelliJ/myproject/privateKeystore.jks"  -Djavax.net.ssl.trustStorePassword=changeit

Como se mencionó, esto solo funcionó después de un reinicio.

StaticNoiseLog
fuente
2

La versión 18.1.3044 de AVG (con Windows 10) interfiere con mi aplicación Spring local.

Solución: ingrese en la sección AVG llamada "Web y correo electrónico" y desactive la "protección de correo electrónico". AVG bloquea el certificado si el sitio no es seguro.

Insoft
fuente
2

Asegúrese de que https://176.66.3.69:6443/ tenga un certificado válido. Puede verificarlo a través del navegador en primer lugar, https no es segurosi funciona en el navegador, funcionará en Java.

eso me funciona

Amr Ibrahim
fuente
¿Y qué debo hacer si el navegador también se queja?
El padrino
intente instalar el certificado
Amr Ibrahim
2

Hay muchas maneras de resolver esto ...

Una forma es establecer los certificados de TrustStore en un archivo de almacén de claves y colocarlo en la ruta de la aplicación, y establecer estas propiedades del sistema en el método principal:

public static void main(String[] args) {
  System.setProperty("javax.net.ssl.trustStore", "trust-store.jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "TrustStore");
  ...
}

Otra forma es colocar el almacén de claves como archivo de recursos dentro del archivo jar del proyecto y cargarlo:

public static SSLContext createSSLContext(String resourcePath, String pass) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException, KeyManagementException {
  // initialise the keystore
  final char[] password = pass.toCharArray();
  KeyStore ks = KeyStore.getInstance("JKS");
  ks.load(ThisClass.class.getResourceAsStream(resourcePath
  ), password);

  // Setup the key manager factory.
  KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
  kmf.init(ks, password);

  // Setup the trust manager factory.
  TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
  tmf.init(ks);

  SSLContext sslc = SSLContext.getInstance("TLS");
  sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
  return sslc;
}

public static void main(String[] args) {
  SSLContext.setDefault(
    createSSLContext("/trust-store.jks", "TrustStore"));
  ...
}

En Windows también puede probar esta solución: https://stackoverflow.com/a/59056537/980442


Creé el archivo de almacén de claves a partir de un .crtarchivo CA de autoridad de certificación de esta manera:

keytool -import -alias ca -keystore trust-store.jks -storepass TrustStore -trustcacerts -file ca.crt

FYI: https://docs.oracle.com/javadb/10.8.3.0/adminguide/cadminsslclient.html

Daniel De León
fuente
1

Tiene dos opciones: importe el certificado autofirmado en el almacén de claves de Java para cada jvm en el que se ejecutará el software o pruebe la fábrica SSL no validante:

jdbc:postgresql://myserver.com:5432/mydatabasename?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory
Pradip Das
fuente
1

Tenía el problema como esta imagen.

ingrese la descripción de la imagen aquí

Intenté algunas soluciones. Pero descubrí que incluso si es el mismo proyecto, cuando está en el lugar de trabajo de otro, está totalmente bien. No se necesitan configuraciones adicionales. Así que supusimos que es un problema ambiental. Intentamos cambiar la versión JDK, IDE pero no funcionó. La investigación tardó aproximadamente 4 horas, hasta que probamos la respuesta mejor calificada. No encontré el error mencionado en esa respuesta, pero encontré a través de mi navegador sobre HTTP URL (bloqueo) que había una certificación de Charles. Entonces me di cuenta de que Charles estaba encendido todo el tiempo. Mientras lo apague, todo funciona bien.

Así que dejé mi experiencia que podría ser útil para su caso.

Lalaphoon
fuente
0

En mi caso, estoy ejecutando MacOs High Sierra con Java 1.6. El archivo cacert está en una ubicación diferente a la mencionada anteriormente en la respuesta de Gabe Martin-Dempesy. El archivo cacert también ya estaba vinculado a otra ubicación (/ Library / Internet Plug-Ins / JavaAppletPlugin.plugin / Contents / Home / lib / security / cacerts).

Usando FireFox, exporté el certificado del sitio web en cuestión a un archivo local llamado "exportedCertFile.crt". A partir de ahí, utilicé keytool para mover el certificado al archivo cacert. Esto solucionó el problema.

bash-3.2# cd /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/security/
bash-3.2# keytool -importcert -file ~/exportedCertFile.crt -alias example -keystore cacerts -storepass changeit
Alan Curtis
fuente
0

Primero descargue el certificado SSL, luego puede ir a su ruta java bin y ejecutar el siguiente comando en la consola.

C:\java\JDK1.8.0_66-X64\bin>keytool -printcert -file C:\Users\lova\openapi.cer -keystore openapistore
Lova Chittumuri
fuente
-1

En mi caso, tenía el almacén de claves y el almacén de confianza con el mismo certificado, por lo que fue útil eliminar el almacén de confianza. A veces, la cadena de certificados puede ser un problema si tiene varias copias de certificados.

Codificador inteligente
fuente