2016-04-11 2 views
15

signiert ist. Ich möchte die onReceivedSslError() einer WebViewClient überschreiben. Hier möchte ich überprüfen, ob das error.getCertificate() Zertifikat von einer selbstsignierten CA signiert ist und nur in diesem Fall, rufen Sie die handler.proceed(). In Pseudo-Code:Überprüfen Sie in der onReceivedSslError() - Methode eines WebViewClient, wenn ein Zertifikat von einer bestimmten selbstsignierten CA

@Override 
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 
    SslCertificate serverCertificate = error.getCertificate(); 

    if (/* signed from my self-signed CA */) { 
     handler.proceed(); 
    } 
    else { 
     super.onReceivedSslError(view, handler, error); 
    } 
} 

Der öffentliche Schlüssel meines CA in einer BouncyCastle Ressource gespeichert wird aufgerufen rootca.bks. Wie kann ich?

Antwort

0

basierend auf Dokumentation:

Haben Sie versucht, die Methode getIssuedBy().getDName() der Klasse SSLCertificate verwenden. Diese Methode gibt einen String zurück, der "Die Entität, die dieses Zertifikat ausgestellt hat" darstellt.

einen Blick hier nehmen: http://developer.android.com/reference/android/net/http/SslCertificate.html#getIssuedBy()

Dann brauchen Sie nur wich Zeichenfolge wissen, zurückgegeben wird, wenn es sich von selbst unterzeichnet ist.

EDIT: Ich denke, wenn es selbstsignierten ist, dass leere Zeichenfolge zurückgeben sollte, und wenn nicht, würde es das Unternehmen

Grüße

+1

Das ist keine gute Lösung. Jeder kann diesen Namen "fälschen". Da wir den öffentlichen Schlüssel der Stammzertifizierungsstelle haben, ist es die richtige Lösung zu überprüfen, ob das Zertifikat von ihm signiert ist. Und das bringt uns zurück zur ursprünglichen Frage ... – Dev

+0

Guten Morgen! nur zur Selbstinformation, wie könnte das irgendjemand einstellen? Für diesen Wert gibt es keine festgelegten Methoden. Grüße – Oldskultxo

+0

sowieso, wenn Sie die Weg-Bedingung ändern, könnte es Ihr Problem zu beheben, nur überprüfen, ob ... getDName gleich Ihrem bekannten Zertifizierer Einheit. Oder vielleicht verstehe ich dein Problem nicht ok. Entschuldigung, wenn das das Problem ist – Oldskultxo

2

Ich denke zurückkehren sollte dies funktionieren (SSL_IDMISMATCH Mittel „Hostname mismatch“).

@Override 
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 
    SslCertificate serverCertificate = error.getCertificate(); 

    if (error.hasError(SSL_UNTRUSTED)) { 
     // Check if Cert-Domain equals the Uri-Domain 
     String certDomain = serverCertificate.getIssuedTo().getCName(); 
     if(certDomain.equals(new URL(error.getUrl()).getHost())) { 
      handler.proceed(); 
     } 
    } 
    else { 
     super.onReceivedSslError(view, handler, error); 
    } 
} 

Wenn "hasError()" ist nicht, versuchen Sie error.getPrimaryError() == SSL_IDMISMATCH

prüfen Documentation of SslError für alle Fehlertypen zu arbeiten.

EDIT: Ich testete die Funktion auf meinem eigenen Self-Cert-Server (es ist ein Xampp), und ich habe Fehler # 3. Das bedeutet, dass Sie nach error.hasError(SslError.SSL_UNTRUSTED) für ein selbstsigniertes Zertifikat suchen müssen.

+1

Leider beantwortet das nicht die ursprüngliche Frage.Ich möchte nicht überprüfen, ob die Zertifizierungsstelle nicht vertrauenswürdig ist, und in diesem Fall fortfahren (wodurch die Verwendung von SSL aufgehoben wird), aber ich möchte überprüfen, ob das Zertifikat von einer selbstsignierten Zertifizierungsstelle signiert ist, von der ich weiß Öffentlicher Schlüssel. – Dev

+0

Sie können hinzufügen hinzufügen einen Scheck: 'serverCertificate.getIssuedTo(). GetCName(). Equals (neue URL (error.getUrl()). GetHost())' – Radon8472

11

Ich glaube, Sie als das folgende versuchen:

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    try { 
     WebView webView = (WebView) findViewById(R.id.webView); 
     if (webView != null) { 
      // Get cert from raw resource... 
      CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
      InputStream caInput = getResources().openRawResource(R.raw.rootca); // stored at \app\src\main\res\raw 
      final Certificate certificate = cf.generateCertificate(caInput); 
      caInput.close(); 

      String url = "https://www.yourserver.com"; 
      webView.setWebViewClient(new WebViewClient() {      
       @Override 
       public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { 
        // Get cert from SslError 
        SslCertificate sslCertificate = error.getCertificate(); 
        Certificate cert = getX509Certificate(sslCertificate); 
        if (cert != null && certificate != null){ 
         try { 
          // Reference: https://developer.android.com/reference/java/security/cert/Certificate.html#verify(java.security.PublicKey) 
          cert.verify(certificate.getPublicKey()); // Verify here... 
          handler.proceed(); 
         } catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) { 
          super.onReceivedSslError(view, handler, error); 
          e.printStackTrace(); 
         } 
        } else { 
         super.onReceivedSslError(view, handler, error); 
        } 
       } 
      }); 

      webView.loadUrl(url); 
     } 
    } catch (Exception e){ 
     e.printStackTrace(); 
    } 
} 

// credits to @Heath Borders at http://stackoverflow.com/questions/20228800/how-do-i-validate-an-android-net-http-sslcertificate-with-an-x509trustmanager 
private Certificate getX509Certificate(SslCertificate sslCertificate){ 
    Bundle bundle = SslCertificate.saveState(sslCertificate); 
    byte[] bytes = bundle.getByteArray("x509-certificate"); 
    if (bytes == null) { 
     return null; 
    } else { 
     try { 
      CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 
      return certFactory.generateCertificate(new ByteArrayInputStream(bytes)); 
     } catch (CertificateException e) { 
      return null; 
     } 
    } 
} 

Wenn Fehler bei der Überprüfung, logcat einige Informationen haben wie java.security.SignatureException: Signature was not verified...

Wenn Erfolg, hier ein Screenshot:

BNK's screenshot

+1

Ja! Diese Lösung funktioniert tatsächlich und sieht für mich sicher aus - sie überprüft, ob das Serer-Zertifikat tatsächlich mit dem CA-Schlüssel signiert ist (mit dem öffentlichen CA-Schlüssel). Vielen Dank!!! :-) – johndodo

+0

was soll ich hier behalten -> R.raw.rootca? –

+0

@ jeet.chanchawat es ist cert-Datei, zum Beispiel "rootca.crt", finden Sie weitere Informationen unter https://developer.android.com/training/articles/security-ssl.html#UnknownCa – BNK

Verwandte Themen