Skip to content Skip to sidebar Skip to footer

Check In The Onreceivedsslerror() Method Of A Webviewclient If A Certificate Is Signed From A Specific Self-signed Ca

I would like to override the onReceivedSslError() of a WebViewClient. Here I want to check if the error.getCertificate() certificate is signed from a self-signed CA and, only in th

Solution 1:

I think you can try as the following:

@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

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

            Stringurl="https://www.yourserver.com";
            webView.setWebViewClient(newWebViewClient() {                    
                @OverridepublicvoidonReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                    // Get cert from SslErrorSslCertificatesslCertificate= error.getCertificate();
                    Certificatecert= 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-x509trustmanagerprivate Certificate getX509Certificate(SslCertificate sslCertificate){
    Bundlebundle= SslCertificate.saveState(sslCertificate);
    byte[] bytes = bundle.getByteArray("x509-certificate");
    if (bytes == null) {
        returnnull;
    } else {
        try {
            CertificateFactorycertFactory= CertificateFactory.getInstance("X.509");
            return certFactory.generateCertificate(newByteArrayInputStream(bytes));
        } catch (CertificateException e) {
            returnnull;
        }
    }
}

If failed validation, logcat will have some information such as java.security.SignatureException: Signature was not verified...

If success, here's a screenshot:

BNK's screenshot

Solution 2:

I think this should work (SSL_IDMISMATCH means "Hostname mismatch").

@OverridepublicvoidonReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    SslCertificateserverCertificate= error.getCertificate();

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

If "hasError()" is not working, try error.getPrimaryError() == SSL_IDMISMATCH

Check Documentation of SslError for all error-types.

EDIT: I tested the function on my own self-cert server (its a Xampp), and I got Error #3. That means you have to check for error.hasError(SslError.SSL_UNTRUSTED) for a self-signed cert.

Solution 3:

based on documentation:

Have you tried using the method getIssuedBy().getDName() of class SslCertificate. This method returns a String representing "The entity that issued this certificate".

Take a look here: http://developer.android.com/reference/android/net/http/SslCertificate.html#getIssuedBy()

Then you just need to know wich string is returned when it is self signed.

EDIT: I think that if it is selfsigned, that should return empty string, and if not, it would return the entity

Regards

Post a Comment for "Check In The Onreceivedsslerror() Method Of A Webviewclient If A Certificate Is Signed From A Specific Self-signed Ca"