Java: sun.security.provider.certpath.SunCertPathBuilderException: impossibile trovare un percorso di certificazione valido per la destinazione richiesta


249

Ho una classe che scaricherà un file da un server HTTPS . Quando lo eseguo, restituisce molti errori. Sembra che ho un problema con il mio certificato. È possibile ignorare l'autenticazione client-server? Se é cosi, come?

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

    }
}

Errori:

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

2
Una volta ho riscontrato questo errore e ho contattato il nostro team di sicurezza, e si è scoperto che dovevo riparare il JAR che stavamo usando, poiché il nostro team stava usando uno obsoleto fornito dalla società. Solo una FYI per chiunque si trovi in ​​una situazione simile.
kayleeFrye_onDeck,

Risposte:


215

Il problema appare quando il tuo server ha un certificato autofirmato. Per ovviare a questo problema, è possibile aggiungere questo certificato all'elenco dei certificati attendibili della propria JVM.

In questo articolo l' autore descrive come recuperare il certificato dal tuo browser e aggiungerlo al file cacerts della tua JVM. È possibile modificare il JAVA_HOME/jre/lib/security/cacertsfile o eseguire l'applicazione con il -Djavax.net.ssl.trustStoreparametro. Verifica quale JDK / JRE stai utilizzando anche perché spesso è fonte di confusione.

Guarda anche: Come vengono risolti i nomi dei server certificati SSL / Posso aggiungere nomi alternativi usando keytool? Se si verifica java.security.cert.CertificateException: No name matching localhost foundun'eccezione.


3
questo non ha funzionato per me. Ho installato il root e il cert della catena, ma Tomcat-7 riporta comunque validatorException causata da "impossibile trovare un percorso di certificazione valido per la destinazione richiesta" in qualche modo per eseguire il debug?
Cheruvim,

Il problema si presenta anche con un certificato firmato da qualcun altro che non è attendibile.
Marchese di Lorne,

Grande! Funziona! Non dimenticare che potresti avere sia jre che jdk, ed entrambi cacertsdevono essere aggiornati
Dima Fomin,

Nel mio caso, la CA principale era lì ma non la CA successiva inattivo. L'aggiunta della CA successiva ha fatto il trucco - grazie.
java-addict301,

1
Nel mio caso, sto usando Netbeans + Apache Tomcat (integrato), quindi, aggiungendo .cer al truststore "cacerts" su Jdk / jre (C: \ Programmi \ Java \ jdk1.8.0_152 \ jre \ lib \ sicurezza) e Jre (C: \ Programmi \ Java \ jre1.8.0_91 \ lib \ security) funziona per me
Jnn

149

Ecco cosa funziona in modo affidabile per me su macOS. Assicurati di sostituire example.com e 443 con il nome host e la porta a cui stai tentando di connetterti e dai un alias personalizzato. Il primo comando scarica il certificato fornito dal server remoto e lo salva localmente nel formato x509. Il secondo comando carica il certificato salvato nel truststore SSL di 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

3
Funziona per me perché? Devi fornire una spiegazione.
Marchese di Lorne,

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2> / dev / null) -out ~ / example.crt - che cos'è example.crt nel comando ho un certificato .pem che devo dare che qui ??
Vishnu Ranganathan,

3
.crt e .pem sono estensioni di file comunemente utilizzate per lo stesso formato di file. Se hai già il file, esegui il secondo comando e passalo nell'argomento -file.
Gabe Martin-Dempesy,

1
Roba fantastica. L'unica cosa è: ho dovuto usare l'ultimo openssl 1.0.Xx per qualche motivo, il vecchio 9.X.Xx non funzionava.
zbstof,

1
Questo non funziona con l'endpoint SNI. In tal caso è necessario aggiungere: -servername example.com quando si recupera il certificato
Patrik Beck,

46

Ho avuto lo stesso problema con un certificato jolly firmato valido da Symantec.

Per prima cosa prova a eseguire l'applicazione java con -Djavax.net.debug = SSL per vedere cosa sta realmente succedendo.

Ho finito per importare il certificato intermedio che stava causando la rottura della catena di certificati.

Ho scaricato il certificato intermedio mancante da Symantec ( nel mio caso puoi vedere il link per scaricare il certificato mancante nel registro dell'handshake ssl: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer nel mio caso).

E ho importato il certificato nel keystore java. Dopo aver importato il certificato intermedio il mio jolly ssl cert ha finalmente iniziato a funzionare:

keytool -import -keystore ../jre/lib/security/cacerts -trustcacerts -alias "VeriSign Class 3 International Server CA - G3" -file /pathto/SVRIntlG3.cer

Questo era il caso:
Kisna,

2
Per evitare confusione, eseguire java (o jcurl) con i parametri di debug per vedere la "catena di certificati" remota nei registri, quindi grep la "CN" in truststore passata esplicitamente (anziché predefinita) come segue, se non presente, è necessario aggiungere. ssllabs.com/ssltest/analyze.html mostrerà se i certificati lato server hanno una catena incompleta e include certificati di percorso di certificazione intermedi che devono essere aggiunti. -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,


Ho avuto lo stesso problema, questo è molto utile, ma nel mio caso hai dovuto solo aggiungere il certificato del server al file cacerts della versione JDK
Pigritia,

Tieni presente che esiste un altro strumento chiamato portecle che può aprire il file cacert (archivio certificati) e importare facilmente il certificato. Ricorda solo di salvare il file cacert in seguito.
will824

41
  1. Esporta il certificato SSL utilizzando Firefox. Puoi esportarlo colpendo l'URL nel browser e quindi selezionare l'opzione per esportare il certificato. Supponiamo che il nome del file cert sia tuo.ssl.server.name.crt
  2. Vai al tuo JRE_HOME/binoJDK/JRE/bin
  3. Digita il 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. Riavvia il processo Java

13
Se viene richiesta una password, utilizzare la password del keystore cacerts predefinita changeit( stackoverflow.com/a/22782035/1304830 ). Assicurati anche di eseguire cmd come amministratore.
Fr4nz,

22

La risposta di @Gabe Martin-Dempesy mi è stata di aiuto. E ho scritto una piccola sceneggiatura ad esso correlata. L'utilizzo è molto semplice.

Installa un certificato dall'host:

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

Rimuovere il certificato già installato.

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

Funziona perfettamente. Ottimo lavoro! . Funziona così: avvia il tuo servizio SSL (se non è in esecuzione) ed esegui il comando come spiegato (ad es ./java-cert-importer.sh example.com 1234.). Questo è tutto.
lepe,

1
Funziona alla grande. Stavo ottenendo l'errore su un server Jenkins che si connetteva a un'API esterna che cambia il suo certificato e non riesce a compilare i miei built. Questo risolve il mio problema
user9869932

Oracle avrebbe dovuto fornire qualcosa di simile in primo luogo o non aver mai creato la propria orribile soluzione SSL. La gestione dei certificati SSL dovrebbe essere un lavoro del sistema operativo.
Wolfgang Fahl

17

Citando da Non più "impossibile trovare un percorso di certificazione valido per la destinazione richiesta"

quando si tenta di aprire una connessione SSL a un host utilizzando JSSE. In genere ciò significa che il server sta utilizzando un certificato di prova (possibilmente generato utilizzando keytool) anziché un certificato di un'autorità di certificazione commerciale nota come Verisign o GoDaddy. In questo caso, i browser Web visualizzano finestre di avviso, ma poiché JSSE non può presumere che sia presente un utente interattivo, per impostazione predefinita genera un'eccezione.

La convalida del certificato è una parte molto importante della sicurezza SSL, ma non sto scrivendo questa voce per spiegare i dettagli. Se sei interessato, puoi iniziare leggendo il blurb di Wikipedia. Sto scrivendo questa voce per mostrare un modo semplice per parlare con quell'host con il certificato di prova, se proprio lo desideri.

Fondamentalmente, si desidera aggiungere il certificato del server al KeyStore con i certificati attendibili

Prova il codice fornito lì. Potrebbe aiutare


5
La parte relativa alla "convalida del certificato è una parte molto importante della sicurezza SSL" non è necessariamente vera. SSL ti dà due garanzie: (1) che la tua comunicazione è privata e (2) che stai parlando con un server che è noto alla NSA. (:-) A volte ti interessa solo la privacy della conversazione, e poi un la certificazione autofirmata va bene. Vedi social-biz.org/2011/10/16/the-anti-ssl-conspiracy
AgilePro

@AgilePro SSL ti offre quattro garanzie: autenticazione, privacy, integrità e possibilità di autorizzazione. Non ti dà alcuna garanzia che stai parlando con un server noto all'NSA. Preoccuparsi solo della privacy senza autenticazione è una contraddizione in termini.
Marchese di Lorne,

@EJP Accetto che se si utilizza un certificato client è possibile ottenere l'autenticazione e suppongo che sia possibile l'autorizzazione ... ma la maggior parte degli usi non sono con un certificato client. Come definiresti la differenza tra un certificato "autofirmato" e un certificato di un'autorità firmataria? L'autorità di firma dà "integrità". La mia battuta sull'NSA è che tutte le autorità firmatarie non possono garantire positivamente l'indipendenza da tutto. Non è così paranoico, ma il punto è che il tuo certificato è SOLO segreto quanto l'autorità di firma può farlo. Autofirmato può essere più segreto.
AgilePro,

@AgilePro L'utilizzo di un certificato server autentica il server ed è necessario per rendere SSL sicuro, come indicato nella RFC 2246. I certificati non sono affatto segreti: pertanto il resto del tuo commento non ha senso.
Marchese di Lorne,

6

Questo ha risolto il mio problema,

Dobbiamo importare il certificato sul java locale. Altrimenti potremmo ottenere l'eccezione di seguito.

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: creazione del percorso PKIX non riuscita: sun.security.provider.certpath.SunCertPathBuilderException: impossibile trovare un percorso di certificazione valido per la destinazione richiesta
        at sun.security.ssl.Alerts.getSSLException (Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal (SSLSocketImpl.java:1949)
        at sun.security.ssl.Handshaker.fatalSE (Handshaker.java:302)

SSLPOKE è uno strumento in cui è possibile testare la connettività https dal proprio computer locale.

Comando per testare la connettività:

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
    sun.security.validator.ValidatorException: creazione del percorso PKIX non riuscita: 
    sun.security.provider.certpath.SunCertPathBuilderException: impossibile trovare un percorso di certificazione valido per la destinazione richiesta
        at sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:387)
        at sun.security.validator.PKIXValidator.engineValidate (PKIXValidator.java:292)
        at sun.security.validator.Validator.validate (Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate (X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted (X509TrustManagerImpl.java:229)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted (X509TrustManagerImpl.java:124)
        at sun.security.ssl.ClientHandshaker.serverCertificate (ClientHandshaker.java:1496)
        at sun.security.ssl.ClientHandshaker.processMessage (ClientHandshaker.java:216)
        at sun.security.ssl.Handshaker.processLoop (Handshaker.java:1026)
        at sun.security.ssl.Handshaker.process_record (Handshaker.java:961)
        at sun.security.ssl.SSLSocketImpl.readRecord (SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake (SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.writeRecord (SSLSocketImpl.java:747)
        at sun.security.ssl.AppOutputStream.write (AppOutputStream.java:123)
        at sun.security.ssl.AppOutputStream.write (AppOutputStream.java:138)
        su SSLPoke.main (SSLPoke.java:31)
    Causato da: sun.security.provider.certpath.SunCertPathBuilderException: impossibile trovare un percorso di certificazione valido per 
    target richiesto
        at sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild (SunCertPathBuilder.java:126)
        at java.security.cert.CertPathBuilder.build (CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:382)
        ... altri 15
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

questo richiederebbe prima di tutto "Immettere la password del keystore:" changeitè la password predefinita. e infine un prompt "Trust this certificate? [no]:", fornire "yes" per aggiungere il certificato al keystore.

Verfication:

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

5

Sono stato in grado di farlo funzionare solo con il codice, cioè non è necessario utilizzare 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;
        }
    }
}

1
A proposito, sto usando httpasyncclient: 4.0.1
Jonas Bergström

Avevo bisogno di qualcosa di simile, @ JonasBergström, la tua soluzione con SSLContext aiuta molto.
EnterB

8
Si noti che questa soluzione non è sicura.
Marchese di Lorne,

Grazie Jonas, la tua soluzione ha risolto il problema. Ma ho scoperto che la creazione della prima connessione richiede molto tempo (3-5 secondi), dopodiché ogni connessione richiede solo 300-400 ms.
twcai,

5

La fonte di questo errore sulla mia istanza di Apache 2.4 (usando un certificato jolly Comodo) era un percorso incompleto al certificato radice firmato SHA-1. C'erano più catene nel certificato emesso e nella catena che portava a un certificato radice SHA-1 mancava un certificato intermedio . I browser moderni sanno come gestirlo, ma Java 7 non lo gestisce per impostazione predefinita (anche se ci sono alcuni modi contorti per farlo nel codice). Il risultato sono messaggi di errore che sembrano identici al caso dei certificati autofirmati:

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

In questo caso, viene generato il messaggio "Impossibile trovare il percorso di certificazione valido per la destinazione richiesta" a causa del certificato intermedio mancante. È possibile verificare quale certificato manca tramite il test SSL Labs sul server. Una volta trovato il certificato appropriato, scaricalo e (se il server è sotto il tuo controllo) aggiungilo al pacchetto di certificati. In alternativa, è possibile importare localmente il certificato mancante. Accogliere questo problema sul server è una soluzione più generale al problema.


ssllabs.com/ssltest è un salvatore, basta confrontarlo con una convalida del certificato funzionante.
Kisna,

5

Solo per Windows, attenersi alla seguente procedura:

  1. In Chrome vai alle impostazioni.
  2. In Impostazioni fai clic su Mostra impostazioni avanzate.
  3. In HTTPS / SSL, fai clic su Gestisci certificati.
  4. Esporta il tuo certificato.
  5. Nelle ricerche di Windows (premendo il tasto Windows sulla tastiera) digitare java.
  6. Selezionare l'opzione (Configura Java) che aprirà il Pannello di controllo Java
  7. Seleziona la scheda Sicurezza nel Pannello di controllo Java
  8. Seleziona Gestisci certificati
  9. Fai clic su Importa
  10. Nella scheda (Utente) selezionata e tipo di certificato come (Certificati attendibili)
  11. Fai clic sul pulsante Importa e cerca il certificato scaricato e importalo.

4

Per chi ama Debian e Java preconfezionato:

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

Non dimenticare di verificare /etc/default/cacerts:

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

Per rimuovere il certificato:

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

2

Ciò può anche essere causato dall'utilizzo dei certificati GoDaddy con Java 7 firmati mediante SHA2.

Chrome e tutti gli altri browser stanno iniziando a deprecare certificati SSL firmati utilizzando SHA1, poiché non è così sicuro.

Maggiori informazioni sul problema sono disponibili qui , oltre a come risolverlo sul server, se necessario.


2

Ho avuto lo stesso problema con l'errore dei certificati ed era a causa di SNI, e il client http che ho usato non aveva implementato SNI. Quindi un aggiornamento di versione ha fatto il lavoro

   <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.3.6</version>
    </dependency>

2

AGGIORNAMENTO: Che un riavvio ha aiutato era una coincidenza (lo speravo, evviva!). La vera causa del problema era questa: quando Gradle è diretto a utilizzare un archivio chiavi specifico, tale archivio chiavi deve contenere anche tutti i certificati radice ufficiali. Altrimenti non può accedere alle librerie dai repository regolari. Quello che dovevo fare era questo:

Importa il certificato autofirmato:

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

Aggiungi i certificati di root ufficiali:

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

Forse anche il demone Gradle si è messo in mezzo. Potrebbe valere la pena uccidere tutti i daemon in esecuzione trovati ./gradlew --statusse le cose iniziano a sembrare desolate.

SPEDIZIONE ORIGINALE:

Nessuno ci crederà, lo so. Tuttavia, se tutto il resto fallisce, provalo: dopo un riavvio del mio Mac il problema era sparito. Grrr.

Background: ./gradlew jar continuava a darmi "impossibile trovare un percorso di certificazione valido per l'obiettivo richiesto"

Sono bloccato con un certificato autofirmato, salvato dal browser, importato in privateKeystore.jks. Quindi ha incaricato Gradle di lavorare 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

Come accennato, questo ha funzionato solo dopo un riavvio.


2

La versione 18.1.3044 di AVG (con Windows 10) interferisce con l'applicazione Spring locale.

Soluzione: accedere alla sezione AVG denominata "Web ed e-mail" e disabilitare la "protezione e-mail". AVG blocca il certificato se il sito non è sicuro.



2

C'è un sacco di modo per risolvere questo ...

Un modo è impostare i certificati TrustStore in un file keystore e inserirlo nel percorso dell'applicazione e impostare queste proprietà di sistema nel metodo principale:

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

L'altro modo è posizionare il keystore come file di risorse all'interno del file jar del progetto e caricarlo:

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

In Windows puoi provare anche questa soluzione: https://stackoverflow.com/a/59056537/980442


Ho creato il file keystore da un .crtfile CA dell'autorità di certificazione in questo modo:

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

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


1

Hai due opzioni, importa il certificato autofirmato nel keystore di Java per ogni jvm su cui verrà eseguito il software o prova la factory ssl non validante:

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

1

Aveva il problema come questa immagine.

inserisci qui la descrizione dell'immagine

Ho provato alcune soluzioni. Ma ho scoperto che anche se è lo stesso progetto, quando si trova sul posto di lavoro di un altro, va benissimo. Non sono necessarie impostazioni aggiuntive. Quindi abbiamo indovinato che si tratta di un problema ambientale. Abbiamo provato a cambiare la versione JDK, IDE ma non ha funzionato. ci sono volute circa 4 ore per le indagini, fino a quando non abbiamo provato la risposta più votata. Non ho trovato l'errore menzionato in quella risposta, ma ho trovato tramite il mio browser su HTTP URL (blocco) che c'era una certificazione di Charles. Poi ho capito che il mio charles era sempre acceso. Finché l'ho spento, funziona tutto bene.

Quindi ho lasciato la mia esperienza che potrebbe essere utile per il tuo caso.


0

Nel mio caso sto eseguendo MacOs High Sierra con Java 1.6. Il file cacert si trova in una posizione diversa rispetto a quella sopra menzionata nella risposta di Gabe Martin-Dempesy. Il file cacert era già collegato a un'altra posizione (/ Libreria / Plug-in Internet / JavaAppletPlugin.plugin / Contenuti / Home / lib / security / cacerts).

Utilizzando FireFox, ho esportato il certificato dal sito Web in questione in un file locale chiamato "exportedCertFile.crt". Da lì, ho usato keytool per spostare il certificato nel file cacert. Ciò ha risolto il 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

0

prima scarica il certificato ssl quindi puoi andare sul tuo percorso java bin esegui il comando qui sotto nella console.

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

-1

Nel mio caso avevo sia keystore che truststore con lo stesso certificato, quindi la rimozione di truststore mi ha aiutato. A volte la catena di certificati può essere un problema se hai più copie di certificati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.