Impossibile trovare un percorso di certificazione valido per la destinazione richiesta - errore anche dopo l'importazione del certificato


206

Ho un client Java che tenta di accedere a un server con un certificato autofirmato.

Quando provo a pubblicare sul server, ottengo il seguente errore:

impossibile trovare un percorso di certificazione valido per la destinazione richiesta

Dopo aver fatto alcune ricerche sull'argomento, ho fatto quanto segue.

  1. Ho salvato il nome del mio server come root.cerfile.
  2. Nel JRE del mio server Glassfish, ho eseguito questo:
    keytool -import -alias example -keystore cacerts -file root.cer
  3. Per verificare che il certificato sia stato aggiunto correttamente al mio cacert, ho fatto questo:
    keytool -list -v -keystore cacerts
    vedo che il certificato è presente.
  4. Ho quindi riavviato Glassfish e ho ritirato il "post".

Ricevo ancora lo stesso errore.

Ho la sensazione che ciò sia dovuto al fatto che il mio Glassfish in realtà non sta leggendo il file cacert che ho modificato, ma forse un altro.

Qualcuno di voi ha avuto questo problema e può spingermi nella giusta direzione?


1
Giusto per chiarire "Ho un client Java che tenta di accedere a un server con un certificato autofirmato": stai parlando di usare certificati client autofirmati, vero? Esiste una configurazione specifica per le impostazioni del connettore su Glassfish (impostazioni dell'archivio sicuro, in particolare)?
Bruno,

"Ho un client Java che tenta di accedere a un server con un certificato autofirmato.": Stai parlando di utilizzare certificati client autofirmati, vero? - sì.
TheCoder

1
Ho trovato 2 impostazioni in Glassfish JVM: -Djavax.net.ssl.keyStore = $ {com.sun.aas.instanceRoot} /config/keystore.jks e -Djavax.net.ssl.trustStore = $ {com.sun. aas.instanceRoot} /config/cacerts.jks. Ora devo aggiungere cert a uno di quelli. Puoi confermare che è il keystore a cui lo aggiungo?
TheCoder

4
Sul server, il keystore è per il server cert e la sua chiave privata (keystore è per ciò che "appartiene" alla parte locale). Il truststore è per i certificati utilizzati per verificare la fiducia nella parte remota. È necessario aggiungere il certificato client al truststore del server. (Vedi anche questo , anche se Glassfish non sembra utilizzare la posizione predefinita di JRE.)
Bruno,

Bruno ha funzionato. L'ho aggiunto al mio truststore Glassfish. Molte grazie per il tuo aiuto. Anche tu Dirk.
TheCoder

Risposte:


155

Sfortunatamente - potrebbero essere molte cose - e molti server di app e altri "wrapper" Java sono inclini a giocare con le proprietà e il loro "proprio" portachiavi e cosa no. Quindi potrebbe guardare qualcosa di completamente diverso.

A corto di truss-ing - proverei:

java -Djavax.net.debug=all -Djavax.net.ssl.trustStore=trustStore ...

per vedere se questo aiuta. Invece di "tutto", puoi anche impostarlo su "ssl", gestore delle chiavi e gestore fiduciario, il che può essere d'aiuto nel tuo caso. Impostandolo su "aiuto" elencherà qualcosa come di seguito sulla maggior parte delle piattaforme.

Indipendentemente da ciò - assicurati di comprendere appieno la differenza tra il keystore (in cui hai la chiave privata e il certificato con cui provi la tua identità) e l'archivio di fiducia (che determina di chi ti fidi) - e il fatto che anche la tua identità ha una "catena" di fiducia nella radice - che è separata da qualsiasi catena a una radice che devi capire "di chi" ti fidi.

all            turn on all debugging
ssl            turn on ssl debugging

The   following can be used with ssl:
    record       enable per-record tracing
    handshake    print each handshake message
    keygen       print key generation data
    session      print session activity
    defaultctx   print default SSL initialization
    sslctx       print SSLContext tracing
    sessioncache print session cache tracing
    keymanager   print key manager tracing
    trustmanager print trust manager tracing
    pluggability print pluggability tracing

    handshake debugging can be widened with:
    data         hex dump of each handshake message
    verbose      verbose handshake message printing

    record debugging can be widened with:
    plaintext    hex dump of record plaintext
    packet       print raw SSL/TLS packets

Fonte: # Vedi http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#Debug


6
Molte grazie! -Djavax.net.ssl.trustStore = / location_of / trustStore ha risolto il mio problema e anche le informazioni di debug sono state davvero utili.
RHE,

5
java -Djavax.net.debug = all -Djavax.net.ssl.trustStore = trustStore ... restituisce l'errore seguente: Errore: Impossibile trovare o caricare la classe principale ...
rohith

1
Ovviamente potresti anche dover specificare la password del truststore con -Djavax.net.ssl.trustStorePassword = changeit
user1754036

18

Ecco la soluzione, segui il seguente link Step by Step:

http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/

JAVA FILE: che manca nel blog

/*
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */



import java.io.*;
import java.net.URL;

import java.security.*;
import java.security.cert.*;

import javax.net.ssl.*;

public class InstallCert {

    public static void main(String[] args) throws Exception {
    String host;
    int port;
    char[] passphrase;
    if ((args.length == 1) || (args.length == 2)) {
        String[] c = args[0].split(":");
        host = c[0];
        port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
        String p = (args.length == 1) ? "changeit" : args[1];
        passphrase = p.toCharArray();
    } else {
        System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");
        return;
    }

    File file = new File("jssecacerts");
    if (file.isFile() == false) {
        char SEP = File.separatorChar;
        File dir = new File(System.getProperty("java.home") + SEP
            + "lib" + SEP + "security");
        file = new File(dir, "jssecacerts");
        if (file.isFile() == false) {
        file = new File(dir, "cacerts");
        }
    }
    System.out.println("Loading KeyStore " + file + "...");
    InputStream in = new FileInputStream(file);
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(in, passphrase);
    in.close();

    SSLContext context = SSLContext.getInstance("TLS");
    TrustManagerFactory tmf =
        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(ks);
    X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0];
    SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
    context.init(null, new TrustManager[] {tm}, null);
    SSLSocketFactory factory = context.getSocketFactory();

    System.out.println("Opening connection to " + host + ":" + port + "...");
    SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
    socket.setSoTimeout(10000);
    try {
        System.out.println("Starting SSL handshake...");
        socket.startHandshake();
        socket.close();
        System.out.println();
        System.out.println("No errors, certificate is already trusted");
    } catch (SSLException e) {
        System.out.println();
        e.printStackTrace(System.out);
    }

    X509Certificate[] chain = tm.chain;
    if (chain == null) {
        System.out.println("Could not obtain server certificate chain");
        return;
    }

    BufferedReader reader =
        new BufferedReader(new InputStreamReader(System.in));

    System.out.println();
    System.out.println("Server sent " + chain.length + " certificate(s):");
    System.out.println();
    MessageDigest sha1 = MessageDigest.getInstance("SHA1");
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    for (int i = 0; i < chain.length; i++) {
        X509Certificate cert = chain[i];
        System.out.println
            (" " + (i + 1) + " Subject " + cert.getSubjectDN());
        System.out.println("   Issuer  " + cert.getIssuerDN());
        sha1.update(cert.getEncoded());
        System.out.println("   sha1    " + toHexString(sha1.digest()));
        md5.update(cert.getEncoded());
        System.out.println("   md5     " + toHexString(md5.digest()));
        System.out.println();
    }

    System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
    String line = reader.readLine().trim();
    int k;
    try {
        k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
    } catch (NumberFormatException e) {
        System.out.println("KeyStore not changed");
        return;
    }

    X509Certificate cert = chain[k];
    String alias = host + "-" + (k + 1);
    ks.setCertificateEntry(alias, cert);

    OutputStream out = new FileOutputStream("jssecacerts");
    ks.store(out, passphrase);
    out.close();

    System.out.println();
    System.out.println(cert);
    System.out.println();
    System.out.println
        ("Added certificate to keystore 'jssecacerts' using alias '"
        + alias + "'");
    }

    private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();

    private static String toHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder(bytes.length * 3);
        for (int b : bytes) {
            b &= 0xff;
            sb.append(HEXDIGITS[b >> 4]);
            sb.append(HEXDIGITS[b & 15]);
            sb.append(' ');
        }
        return sb.toString();
    }

    private static class SavingTrustManager implements X509TrustManager {

    private final X509TrustManager tm;
    private X509Certificate[] chain;

    SavingTrustManager(X509TrustManager tm) {
        this.tm = tm;
    }

    public X509Certificate[] getAcceptedIssuers() {
        throw new UnsupportedOperationException();
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType)
        throws CertificateException {
        throw new UnsupportedOperationException();
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException {
        this.chain = chain;
        tm.checkServerTrusted(chain, authType);
    }
    }

}

3
Questa soluzione ha funzionato per me, ma ha bisogno di un piccolo cambiamento nella classe privata SavingTrustManager:public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0];}
Richard

1
@ Richard, @ Paul, @ user6258309 Ho ricevuto l'errore Eccezione nel thread "main" java.net.SocketTimeoutException: Lettura scaduta su java.net.SocketInputStream.socketRead0 (Metodo nativo) su java.net.SocketInputStream.socketRead (fonte sconosciuta ) Come posso risolvere questo problema
Renjith Krishnan,

5
Questo "così; lution" è radicalmente insicuro. Non usare.
Marchese di Lorne,

9
Questa risposta è principalmente codice. Non spiega perché o perché non funziona.

13

È necessario configurare le proprietà del sistema JSSE, in particolare l'archivio certificati client.

Tramite riga di comando:

java -Djavax.net.ssl.trustStore=truststores/client.ts com.progress.Client

o tramite codice Java:

import java.util.Properties;
    ...
    Properties systemProps = System.getProperties();
    systemProps.put("javax.net.ssl.keyStorePassword","passwordForKeystore");
    systemProps.put("javax.net.ssl.keyStore","pathToKeystore.ks");
    systemProps.put("javax.net.ssl.trustStore", "pathToTruststore.ts");
    systemProps.put("javax.net.ssl.trustStorePassword","passwordForTrustStore");
    System.setProperties(systemProps);
    ...

Per ulteriori informazioni, consultare i dettagli sul sito RedHat .


Ha avuto lo stesso problema con Spring Boot, i microservizi Spring Cloud e un certificato SSL autofirmato. Sono stato in grado di impostare keyStore e keyStorePassword in application.properties e farlo funzionare immediatamente, ma non sono riuscito a fare lo stesso con trustStore e trustStorePassword. Questa risposta ha funzionato per me per il negozio di fiducia.
Mate Šimović,

7

(ripubblicare dall'altra mia risposta )
Utilizzare lo strumento di controllo dell'utilità cli dalla distribuzione del software Java per importare (e fidarsi! ) dei certificati necessari

Campione:

  1. Da cli cambia dir a jre \ bin

  2. Controlla keystore (file trovato nella directory jre \ bin)
    keytool -list -keystore .. \ lib \ security \ cacerts La
    password è changeit

  3. Scarica e salva tutti i certificati in catena dal server necessario.

  4. Aggiungi certificati (prima di rimuovere l'attributo "sola lettura" sul file ".. \ lib \ security \ cacerts"), esegui: keytool -alias REPLACE_TO_ANY_UNIQ_NAME -import -keystore .. \ lib \ security \ cacerts -file "r: \ root.crt"

per caso ho trovato un suggerimento così semplice. Altre soluzioni richiedono l'uso di InstallCert.Java e JDK

fonte: http://www.java-samples.com/showtutorial.php?tutorialid=210


6

Ho avuto lo stesso problema con sbt .
Ha tentato di recuperare le dipendenze da repo1.maven.org su ssl
ma ha affermato che "non è stato in grado di trovare un percorso di certificazione valido per l'URL di destinazione richiesto".
quindi ho seguito questo post e ancora non sono riuscito a verificare una connessione.
Quindi l'ho letto e ho scoperto che il certificato di root non è sufficiente, come suggerito dalla posta, quindi -
la cosa che ha funzionato per me è stato importare i certificati CA intermedi nel keystore .
In realtà ho aggiunto tutti i certificati della catena e ha funzionato come un fascino.


4

Soluzione durante la migrazione da JDK 8 a JDK 10

JDK 10

root@c339504909345:/opt/jdk-minimal/jre/lib/security #  keytool -cacerts -list
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 80 entries

JDK 8

root@c39596768075:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts #  keytool -cacerts -list
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 151 entries

I passaggi per risolvere

  • Ho eliminato il certificato JDK 10 e l'ho sostituito con il JDK 8
  • Dal momento che sto creando Docker Images, potrei farlo rapidamente usando build multi-stage
    • Sto costruendo un JRE minimale usando jlinkas/opt/jdk/bin/jlink \ --module-path /opt/jdk/jmods...

Quindi, ecco i diversi percorsi e la sequenza dei comandi ...

# Java 8
COPY --from=marcellodesales-springboot-builder-jdk8 /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts /etc/ssl/certs/java/cacerts

# Java 10
RUN rm -f /opt/jdk-minimal/jre/lib/security/cacerts
RUN ln -s /etc/ssl/certs/java/cacerts /opt/jdk-minimal/jre/lib/security/cacerts

2

Sto lavorando a un tutorial per i servizi Web REST su www.udemy.com (REST Java Web Services). L'esempio nel tutorial ha detto che per avere SSL, dobbiamo avere una cartella chiamata "trust_store" nel mio progetto "client" di eclissi che dovrebbe contenere un file "key store" (avevamo un progetto "client" per chiamare il servizio e progetto "service" che conteneva il servizio web REST - 2 progetti nella stessa area di lavoro eclipse, uno il client, l'altro il servizio). Per semplificare le cose, hanno detto di copiare "keystore.jks" dal server delle app di glassfish (glassfish \ domains \ domain1 \ config \ keystore.jks) che stiamo usando e di metterlo in questa cartella "trust_store" che mi hanno fatto fare il progetto client. Sembra avere senso: i certificati autofirmati nel server ' s key_store corrisponderebbe alle certs nel client trust_store. Ora, facendo questo, stavo ottenendo l'errore menzionato dal post originale. Ho cercato su Google e ho letto che l'errore è dovuto al file "keystore.jks" sul client che non contiene un certificato attendibile / firmato, che il certificato che trova è autofirmato.

Per chiarire le cose, lasciatemi dire che, come ho capito, "keystore.jks" contiene certificati autofirmati e il file "cacerts.jks" contiene certificati CA (firmati dalla CA). "Keystore.jks" è il "keystore" e "cacerts.jks" è il "negozio di fiducia". Come "Bruno", un commentatore, dice sopra, "keystore.jks" è locale e "cacerts.jks" è per i client remoti.

Quindi, ho detto a me stesso, ehi, glassfish ha anche il file "cacerts.jks", che è il file trust_store di glassfish. cacerts.jsk dovrebbe contenere certificati CA. E a quanto pare ho bisogno che la mia cartella trust_store contenga un file di archivio chiavi con almeno un certificato CA. Quindi, ho provato a inserire il file "cacerts.jks" nella cartella "trust_store" che avevo creato, sul mio progetto client, e modificando le proprietà della VM in modo che puntassero a "cacerts.jks" anziché "keystore.jks". Che si è sbarazzato dell'errore. Immagino che tutto ciò che servisse fosse un certificato CA per funzionare.

Questo potrebbe non essere l'ideale per la produzione, o anche per lo sviluppo, oltre a far funzionare qualcosa. Ad esempio, è possibile utilizzare il comando "keytool" per aggiungere certificati CA al file "keystore.jks" nel client. Ma spero che questo almeno restringa i possibili scenari che potrebbero verificarsi qui per causare l'errore.

ANCHE: il mio approccio sembrava essere utile per il client (certificato server aggiunto al client trust_store), sembra che i commenti sopra per risolvere il post originale siano utili per il server (certificato client aggiunto al server trust_store). Saluti.

Installazione del progetto Eclipse:

  • MyClientProject
  • src
  • test
  • Libreria di sistema JRE
  • ...
  • trust_store
    --- cacerts.jks --- keystore.jks

Snippet dal file MyClientProject.java:

static {
  // Setup the trustStore location and password
  System.setProperty("javax.net.ssl.trustStore","trust_store/cacerts.jks");
  // comment out below line
  System.setProperty("javax.net.ssl.trustStore","trust_store/keystore.jks");
  System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
  //System.setProperty("javax.net.debug", "all");

  // for localhost testing only
  javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() {
        public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) {
          return hostname.equals("localhost");
        }

  });
}

1

Il mio problema era che un broker di sicurezza per l'accesso al cloud, NetSkope, era installato sul mio laptop da lavoro tramite un aggiornamento software. Ciò stava alterando la catena di certificati e non ero ancora in grado di connettermi al server tramite il mio client Java dopo aver importato l'intera catena nel mio keystore cacerts. Ho disabilitato NetSkope ed è stato in grado di connettermi correttamente.


1

Nel mio caso stavo affrontando il problema perché nel mio processo Tomcat è stato dato l'uso di keystore specifico

-Djavax.net.ssl.trustStore=/pathtosomeselfsignedstore/truststore.jks

Mentre stavo importando il certificato nel cacert di JRE / lib / security e le modifiche non riflettevano. Poi ho fatto sotto il comando dove /tmp/cert1.test contiene il certificato del server di destinazione

keytool -import -trustcacerts -keystore /pathtosomeselfsignedstore/truststore.jks -storepass password123 -noprompt -alias rapidssl-myserver -file /tmp/cert1.test

Possiamo ricontrollare se l'importazione del certificato ha esito positivo

keytool -list -v -keystore /pathtosomeselfsignedstore/truststore.jks

e vedere se il tuo server di taget è stato trovato contro alias rapidssl-myserver


0

Controlla se il file $JAVA_HOME/lib/security/cacertsesiste! Nel mio caso non si trattava di un file ma di un collegamento /etc/ssl/certs/java/cacertse anche questo era un collegamento a se stesso (COSA ???), quindi JVM non riesce a trovare il file.

Soluzione: copia il file cacerts reale ( puoi farlo da un altro JDK ) nella /etc/ssl/certs/java/directory e risolverà il tuo problema :)


infatti JDK mantiene un collegamento e forse per compatibilità con API, SDK precedenti ... Sono riuscito a fare lo stesso con successo ... Mi sto spostando da JDK 8 a JDK 10 e usando Docker, quindi dovevo solo copiare i cookie da un immagine ad un altro ... Ho creato il link e lo stesso esatto modo ...rm -f /opt/jdk-minimal/jre/lib/security/cacerts ; ln -s /etc/ssl/certs/java/cacerts /opt/jdk-minimal/jre/lib/security/cacerts
Marcello de Sales

-9

Diciamo se stai usando variabili classpath come $ {JAVA_HOME} in pom.xml.

<target>
                    <property name="compile_classpath" refid="maven.compile.classpath"/>
                    <property name="runtime_classpath" refid="maven.runtime.classpath"/>
                    <property name="test_classpath" refid="maven.test.classpath"/>
                    <property name="plugin_classpath" refid="maven.plugin.classpath"/>
                    <property name="jaxb-api.jar" value="${maven.dependency.javax.xml.bind.jaxb-api.jar.path}"/>
                    <property name="project_home" value="${PROJECT_HOME}"/>
                    <property name="java_home" value="${JAVA_HOME}"/>
                    <property name="ant_home" value="${ANT_HOME}"/>
                    <property name="common_home" value="${COMMON_HOME}"/>
                    <property name="JAXP_HOME" value="${common_home}/lib"/>
                    <property name="ejfw_home" value="${PROJECT_HOME}/lib"/>
                    <property name="weblogic_home" value="${WL_HOME}"/>
                    <property name="fw_home" value="${FW_HOME}"/>
                    <property name="env" value="${BUILDENV}"/>
                    <property name="tokenfile" value="${BUILDENV}${BUILDENV_S2S}.properties"/>

Sugli obiettivi, aggiungi le variabili del percorso di classe. cioè .., -DANT_HOME, -DJAVA_HOME

clean install -e -DPROJECT_HOME=..... -DANT_HOME=C:\bea1036\modules\org.apache.ant_1.7.1 -DJAVA_HOME=C:\bea1036\jdk160_31

1
I percorsi di classe e i certificati non hanno nulla a che fare l'uno con l'altro.
Marchese di Lorne,

1
Credo che tu abbia frainteso la domanda.
Dawood ibn Kareem,
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.