web-dev-qa-db-fra.com

Ancre de confiance introuvable pour la connexion SSL Android

J'essaie de me connecter à une boîte IIS6 exécutant un certificat SSL godaddy 256 bits, et j'obtiens le message d'erreur suivant:

Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

J'essayais de déterminer ce qui pouvait être la cause de cela, mais je dessinais des blancs en ce moment.

Voici comment je me connecte:

HttpsURLConnection conn;              
conn = (HttpsURLConnection) (new URL(mURL)).openConnection();
conn.setConnectTimeout(20000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
String tempString = toString(conn.getInputStream()); 
132
Chrispix

La solution de @Chrispix est dangereuse! Faire confiance à tous les certificats permet à quiconque de faire l'attaque d'un homme au milieu! Envoyez n'importe quel certificat au client et il l'acceptera!

Ajoutez vos certificats à un gestionnaire de confiance personnalisé comme décrit dans cet article: Faire confiance à tous les certificats utilisant HttpClient via HTTPS

Bien qu’il soit un peu plus complexe d’établir une connexion sécurisée avec un certificat personnalisé, il vous apportera la sécurité de chiffrement SSL recherchée sans le danger d’une attaque de type homme au milieu!

62
Matthias B

Contrairement à la réponse acceptée, vous n'avez pas besoin d'un gestionnaire de confiance personnalisé, vous devez réparer votre serveur configuration!

Je rencontre le même problème lors de la connexion à un serveur Apache avec un certificat dynadot/alphassl mal installé. Je me connecte à l'aide de HttpsUrlConnection (Java/Android), qui lançait -

javax.net.ssl.SSLHandshakeException: 
  Java.security.cert.CertPathValidatorException: 
    Trust anchor for certification path not found.

Le problème réel est une mauvaise configuration du serveur - testez-le avec http://www.digicert.com/help/ ou similaire, et il vous indiquera même la solution:

"Le certificat n'est pas signé par une autorité de confiance (vérification par rapport au magasin racine de Mozilla). Si vous avez acheté le certificat auprès d'une autorité de confiance, , il vous suffit probablement de l'installer. un ou plusieurs certificats intermédiaires . Contactez votre fournisseur de certificats pour obtenir de l'aide pour cette opération sur votre plate-forme de serveur. "

Vous pouvez également vérifier le certificat avec openssl:

openssl s_client -debug -connect www.thedomaintocheck.com:443

Vous verrez probablement:

Verify return code: 21 (unable to verify the first certificate)

et plus tôt dans la sortie:

depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, CN = www.thedomaintocheck.com
verify error:num=21:unable to verify the first certificate`

La chaîne de certificats ne contiendra qu'un seul élément (votre certificat):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
  i:/O=AlphaSSL/CN=AlphaSSL CA - G2

... mais les autorités de signature doivent, dans une chaîne, faire référence à des autorités de confiance approuvées par Android (Verisign, GlobalSign, etc.):

Certificate chain
 0 s:/OU=Domain Control Validated/CN=www.thedomaintocheck.com
   i:/O=AlphaSSL/CN=AlphaSSL CA - G2
 1 s:/O=AlphaSSL/CN=AlphaSSL CA - G2
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
 2 s:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA
   i:/C=BE/O=GlobalSign nv-sa/OU=Root CA/CN=GlobalSign Root CA

Les instructions (et les certificats intermédiaires) pour la configuration de votre serveur sont généralement fournies par l'autorité qui a délivré votre certificat, par exemple: http://www.alphassl.com/support/install-root-certificate.html =

Après avoir installé les certificats intermédiaires fournis par mon émetteur de certificats, je n'ai plus d'erreur lors de la connexion à l'aide de HttpsUrlConnection.

193
Stevie

Vous pouvez faire confiance à un certificat particulier au moment de l'exécution.
Il suffit de le télécharger depuis le serveur, de mettre des actifs et de le charger comme ceci avec ssl-utils-Android :

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

Dans l'exemple ci-dessus, j'ai utilisé OkHttpClient mais SSLContext peut être utilisé avec n'importe quel client Java.

Si vous avez des questions, n'hésitez pas à les poser. Je suis l'auteur de cette petite bibliothèque.

15
klimat

Mise à jour basée sur la dernière documentation Android (mars 2017):

Lorsque vous obtenez ce type d'erreur:

javax.net.ssl.SSLHandshakeException: Java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
        at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:374)
        at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.Java:209)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.Java:478)
        at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.Java:433)
        at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.Java:290)
        at libcore.net.http.HttpEngine.sendRequest(HttpEngine.Java:240)
        at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.Java:282)
        at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.Java:177)
        at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.Java:271)

le problème pourrait être l'un des suivants:

  1. L'autorité de certification ayant émis le certificat de serveur était inconnue. 
  2. Le certificat de serveur n'a pas été signé par une autorité de certification, mais a été auto-signé 
  3. Il manque une autorité de certification intermédiaire à la configuration du serveur.

La solution consiste à apprendre à HttpsURLConnection à faire confiance à un ensemble spécifique d'AC. Comment? Veuillez vérifier https://developer.Android.com/training/articles/security-ssl.html#CommonProblems

Les autres utilisateurs de AsyncHTTPClient de la bibliothèque com.loopj.Android:android-async-http doivent vérifier Configurez AsyncHttpClient pour utiliser HTTPS

11
user1506104

Répondre à très vieux poste. Mais peut-être que cela aidera certains débutants et si aucune de ces solutions ne fonctionne.

Explication: Je sais que personne ne veut une explication merde; plutôt la solution. Mais dans une ligne, vous essayez d'accéder à un service de votre ordinateur local vers un ordinateur distant qui ne fait pas confiance à votre ordinateur. Votre demande doit gagner la confiance du serveur distant. 

Solution: La solution suivante suppose que vous remplissez les conditions suivantes.

  1. Essayer d'accéder à une api distante à partir de votre machine locale.
  2. Vous construisez pour une application Android
  3. Votre serveur distant est en cours de filtrage par proxy (vous utilisez un proxy dans les paramètres de votre navigateur pour accéder au service api distant, généralement un serveur intermédiaire ou un serveur dev).
  4. Vous testez sur un appareil réel

Pas:

Vous avez besoin d’un fichier d’extension .keystore pour inscrire votre application. Si vous ne savez pas comment créer un fichier .keystore; Ensuite, suivez la section suivante Créer un fichier .keystore ou passez à la section suivante Sign Apk File

Créer un fichier .keystore

Ouvrez Android Studio. Cliquez sur le menu supérieur Construction> Générer un APK signé. Dans la fenêtre suivante, cliquez sur le bouton Créer nouveau .... Dans la nouvelle fenêtre, veuillez saisir les données dans tous les champs. Rappelez-vous que le champ de deux mots de passe que je recommande devrait avoir le même mot de passe; n'utilisez pas de mot de passe différent; et souvenez-vous également du chemin de sauvegarde situé en haut du champ chemin du magasin de clés:. Après avoir saisi tout le champ, cliquez sur le bouton OK.

Sign Apk File

Vous devez maintenant créer une application signée avec le fichier .keystore que vous venez de créer. Suivez ces étapes

  1. Build> Clean Project, attendez la fin du nettoyage
  2. Construire> Générer un APK signé
  3. Cliquez sur le bouton Choose existing...
  4. Sélectionnez le fichier .keystore que nous venons de créer dans la section Create .keystore file.
  5. Entrez le même mot de passe que vous avez créé lors de la création dans la section Create .keystore file. Utilisez le même mot de passe pour les champs Key store password et Key password. Entrez également le pseudonyme
  6. Cliquez sur le bouton Suivant
  7. Dans l'écran suivant; qui peuvent être différents en fonction de vos paramètres dans les fichiers build.gradle, vous devez sélectionner Build Types et Flavors.
  8. Pour le Build Types, choisissez release dans le menu déroulant.
  9. Pour Flavors cependant, cela dépendra de vos paramètres dans le fichier build.gradle. Choisissez staging dans ce champ. J'ai utilisé les paramètres suivants dans le build.gradle, vous pouvez utiliser la même chose que le mien, mais assurez-vous de changer la applicationId pour le nom de votre paquet

    productFlavors {
        staging {
            applicationId "com.yourapplication.package"
            manifestPlaceholders = [icon: "@drawable/ic_launcher"]
            buildConfigField "boolean", "CATALYST_DEBUG", "true"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "true"
        }
        production {
            buildConfigField "boolean", "CATALYST_DEBUG", "false"
            buildConfigField "boolean", "ALLOW_INVALID_CERTIFICATE", "false"
        }
    }
    
  10. Cliquez sur les deux cases Signature Versions du bas, puis sur le bouton Finish.

Presque là:

Tout le travail est fait, maintenant le mouvement de la vérité. Pour pouvoir accéder au serveur de stockage intermédiaire sauvegardé par un proxy, vous devez définir certains paramètres dans vos appareils Android en cours de test. 

Configuration du proxy sur un périphérique Android:

  1. Cliquez sur les paramètres à l'intérieur du téléphone Android, puis Wi-Fi
  2. Appuyez longuement sur le wifi connecté et sélectionnez Modify network
  3. Cliquez sur le Advanced options si vous ne pouvez pas voir le champ Proxy Hostname
  4. Dans le Proxy Hostname, entrez l'adresse IP de l'hôte ou le nom que vous souhaitez connecter. Un serveur de transfert type sera nommé stg.api.mygoodcompany.com
  5. Pour le port, entrez le numéro de port à quatre chiffres, par exemple 9502
  6. Appuyez sur le bouton Save

Un dernier arrêt:

Rappelez-vous que nous avons généré le fichier apk signé dans la section Sign APK APK. Il est maintenant temps d'installer ce fichier APK.

  1. Ouvrez un terminal et ouvrez le dossier de fichiers apk signé.
  2. Connectez votre appareil Android à votre machine
  3. Supprimer tout fichier apk précédemment installé du périphérique Android
  4. Exécuter adb installname of the apk file
  5. Si, pour une raison quelconque, la commande ci-dessus est renvoyée avec adb command not found. Entrez le chemin complet en tant que C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exeinstallname of the apk file

J'espère que le problème pourra être résolu. Si non s'il vous plaît laissez-moi un commentaire.

Salam!

6
HA S

Le message d'erreur que je recevais était similaire, mais la raison en était que le certificat auto-signé avait expiré . Lorsque le client openssl a été tenté, il m'a donné la raison qui avait été oubliée lorsque je vérifiais la boîte de dialogue du certificat de Firefox.

Donc, en général, si le certificat est présent dans le magasin de clés et que sa valeur est "VALID", cette erreur disparaîtra.

4
MPN

J'ai eu le même problème lors de la connexion d'un client Android au serveur Kurento . Le serveur Kurento utilisait des certificats jks. errors . Mais si vous utilisez fullchain.pem au lieu de cert.pem - tout va bien.

2
V.Poddubchak

J'ai eu le même problème ce que j'ai trouvé était que le fichier de certificat .crt i fourni manquant un certificat intermédiaire. J'ai donc demandé à tous les fichiers .crt de mon administrateur serveur, puis je les ai concaténés dans l'ordre inverse.

Ex ..__ 1. Root.crt 2. Inter.crt 3. myCrt.crt

dans Windows i exécuté copier Inter.crt + Root.crt newCertificate.crt

(Ici j'ai ignoré myCrt.crt)

Ensuite, j'ai fourni le fichier newCertificate.crt dans le code via inputstream . Travail effectué.

2
sahan maldeniya

Je sais que vous n'avez pas besoin de faire confiance à tous les certificats, mais dans mon cas, j'avais des problèmes avec certains environnements de débogage dans lesquels nous avions des certificats auto-signés et j'avais besoin d'une solution fictive. 

Tout ce que je devais faire était de changer l'initialisation de sslContext

mySSLContext.init(null, trustAllCerts, null); 

trustAllCerts a été créé comme ceci:

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new Java.security.cert.X509Certificate[]{};
    }

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

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

J'espère que cela vous sera utile.

1
Adrian C.

L'erreur d'ancrage de confiance peut se produire pour de nombreuses raisons. Pour moi, c'était simplement que j'essayais d'accéder à https://example.com/ au lieu de https://www.example.com/.

Donc, vous voudrez peut-être vérifier vos URL avant de commencer à créer votre propre gestionnaire de confiance (comme je l'ai fait).

1
Unkulunkulu

Si vous utilisez retrofit, vous devez personnaliser votre OkHttpClient. 

retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

Le code complet est comme ci-dessous.

    public class RestAdapter {

    private static Retrofit retrofit = null;
    private static ApiInterface apiInterface;

    public static OkHttpClient.Builder getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

                        @Override
                        public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new Java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            return builder;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static ApiInterface getApiClient() {
        if (apiInterface == null) {

            try {
                retrofit = new Retrofit.Builder()
                        .baseUrl(ApplicationData.FINAL_URL)
                        .client(getUnsafeOkHttpClient().build())
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();

            } catch (Exception e) {

                e.printStackTrace();
            }


            apiInterface = retrofit.create(ApiInterface.class);
        }
        return apiInterface;
    }

}
1
Shihab Uddin

Sur les téléphones en pain d'épice, j'obtiens toujours l'erreur: Trust Anchor not found for Android SSL Connection, même si je dois installer mon certificat.

Voici le code que j'utilise (en langage Scala):

object Security {
    private def createCtxSsl(ctx: Context) = {
        val cer = {
            val is = ctx.getAssets.open("mycertificate.crt")
            try
                CertificateFactory.getInstance("X.509").generateCertificate(is)
            finally
                is.close()
        }
        val key = KeyStore.getInstance(KeyStore.getDefaultType)
        key.load(null, null)
        key.setCertificateEntry("ca", cer)

        val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
    tmf.init(key)

        val c = SSLContext.getInstance("TLS")
        c.init(null, tmf.getTrustManagers, null)
        c
    }

    def prepare(url: HttpURLConnection)(implicit ctx: Context) {
        url match {
            case https: HttpsURLConnection ⇒
                val cSsl = ctxSsl match {
                    case None ⇒
                        val res = createCtxSsl(ctx)
                        ctxSsl = Some(res)
                        res
                    case Some(c) ⇒ c
                }
                https.setSSLSocketFactory(cSsl.getSocketFactory)
            case _ ⇒
        }
    }

    def noSecurity(url: HttpURLConnection) {
        url match {
            case https: HttpsURLConnection ⇒
                https.setHostnameVerifier(new HostnameVerifier {
                    override def verify(hostname: String, session: SSLSession) = true
                })
            case _ ⇒
        }
    }
}

et voici le code de connexion:

def connect(securize: HttpURLConnection ⇒ Unit) {
    val conn = url.openConnection().asInstanceOf[HttpURLConnection]
    securize(conn)
    conn.connect();
    ....
}

try {
    connect(Security.prepare)
} catch {
    case ex: SSLHandshakeException /*if ex.getMessage != null && ex.getMessage.contains("Trust anchor for certification path not found")*/ ⇒
        connect(Security.noSecurity)
}

Fondamentalement, j'ai configuré pour faire confiance à mon certificat personnalisé. Si cela échoue, alors je désactive la sécurité. Ce n'est pas la meilleure option, mais le seul choix que je connaisse avec les téléphones anciens et bogués.

Cet exemple de code peut être facilement traduit en Java.

0
david.perez

Dans mon cas, cela se produisait après la mise à jour vers Android 8.0. Le certificat auto-signé par Android était censé utiliser l’algorithme de signature SHA1withRSA. Le passage à un nouveau certificat utilisant l’algorithme de signature SHA256withRSA a résolu le problème.

0
Zds