2015-08-10 8 views
10

Ich habe seit Tagen versucht, das funktioniert zu bekommen. Ich versuche, eine Verbindung zu meinem Server über https mit einem selbst signierten Zertifikat herzustellen. Ich glaube nicht, dass es Seiten oder Beispiele gibt, die ich noch nicht gelesen habe.OkHttp javax.net.ssl.SSLPeerUnverifiedException: Hostname domain.com nicht verifiziert

Was ich getan habe:

  1. Erstellt bks Schlüsselspeicher von diesem Tutorial folgenden: http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html

Es verwendet openssl s_client -connect domain.com:443 das Zertifikat vom Server zu erhalten. Dann erstellt einen bks Keystore mit Hüpfburg.

  1. Lesen erstellt Keystore aus Raw-Ordner, fügen Sie es zu sslfactory und dann zu OkHttpClient. Wie folgt aus:

    public ApiService() { 
        mClient = new OkHttpClient(); 
        mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); 
        mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); 
        mClient.setCache(getCache()); 
        mClient.setCertificatePinner(getPinnedCerts()); 
        mClient.setSslSocketFactory(getSSL()); 
    } 
    
    protected SSLSocketFactory getSSL() { 
        try { 
         KeyStore trusted = KeyStore.getInstance("BKS"); 
         InputStream in = Beadict.getAppContext().getResources().openRawResource(R.raw.mytruststore); 
         trusted.load(in, "pwd".toCharArray()); 
         SSLContext sslContext = SSLContext.getInstance("TLS"); 
         TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
         trustManagerFactory.init(trusted); 
         sslContext.init(null, trustManagerFactory.getTrustManagers(), null); 
         return sslContext.getSocketFactory(); 
        } catch(Exception e) { 
         e.printStackTrace(); 
        } 
        return null; 
    } 
    
    public CertificatePinner getPinnedCerts() { 
        return new CertificatePinner.Builder() 
          .add("domain.com", "sha1/theSha=") 
          .build(); 
    } 
    
  2. dieser aus irgendeinem Grund erzeugt dies immer eine SSLPeerUnverifiedException mit oder ohne Schlüsselspeicher. Und mit oder ohne CertificatePinner.

    javax.net.ssl.SSLPeerUnverifiedException: Hostname domain.com not verified: 0   
    W/System.err﹕ certificate: sha1/theSha= 
    W/System.err﹕ DN: 1.2.840.113549.1.9.1=#1610696e666f40626561646963742e636f6d,CN=http://domain.com,OU=development,O=domain,L=Valencia,ST=Valencia,C=ES 
    W/System.err﹕ subjectAltNames: [] 
    W/System.err﹕ at com.squareup.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:124) 
    W/System.err﹕ at com.squareup.okhttp.Connection.connect(Connection.java:143) 
    W/System.err﹕ at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:185) 
    W/System.err﹕ at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128) 
    W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341) 
    W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330) 
    W/System.err﹕ at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248) 
    W/System.err﹕ at com.squareup.okhttp.Call.getResponse(Call.java:273) 
    W/System.err﹕ at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:230) 
    W/System.err﹕ at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:201) 
    W/System.err﹕ at com.squareup.okhttp.Call.execute(Call.java:81) 
    ... 
    

Was mache ich falsch?

+3

Bitte überprüfen Sie, dass Ihr Zertifikat tatsächlichen Host-Namen und nicht IP-Adresse enthält (IP-Adressen sollen im 'Antragstellernamen 'Feld des Zertifikats sein). Wie bei 'HostnameVerifier', was" True "zurückgibt, wird SSL nutzlos und unsicher (die meisten Uploads). Auf modernen Android-Geräten können Sie Ihr selbstsigniertes Zertifikat problemlos über Sicherheitseinstellungen installieren. –

Antwort

8

Ich habe endlich das funktioniert mit einer Mischung aus mehreren Antworten.

Erstens, die Zertifikate wurden falsch gemacht, nicht sicher, wie. Aber indem Sie sie mit dem Skript in this answer erstellt haben, haben sie funktioniert. Was benötigt wurde, war ein Serverzertifikat und ein Schlüssel. Dann benötigte der Client ein anderes Zertifikat.

Um das Zertifikat in Android verwende ich die .pem-Datei in eine .crt-Datei wie folgt umgerechnet:

openssl x509 -outform der -in client.pem -out client.crt 

In android Ich habe das Zertifikat zu meinem OkHttp Client wie folgt aus:

public ApiService() { 
    mClient = new OkHttpClient(); 
    mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); 
    mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS); 
    mClient.setCache(getCache()); 
    mClient.setSslSocketFactory(getSSL()); 
} 

protected SSLSocketFactory getSSL() { 
    try { 
     CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
     InputStream cert = getAppContext().getResources().openRawResource(R.raw.client); 
     Certificate ca = cf.generateCertificate(cert); 
     cert.close(); 

     // creating a KeyStore containing our trusted CAs 
     String keyStoreType = KeyStore.getDefaultType(); 
     KeyStore keyStore = KeyStore.getInstance(keyStoreType); 
     keyStore.load(null, null); 
     keyStore.setCertificateEntry("ca", ca); 

     return new AdditionalKeyStore(keyStore); 
    } catch(Exception e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

Der letzte Teil mit new AdditionalKeyStore() stammt aus this very well written answer. Dies fügt einen Fallback-Keystore hinzu.

Ich hoffe, dass dies jemand anderen helfen kann! Dies ist der einfachste Weg, HTTPS mit einem selbstsignierten Zertifikat zu arbeiten, das ich gefunden habe. Andere Möglichkeiten schließen ein, einen BouncyCastle Schlüsselspeicher zu haben, der zu mir übermäßig scheint.

+0

Was ist die Datei (Client) in roh? – JUL2791

+0

Das ist die 'client.crt'Datei, die in der openssl-Zeile generiert wird. –

+0

Was ist die Datei client.pem, die Sie hier verwendet haben? Dieses Skript generiert wenige .pem-Datei. Ist es chain.pem Datei im Client-Verzeichnis? – Chrishan

15

Ich hatte das gleiche Problem, aber ich brauchte meine Anwendung auf mehreren Staging-Umgebungen zu arbeiten, von denen alle selbst signierte Zertifikate hatten. Um die Sache noch schlimmer zu machen, könnten sie diese Zertifikate im laufenden Betrieb ändern.

Um dies zu beheben, habe ich bei der Verbindung nur zum Staging eine SSLSocketFactory hinzugefügt, die allen Zertifikaten vertraut. Das hat den Java-Fehler behoben, aber es hat mich mit der okhttp-Ausnahme verlassen, die in diesem Ticket notiert ist.

Um diesen Fehler zu vermeiden, musste ich meinem okHttpClient eine weitere Anpassung hinzufügen. Dies hat den Fehler für mich behoben.

okHttpClient.setHostnameVerifier(new HostnameVerifier() { 
      @Override 
      public boolean verify(String hostname, SSLSession session) { 
       return true; 
      } 
     }); 
+5

Dies ist nicht sicher ! Ich weiß, dass ich das in meiner Frage nicht angegeben habe. Ich weiß, es funktioniert, ich habe es früher benutzt. Aber ich bin jetzt erwachsen geworden und will die volle Sicherheit von https. :) –

+0

natürlich ist das nicht sicher - dies umgeht explizit HTTPS Zertifikat Verifikation. Dies sollte nur in Pre-Prod-Umgebungen verwendet werden, in denen Sie die SSL-Verifizierung vermeiden möchten, niemals in einem Produktions-Build. –

+0

'setHostnameVerifier' nicht kompiliert –

6

Dieses Problem wird durch setHostNameVerifier-okHttpBuilder Einstellung gelöst. Stellen Sie sicher, dass die Überprüfungsmethode true zurückgibt.

Probe:

okHttpClient.setHostnameVerifier(new HostnameVerifier() { 
    @Override 
    public boolean verify(String hostname, SSLSession session) { 
     return true; 
    } 
}); 

OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
    builder.hostnameVerifier(new HostnameVerifier() { 
     @Override 
     public boolean verify(String hostname, SSLSession session) { 
      return true; 
     } 
    }); 
OkHttpClient client = builder.build(); 
+0

Wie sicher ist das? Wenn es wahr zurückgibt, werden nicht alle Zertifikate akzeptiert? Wenn ja, sollte das vermieden werden! –

+0

Ich stimme @just_user zu. Das funktioniert, ist aber keine gute Lösung. Recht...? – Otziii

+0

@Otziii Ja, das ist nicht sicher. Ich weiß nicht, warum die Leute diese "Lösung" vorschlagen. Überprüfen Sie meine Antwort oben, dies bietet eine sicherere Option. –

0

Bitte überprüfen Sie, ob CN Name auf dem Client-Zertifikat auf den Alternativen Namen hinzugefügt wird. Ich hatte das gleiche Problem

Verwandte Themen