Java: sun.security.provider.certpath.SunCertPathBuilderException: impossible de trouver un chemin de certification valide vers la cible demandée


249

J'ai une classe qui téléchargera un fichier à partir d'un serveur https . Lorsque je l'exécute, il renvoie beaucoup d'erreurs. Il semble que j'ai un problème avec mon certificat. Est-il possible d'ignorer l'authentification client-serveur? Si c'est le cas, comment?

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

    }
}

Les erreurs:

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
Une fois, j'ai eu cette erreur et j'ai contacté notre équipe de sécurité, et il s'est avéré que je devais corriger le JAR que nous utilisions, car notre équipe en utilisait un obsolète fourni par la société. Juste un info pour toute autre personne qui peut être dans une situation similaire.
kayleeFrye_onDeck

Réponses:


215

Le problème apparaît lorsque votre serveur possède un certificat auto-signé. Pour contourner ce problème, vous pouvez ajouter ce certificat à la liste des certificats approuvés de votre machine virtuelle Java.

Dans cet article, l' auteur explique comment récupérer le certificat à partir de votre navigateur et l'ajouter au fichier cacerts de votre machine virtuelle Java. Vous pouvez soit modifier le JAVA_HOME/jre/lib/security/cacertsfichier, soit exécuter votre application avec un -Djavax.net.ssl.trustStoreparamètre. Vérifiez également le JDK / JRE que vous utilisez, car cela est souvent une source de confusion.

Voir aussi: Comment les noms de serveur de certificats SSL sont-ils résolus / Puis-je ajouter d'autres noms à l'aide de keytool? Si vous rencontrez une java.security.cert.CertificateException: No name matching localhost foundexception.


3
cela n'a pas fonctionné pour moi. J'ai la racine et le certificat de chaîne installés, mais Tomcat-7 signale toujours une exception validatorException causée par "impossible de trouver un chemin de certification valide vers la cible demandée".
Cheruvim

Le problème apparaît également avec un certificat signé par quelqu'un d'autre qui n'est pas approuvé.
Marquis de Lorne

Génial! Ça marche! N'oubliez pas que vous pouvez avoir à la fois jre et jdk, et que leurs deux cacertsdoivent être mis à jour
Dima Fomin

Dans mon cas, l'autorité de certification racine était là, mais pas l'autorité de certification suivante en panne. L'ajout de la prochaine autorité de certification a fait l'affaire - merci.
java-addict301

1
Dans mon cas, j'utilise Netbeans + Apache Tomcat (intégré), donc, en ajoutant .cer au magasin de clés de confiance "cacerts" sur Jdk / jre (C: \ Program Files \ Java \ jdk1.8.0_152 \ jre \ lib \ sécurité) et Jre (C: \ Program Files \ Java \ jre1.8.0_91 \ lib \ security) fonctionne pour moi
Jnn

149

Voici ce qui fonctionne de manière fiable pour moi sur macOS. Assurez-vous de remplacer example.com et 443 par le nom d'hôte et le port réels auxquels vous essayez de vous connecter et donnez un alias personnalisé. La première commande télécharge le certificat fourni à partir du serveur distant et l'enregistre localement au format x509. La deuxième commande charge le certificat enregistré dans le magasin de confiance 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

3
Fonctionne pour moi pourquoi? Vous devez fournir une explication.
Marquis de Lorne

openssl x509 -in <(openssl s_client -connect example.com:443 -prexit 2> / dev / null) -out ~ / example.crt - qu'est-ce que example.crt dans la commande j'ai un certificat .pem que je dois donner c'est ici ??
Vishnu Ranganathan

3
.crt et .pem sont des extensions de fichier couramment utilisées pour le même format de fichier. Si vous avez déjà le fichier, exécutez simplement la deuxième commande et passez-le dans l'argument -file.
Gabe Martin-Dempesy

1
Super truc. La seule chose est: j'ai dû utiliser le dernier openssl 1.0.Xx pour une raison quelconque, l'ancien 9.X.Xx ne fonctionnait pas.
zbstof

1
Cela ne fonctionne pas avec le point de terminaison SNI. Pour ce cas, vous devez ajouter: -nomserveur example.com lors de la récupération du certificat
Patrik Beck

46

J'ai eu le même problème avec un certificat générique signé valide de symantec.

Essayez d'abord d'exécuter votre application java avec -Djavax.net.debug = SSL pour voir ce qui se passe réellement.

J'ai fini par importer le certificat intermédiaire qui provoquait la rupture de la chaîne de certificats.

J'ai téléchargé le certificat intermédiaire manquant depuis symantec (vous pouvez voir le lien de téléchargement vers le certificat manquant dans le journal de prise de contact SSL: http://svrintl-g3-aia.verisign.com/SVRIntlG3.cer dans mon cas).

Et j'ai importé le certificat dans le magasin de clés java. Après avoir importé le certificat intermédiaire, mon certificat SSL générique a finalement commencé à fonctionner:

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

Ce fut le cas:
kisna

2
Pour éviter toute confusion, exécutez java (ou jcurl) avec des paramètres de débogage pour voir la "chaîne de certificats" distante dans les journaux, puis grep le "CN" dans le magasin de clés de confiance explicitement passé (au lieu de la valeur par défaut) comme suit, s'il n'est pas présent, vous devez l'ajouter. ssllabs.com/ssltest/analyze.html indiquera si les certificats côté serveur ont une chaîne incomplète et inclut des certificats de chemin de certification intermédiaires qui doivent être ajoutés. -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


J'ai eu le même problème, cela est très utile, mais dans mon cas, vous n'avez eu qu'à ajouter le certificat de serveur au fichier cacerts de la version JDK
Pigritia

Veuillez garder à l'esprit qu'il existe un autre outil appelé portecle qui peut ouvrir le fichier cacert (magasin de certificats) et importer facilement le certificat. N'oubliez pas de sauvegarder le fichier cacert par la suite.
will824 Il y a

41
  1. Exportez le certificat SSL à l'aide de Firefox. Vous pouvez l'exporter en appuyant sur l'URL dans le navigateur, puis sélectionnez l'option pour exporter le certificat. Supposons que le nom du fichier cert soit your.ssl.server.name.crt
  2. Accédez à votre JRE_HOME/binouJDK/JRE/bin
  3. Tapez la commande
  4. keytool -keystore ..\lib\security\cacerts -import -alias your.ssl.server.name -file .\relative-path-to-cert-file\your.ssl.server.name.crt
  5. Redémarrez votre processus Java

13
Si un mot de passe vous est demandé, utilisez le mot de passe par défaut du magasin de clés cacerts changeit( stackoverflow.com/a/22782035/1304830 ). Assurez-vous également d'exécuter cmd en tant qu'administrateur.
Fr4nz

22

@Gabe Martin-Dempesy m'a aidé. Et j'ai écrit un petit script qui s'y rapporte. L'utilisation est très simple.

Installez un certificat de l'hôte:

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

Supprimez le certificat déjà installé.

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

Fonctionne parfaitement. Bon travail! . Voici comment cela fonctionne: démarrez votre service SSL (s'il ne fonctionne pas) et exécutez la commande comme expliqué (par exemple ./java-cert-importer.sh example.com 1234). C'est tout.
lepe

1
Fonctionne très bien. J'obtenais l'erreur sur un serveur Jenkins se connectant à une API externe qui modifie son certificat et échoue mes constructions. Cela résout mon problème
user9869932

Oracle aurait dû fournir quelque chose comme ça en premier lieu ou jamais chacun n'a créé sa propre horrible solution SSL. La gestion des certificats SSL devrait être la tâche d'un système d'exploitation.
Wolfgang Fahl

17

Citation de No more «impossible de trouver un chemin de certification valide vers la cible demandée»

lorsque vous essayez d'ouvrir une connexion SSL à un hôte à l'aide de JSSE. Cela signifie généralement que le serveur utilise un certificat de test (éventuellement généré à l'aide de keytool) plutôt qu'un certificat d'une autorité de certification commerciale bien connue telle que Verisign ou GoDaddy. Les navigateurs Web affichent des boîtes de dialogue d'avertissement dans ce cas, mais comme JSSE ne peut pas supposer qu'un utilisateur interactif est présent, il lève simplement une exception par défaut.

La validation du certificat est une partie très importante de la sécurité SSL, mais je n'écris pas cette entrée pour expliquer les détails. Si vous êtes intéressé, vous pouvez commencer par lire le texte de présentation Wikipédia. J'écris cette entrée pour montrer un moyen simple de parler à cet hôte avec le certificat de test, si vous le voulez vraiment.

Fondamentalement, vous souhaitez ajouter le certificat du serveur au magasin de clés avec vos certificats de confiance

Essayez le code fourni ici. Ça pourrait aider.


5
La partie sur "La validation des certificats est une partie très importante de la sécurité SSL" n'est pas nécessairement vraie. SSL vous donne deux assurances: (1) que votre communication est privée, et (2) que vous parlez à un serveur connu de la NSA. (:-) Parfois, vous ne vous souciez que de la confidentialité de la conversation, puis la certification auto-signée est très bien. Voir social-biz.org/2011/10/16/the-anti-ssl-conspiracy
AgilePro

@AgilePro SSL vous donne quatre assurances: authentification, confidentialité, intégrité et possibilité d'autorisation. Il ne pas vous donner l'assurance que vous parlez à un serveur connu à la NSA. Se soucier uniquement de la confidentialité sans authentification est une contradiction en termes.
Marquis de Lorne

@EJP Je suis d'accord que si vous utilisez un certificat client, vous pouvez obtenir une authentification et je suppose que la possibilité d'autorisation ... mais la plupart des utilisations ne sont pas avec un certificat client. Comment qualifieriez-vous la différence entre un certificat «auto-signé» et un certificat émanant d'une autorité de signature? Le pouvoir de signature confère-t-il «l'intégrité». Ma blague à propos de la NSA est que toutes les autorités de signature ne peuvent pas garantir positivement l'indépendance de tout. Pas vraiment paranoïaque, mais le fait est que votre certificat est SEULEMENT aussi secret que le signataire peut le faire. L'auto-signature peut être plus secrète.
AgilePro

@AgilePro L'utilisation d'un certificat de serveur authentifie le serveur et est nécessaire pour sécuriser SSL, comme indiqué dans la RFC 2246. Les certificats ne sont pas secrets du tout: le reste de votre commentaire n'a donc aucun sens.
Marquis de Lorne

6

Cela a résolu mon problème,

Nous devons importer le certificat sur la java locale. Sinon, nous pourrions obtenir l'exception ci-dessous.

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: échec de la création du chemin PKIX: sun.security.provider.certpath.SunCertPathBuilderException: impossible de trouver un chemin de certification valide vers la cible demandée
        à sun.security.ssl.Alerts.getSSLException (Alerts.java:192)
        à sun.security.ssl.SSLSocketImpl.fatal (SSLSocketImpl.java:1949)
        à sun.security.ssl.Handshaker.fatalSE (Handshaker.java:302)

SSLPOKE est un outil où vous pouvez tester la connectivité https depuis votre machine locale.

Commande pour tester la connectivité:

"%JAVA_HOME%/bin/java" SSLPoke <hostname> 443
    sun.security.validator.ValidatorException: échec de la création du chemin PKIX: 
    sun.security.provider.certpath.SunCertPathBuilderException: impossible de trouver un chemin de certification valide vers la cible demandée
        à sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:387)
        à sun.security.validator.PKIXValidator.engineValidate (PKIXValidator.java:292)
        à sun.security.validator.Validator.validate (Validator.java:260)
        à sun.security.ssl.X509TrustManagerImpl.validate (X509TrustManagerImpl.java:324)
        à sun.security.ssl.X509TrustManagerImpl.checkTrusted (X509TrustManagerImpl.java:229)
        à sun.security.ssl.X509TrustManagerImpl.checkServerTrusted (X509TrustManagerImpl.java:124)
        à sun.security.ssl.ClientHandshaker.serverCertificate (ClientHandshaker.java:1496)
        à sun.security.ssl.ClientHandshaker.processMessage (ClientHandshaker.java:216)
        à sun.security.ssl.Handshaker.processLoop (Handshaker.java:1026)
        à sun.security.ssl.Handshaker.process_record (Handshaker.java:961)
        à sun.security.ssl.SSLSocketImpl.readRecord (SSLSocketImpl.java:1062)
        à sun.security.ssl.SSLSocketImpl.performInitialHandshake (SSLSocketImpl.java:1375)
        à sun.security.ssl.SSLSocketImpl.writeRecord (SSLSocketImpl.java:747)
        à sun.security.ssl.AppOutputStream.write (AppOutputStream.java:123)
        à sun.security.ssl.AppOutputStream.write (AppOutputStream.java:138)
        sur SSLPoke.main (SSLPoke.java:31)
    Causée par: sun.security.provider.certpath.SunCertPathBuilderException: impossible de trouver un chemin de certification valide vers 
    cible demandée
        à sun.security.provider.certpath.SunCertPathBuilder.build (SunCertPathBuilder.java:141)
        à sun.security.provider.certpath.SunCertPathBuilder.engineBuild (SunCertPathBuilder.java:126)
        sur java.security.cert.CertPathBuilder.build (CertPathBuilder.java:280)
        à sun.security.validator.PKIXValidator.doBuild (PKIXValidator.java:382)
        ... 15 de plus
keytool -import -alias <anyname> -keystore "%JAVA_HOME%/jre/lib/security/cacerts" -file <cert path>

cela demanderait d'abord "Entrez le mot de passe du magasin de clés:" changeitest le mot de passe par défaut. et enfin une invite "Trust this certificate? [no]:", indiquez "yes" pour ajouter le certificat au magasin de clés.

Vérification:

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

5

J'ai pu le faire fonctionner uniquement avec du code, c'est-à-dire pas besoin d'utiliser 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
Btw, j'utilise httpasyncclient: 4.0.1
Jonas Bergström

J'avais besoin de quelque chose de similaire, @ JonasBergström, votre solution avec SSLContext aide beaucoup.
EnterSB

8
Notez que cette solution n'est pas sécurisée.
Marquis de Lorne

Merci Jonas, votre solution a résolu le problème. Mais j'ai trouvé que la création de la première connexion coûte très longtemps (3 à 5 s), après quoi chaque connexion n'a besoin que de 300 à 400 ms.
twcai

5

La source de cette erreur sur mon instance Apache 2.4 (à l'aide d'un certificat générique Comodo) était un chemin incomplet vers le certificat racine signé SHA-1. Il y avait plusieurs chaînes dans le certificat émis et la chaîne menant à un certificat racine SHA-1 manquait un certificat intermédiaire . Les navigateurs modernes savent comment gérer cela, mais Java 7 ne le gère pas par défaut (bien qu'il existe des moyens compliqués pour y parvenir dans le code). Le résultat est des messages d'erreur identiques à ceux des certificats auto-signés:

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

Dans ce cas, le message «impossible de trouver un chemin de certification valide vers la cible demandée» est généré en raison du certificat intermédiaire manquant. Vous pouvez vérifier quel certificat est manquant à l'aide du test SSL Labs sur le serveur. Une fois que vous avez trouvé le certificat approprié, téléchargez-le et (si le serveur est sous votre contrôle), ajoutez-le à l'ensemble de certificats. Vous pouvez également importer le certificat manquant localement. La résolution de ce problème sur le serveur est une solution plus générale au problème.


ssllabs.com/ssltest est un sauveur, il suffit de le comparer avec une validation de certificat de travail.
kisna

5

Pour Windows uniquement, procédez comme suit:

  1. Dans Chrome, accédez aux paramètres.
  2. Dans Paramètres, cliquez sur Afficher les paramètres avancés.
  3. Sous HTTPS / SSL, cliquez sur Gérer les certificats.
  4. Exportez votre certificat.
  5. Dans les recherches Windows (en appuyant sur la touche Windows du clavier), tapez java.
  6. Sélectionnez (Configurer Java) Option qui ouvrira le Panneau de configuration Java
  7. Sélectionnez l'onglet Sécurité dans le panneau de configuration Java
  8. Sélectionnez Gérer les certificats
  9. Cliquez sur Importer
  10. Sous l'onglet (Utilisateur) sélectionné et le type de certificat comme (Certificats de confiance)
  11. Cliquez sur le bouton Importer et recherchez le certificat téléchargé et importez-le.

4

Pour ceux qui aiment Debian et Java préemballé:

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

N'oubliez pas de vérifier /etc/default/cacerts:

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

Pour supprimer le cert:

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

2

Cela peut également être dû à l'utilisation de certificats GoDaddy avec Java 7 signés à l'aide de SHA2.

Chrome et tous les autres navigateurs commencent à déprécier les certificats SSL signés à l'aide de SHA1, car ce n'est pas aussi sécurisé.

Plus d'informations sur le problème peuvent être trouvées ici , ainsi que comment le résoudre sur votre serveur si vous en avez besoin maintenant.


2

J'ai eu le même problème avec l'erreur de certificats et c'était à cause de SNI, et le client http que j'ai utilisé n'a pas implémenté SNI. Donc, une mise à jour de version a fait le travail

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

2

MISE À JOUR: Qu'un redémarrage a aidé était une coïncidence (je l'espérais, hourra!). La véritable cause du problème était la suivante: lorsque Gradle est invité à utiliser un magasin de clés spécifique, ce magasin de clés doit également contenir tous les certificats racine officiels. Sinon, il ne peut pas accéder aux bibliothèques à partir de référentiels réguliers. Ce que je devais faire était ceci:

Importez le certificat auto-signé:

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

Ajoutez les certificats racine officiels:

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

Peut-être que le démon Gradle a également gêné. Cela pourrait valoir la peine de tuer tous les démons en cours d'exécution trouvés ./gradlew --statussi les choses semblent sombres.

AFFICHAGE ORIGINAL:

Personne ne le croira, je le sais. Pourtant, si tout le reste échoue, essayez-le: après un redémarrage de mon Mac, le problème a disparu. Grrr.

Contexte: ./gradlew jar n'arrêtait pas de me donner "impossible de trouver un chemin de certification valide vers la cible demandée"

Je suis coincé avec un certificat auto-signé, enregistré à partir du navigateur, importé dans privateKeystore.jks. Ensuite, j'ai demandé à Gradle de travailler avec privateKeystore.jks:

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

Comme mentionné, cela n'a fonctionné qu'après un redémarrage.


2

La version AVG 18.1.3044 (avec Windows 10) interfère avec mon application Spring locale.

Solution: entrez dans la section AVG intitulée "Web et e-mail" et désactivez la "protection des e-mails". AVG bloque le certificat si le site n'est pas sécurisé.


2

Assurez-vous que les https://176.66.3.69:6443/ ont un certificat valide. vous pouvez le vérifier via le navigateur d'abord https non sécurisési cela fonctionne dans le navigateur, cela fonctionnera en java.

ça marche pour moi


Et que dois-je faire si le navigateur se plaint également?
The Godfather

essayez d'installer le certificat
Amr Ibrahim

2

Il existe de nombreuses façons de résoudre ce problème ...

Une façon consiste à définir les certificats TrustStore dans un fichier de clés et à le placer dans le chemin de l'application, puis à définir ces propriétés système dans la méthode principale:

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

Vous pouvez également placer le fichier de clés en tant que fichier de ressources dans le fichier jar du projet et le charger:

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

Dans Windows, vous pouvez également essayer cette solution: https://stackoverflow.com/a/59056537/980442


J'ai créé le fichier de clés à partir d'un fichier d'autorité de certification CA .crtde cette manière:

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

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


1

Vous avez deux options, importez le certificat auto-signé dans le magasin de clés de Java pour chaque jvm sur lequel le logiciel s'exécutera ou essayez l'usine ssl non validante:

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

1

Eu le problème comme cette image.

entrez la description de l'image ici

J'ai essayé quelques solutions. Mais j'ai trouvé que même si c'est le même projet, quand il est sur le lieu de travail de l'autre, c'est tout à fait bien. Aucun réglage supplémentaire requis. Nous avons donc deviné que c'était un problème d'environnement. Nous avons essayé de changer la version JDK, IDE, mais cela n'a pas fonctionné. il a fallu environ 4 heures pour enquêter, jusqu'à ce que nous essayions la réponse la mieux notée. Je n'ai pas trouvé l'erreur mentionnée dans cette réponse mais j'ai trouvé via mon navigateur sur l'URL HTTP (verrou) qu'il y avait une certification de Charles. Puis j'ai réalisé que mon charles était allumé tout le temps. Tant que je l'ai désactivé, cela fonctionne très bien.

J'ai donc laissé mon expérience qui pourrait être utile pour votre cas.


0

Dans mon cas, j'utilise MacOs High Sierra avec Java 1.6. Le fichier cacert est dans un emplacement différent de celui mentionné ci-dessus dans la réponse de Gabe Martin-Dempesy. Le fichier cacert était également déjà lié à un autre emplacement (/ Library / Internet Plug-Ins / JavaAppletPlugin.plugin / Contents / Home / lib / security / cacerts).

À l'aide de FireFox, j'ai exporté le certificat du site Web en question vers un fichier local appelé "exportsCertFile.crt". De là, j'ai utilisé keytool pour déplacer le certificat dans le fichier cacert. Cela a résolu le problème.

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

téléchargez d'abord le certificat ssl puis vous pouvez aller sur votre chemin java bin exécuter la commande ci-dessous dans la console.

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

-1

Dans mon cas, j'avais le keystore et le truststore ayant le même certificat, donc la suppression du truststore a aidé. Parfois, la chaîne de certificats peut être un problème si vous avez plusieurs copies de certificats.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.