it-swarm.com.de

Vertrauensanker für Android SSL-Verbindung nicht gefunden

Ich versuche, eine Verbindung zu einer IIS6-Box herzustellen, auf der ein 256-Bit-SSL-Zertifikat ausgeführt wird, und ich erhalte den Fehler:

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

Ich habe versucht herauszufinden, was das verursachen könnte, aber jetzt Leerzeichen zeichnen.

So verbinde ich:

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

Die Lösung von @Chrispix ist gefährlich! Wenn Sie allen Zertifikaten vertrauen, kann jeder einen Mann im mittleren Angriff einsetzen! Senden Sie einfach ein beliebiges Zertifikat an den Kunden und es wird es akzeptieren!

Fügen Sie Ihre Zertifikate einem benutzerdefinierten Vertrauensmanager hinzu, wie in diesem Beitrag beschrieben: Alle Zertifikate mit HttpClient über HTTPS vertrauen

Obwohl es etwas komplizierter ist, eine sichere Verbindung mit einem benutzerdefinierten Zertifikat herzustellen, erhalten Sie die gewünschte SSL-Verschlüsselungssicherheit, ohne dass dabei die Gefahr eines manuellen Angriffs besteht.

62
Matthias B

Im Gegensatz zur akzeptierten Antwort benötigen Sie keinen benutzerdefinierten Vertrauensmanager, sondern müssen Ihren Server reparieren Aufbau!

Beim Herstellen einer Verbindung zu einem Apache-Server mit einem falsch installierten Dynadot/Alphassl-Zertifikat ist das gleiche Problem aufgetreten. Ich verbinde über HttpsUrlConnection (Java/Android), das ausgelöst hat -

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

Das eigentliche Problem ist eine Fehlkonfiguration des Servers - testen Sie es mit http://www.digicert.com/help/ oder ähnlichem, und es wird Ihnen sogar die Lösung mitteilen:

"Das Zertifikat ist nicht von einer vertrauenswürdigen Stelle signiert (Prüfung gegen Mozillas Stammspeicher). Wenn Sie das Zertifikat von einer vertrauenswürdigen Stelle gekauft haben, müssen Sie wahrscheinlich nur installieren ein oder mehrere Zwischenzertifikate . Wenden Sie sich an Ihren Zertifikatsanbieter, um Unterstützung für Ihre Serverplattform zu erhalten. "

Sie können das Zertifikat auch mit openssl überprüfen:

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

Sie werden wahrscheinlich sehen:

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

und früher in der Ausgabe:

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`

Die Zertifikatskette enthält nur 1 Element (Ihr Zertifikat):

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

... sollte aber die Unterzeichnungsbehörden in einer Kette auf eine verweisen, die von Android (Verisign, GlobalSign usw.) als vertrauenswürdig eingestuft wird:

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

Anweisungen (und die Zwischenzertifikate) zur Konfiguration Ihres Servers werden normalerweise von der Behörde bereitgestellt, die Ihr Zertifikat ausgestellt hat. Beispiel: http://www.alphassl.com/support/install-root-certificate.html =

Nach der Installation der von meinem Zertifikatsaussteller bereitgestellten Zwischenzertifikate treten bei der Verbindung über HttpsUrlConnection keine Fehler auf.

193
Stevie

Sie können einem bestimmten Zertifikat zur Laufzeit vertrauen.
Laden Sie es einfach vom Server herunter, legen Sie Assets ein und laden Sie diese mit ssl-utils-Android :

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

Im obigen Beispiel habe ich OkHttpClient verwendet, aber SSLContext kann mit jedem Client in Java verwendet werden.

Wenn Sie Fragen haben, können Sie gerne fragen. Ich bin der Autor dieser kleinen Bibliothek.

15
klimat

Update basierend auf der neuesten Android-Dokumentation (März 2017):

Wenn Sie diese Art von Fehler erhalten:

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)

das Problem könnte eines der folgenden sein:

  1. Die Zertifizierungsstelle, die das Serverzertifikat ausgestellt hat, war unbekannt 
  2. Das Serverzertifikat wurde nicht von einer Zertifizierungsstelle signiert, war jedoch selbst signiert 
  3. Bei der Serverkonfiguration fehlt eine Zwischenzertifizierungsstelle

Die Lösung besteht darin, HttpsURLConnection zu lehren, einem bestimmten Satz von CAs zu vertrauen. Wie? Bitte überprüfen Sie https://developer.Android.com/training/articles/security-ssl.html#CommonProblems

Andere, die AsyncHTTPClient aus der com.loopj.Android:android-async-http-Bibliothek verwenden, überprüfen die Option AsyncHttpClient für die Verwendung von HTTPS

11
user1506104

Antworten auf sehr alte Post. Aber vielleicht hilft es einigen Neulingen und wenn keiner der oben genannten klappt.

Erklärung: Ich weiß, dass niemand Erklärungssache will; eher die lösung. In einem Liner versuchen Sie jedoch, auf einen Dienst von Ihrem lokalen Computer zu einem Remote-Computer zuzugreifen, der Ihrem Computer nicht vertraut. Sie müssen die Vertrauensstellung vom Remote-Server anfordern. 

Lösung: Bei der folgenden Lösung wird davon ausgegangen, dass die folgenden Bedingungen erfüllt sind

  1. Versuch, von Ihrem lokalen Rechner aus auf eine Remote-API zuzugreifen.
  2. Sie bauen für Android App
  3. Ihr Remote-Server unterliegt der Proxy-Filterung (Sie verwenden Proxy in Ihren Browsereinstellungen, um auf den Remote-API-Dienst zuzugreifen, normalerweise einen Staging- oder Dev-Server).
  4. Sie testen auf einem echten Gerät

Schritte:

Sie benötigen eine .keystore-Erweiterungsdatei, um Ihre App zu registrieren. Wenn Sie nicht wissen, wie eine .keystore-Datei erstellt wird; Folgen Sie dann dem folgenden Abschnitt Abschnitt .keystore-Datei erstellen oder springen Sie zum nächsten Abschnitt Apk-Datei signieren

.keystore-Datei erstellen

Öffnen Sie Android Studio. Klicken Sie auf das Hauptmenü Erstellen> Generiert Signierte APK. Klicken Sie im nächsten Fenster auf die Schaltfläche Create new ... . In dem neuen Fenster geben Sie bitte Daten in alle Felder ein. Denken Sie daran, dass das Feld mit den zwei Kennwörtern, die ich empfehle, dasselbe Kennwort haben sollte. Verwenden Sie kein anderes Passwort. Denken Sie auch an den Speicherpfad am obersten Feld Schlüsselspeicherpfad: . Nachdem Sie alle Felder eingegeben haben, klicken Sie auf die Schaltfläche OK.

Apk-Datei signieren

Jetzt müssen Sie eine signierte App mit der soeben erstellten .keystore-Datei erstellen. Folge diesen Schritten

  1. Build> Projekt reinigen, warten, bis die Reinigung abgeschlossen ist
  2. Erstellen> Signierte APK generieren
  3. Klicken Sie auf die Schaltfläche Choose existing...
  4. Wählen Sie die gerade erstellte .keystore-Datei im Abschnitt Create .keystore-Datei aus
  5. Geben Sie dasselbe Kennwort ein, das Sie beim Erstellen in .keystore-Datei erstellen erstellt haben. Verwenden Sie dasselbe Kennwort für die Felder Key store password und Key password. Geben Sie auch den Alias ​​ein
  6. Klicken Sie auf die Schaltfläche Weiter
  7. Im nächsten Bildschirm; Je nachdem, welche Einstellungen Sie in build.gradle-Dateien vorgenommen haben, können Sie Build Types und Flavors auswählen.
  8. Für den Build Types wählen Sie release aus der Dropdown-Liste
  9. Für Flavors hängt es jedoch von Ihren Einstellungen in der build.gradle-Datei ab. Wählen Sie in diesem Feld staging aus. Ich habe die folgenden Einstellungen in build.gradle verwendet. Sie können dieselbe Einstellung wie meine verwenden. Stellen Sie jedoch sicher, dass Sie die applicationId in Ihren Paketnamen ändern

    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. Klicken Sie auf die beiden unteren Kontrollkästchen Signature Versions und klicken Sie auf die Schaltfläche Finish.

Fast dort:

Alle harte Arbeit ist getan, jetzt die Bewegung der Wahrheit. Um auf den durch Proxy gesicherten Staging-Server zuzugreifen, müssen Sie einige Einstellungen in Ihren echten Android-Geräten vornehmen. 

Proxy-Einstellung im Android-Gerät:

  1. Klicken Sie im Android-Telefon auf die Einstellung und dann auf WLAN
  2. Drücken Sie lange auf das verbundene WLAN und wählen Sie Modify network aus.
  3. Klicken Sie auf Advanced options, wenn Sie das Feld Proxy Hostname nicht sehen können
  4. Geben Sie in Proxy Hostname die Host-IP oder den Namen ein, zu dem Sie eine Verbindung herstellen möchten. Ein typischer Staging-Server wird als stg.api.mygoodcompany.com bezeichnet.
  5. Geben Sie für den Port die vierstellige Portnummer ein, zum Beispiel 9502
  6. Drücken Sie die Save-Taste

Eine letzte Station:

Denken Sie daran, dass wir die signierte apk-Datei im Abschnitt Sign APK File generiert haben. Nun ist es an der Zeit, diese APK-Datei zu installieren.

  1. Öffnen Sie ein Terminal und wechseln Sie in den signierten apk-Dateiordner
  2. Verbinden Sie Ihr Android-Gerät mit Ihrem Computer
  3. Entfernen Sie alle zuvor installierten APK-Dateien vom Android-Gerät
  4. adb installname of the apk file ausführen
  5. Wenn aus irgendeinem Grund der obige Befehl mit adb command not found zurückgegeben wird. Geben Sie den vollständigen Pfad als C:\Users\shah\AppData\Local\Android\sdk\platform-tools\adb.exeinstallname of the apk file ein.

Ich hoffe das Problem könnte gelöst werden. Wenn nicht, bitte hinterlassen Sie mir einen Kommentar.

Salam!

6
HA S

Die Fehlermeldung, die ich erhielt, war ähnlich, aber der Grund dafür war, dass das selbstsignierte Zertifikat abgelaufen war. Wenn der openssl-Client versucht wurde, gab er mir den Grund an, der bei der Überprüfung des Zertifikatdialogs von Firefox übersehen wurde.

Wenn sich das Zertifikat also im Schlüsselspeicher befindet und "GÜLTIG" ist, wird dieser Fehler im Allgemeinen ausgegeben.

4
MPN

Ich hatte das gleiche Problem bei der Verbindung vom Android-Client zum Kurento-Server . Der Kurento-Server verwendet Jks-Zertifikate, daher musste ich pem konvertieren . Als Eingabe für die Konvertierung verwendete ich die cert.pem-Datei, und es führte zu einer solchen Fehler . Wenn Sie jedoch fullchain.pem anstelle von cert.pem - verwenden, ist alles in Ordnung.

2
V.Poddubchak

Ich hatte das gleiche Problem. Ich fand heraus, dass die .crt-Datei des Zertifikats ein Zwischenzertifikat fehlte. Also habe ich alle .crt-Dateien von meinem Server-Admin gefragt und sie dann in umgekehrter Reihenfolge zusammengestellt.

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

in Windows habe ich ausgeführt copy Inter.crt + Root.crt newCertificate.crt

(Hier habe ich myCrt.crt ignoriert)

Dann habe ich die Datei newCertificate.crt über inputstream ..__ in den Code eingefügt.

2
sahan maldeniya

Ich weiß, dass Sie nicht allen Zertifikaten vertrauen müssen, aber in meinem Fall hatte ich Probleme mit einigen Debugging-Umgebungen, in denen wir selbstsignierte Zertifikate hatten und eine fehlerhafte Lösung brauchten. 

Ich musste nur die Initialisierung der sslContext ändern.

mySSLContext.init(null, trustAllCerts, null); 

wo trustAllCerts so erstellt wurde:

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

Ich hoffe, dass dies nützlich sein wird.

1
Adrian C.

Der Vertrauensankerfehler kann aus vielen Gründen auftreten. Für mich war es einfach nur der Versuch, auf https://example.com/ statt auf https://www.example.com/ zuzugreifen.

Sie sollten Ihre URLs daher noch einmal überprüfen, bevor Sie mit dem Aufbau Ihres eigenen Trust Managers beginnen (wie ich es tat).

1
Unkulunkulu

Wenn Sie Retrofit verwenden, müssen Sie Ihren OkHttpClient anpassen. 

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

Vollständiger Code ist wie folgt.

    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

Bei Gingerbread-Telefonen bekomme ich immer diese Fehlermeldung: Trust Anchor not found for Android SSL Connection, auch wenn ich mich auf mein Zertifikat stelle.

Hier ist der Code, den ich verwende (in Scala-Sprache):

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 _ ⇒
        }
    }
}

und hier ist der Verbindungscode:

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

Grundsätzlich kann ich meinem benutzerdefinierten Zertifikat vertrauen. Wenn dies fehlschlägt, deaktiviere ich die Sicherheit. Dies ist nicht die beste Option, aber die einzige Wahl, die ich mit alten und fehlerhaften Handys kenne.

Dieser Beispielcode kann leicht in Java übersetzt werden.

0
david.perez

In meinem Fall geschah dies nach dem Update auf Android 8.0. Das selbstsignierte Zertifikat, das Android als vertrauenswürdig eingestuft hatte, verwendete den Signaturalgorithmus SHA1withRSA. Der Wechsel zu einem neuen Zertifikat mit dem Signaturalgorithmus SHA256withRSA hat das Problem behoben.

0
Zds