Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Webview Client Certificate, Mutual Auth, SSL over Webview

I have a Webpage which requires Mutual auth to load the page. I get onReceivedError() with ERROR_FAILED_SSL_HANDSHAKE. In the logs "Could not establish a secure connection" is printed by Webkit. I have searched extensively but could not find an answer. There are several posts but nothing conclusive. I tried all 3 solutions posted here. The solution likely to work was :- Solution 1: use ClientCertRequestHandler anyway (It's marked as hidden, but apparently still usable):

So i modified the android.jar to include the internal API for overriding onReceivedClientCertRequest() But i am not getting the callback at runtime. Same is the case with any third party browser. I tried loading the same webpage in a standard browser. I got a callback on UI asking the User to select a Client certificate.

So seems that only system browser app can get the callback for onReceivedClientCertRequest() from Webkit.

In case of iOS platform, Webview cannot directly load the site too . But making an HTTPS Connection using NSURL , keeps the Client certificate in memory for some time and Webview can load this page successfully.

On Android i have successfully setup HTTPS communication by registering an SSLSocketFactory loading Client and Server certificates. I can do REST API calls using that.However unlike iOS, i cannot find a way in which Android webview can use the Client certificate for Mutual auth.

I think having Mutual auth over a Webview should be supported by the platform as one of the basic requirements for security. Is there any update on this issue ?

EDIT 1 :

I got it working on Android 4.0 to 4.3 as per my answer given below. Hoverer , now on Android 4.4 , seems that WebViewClientClassicExt class itself is removed. Any idea what can be done in this case ? Why is Android not allowing setting ClientCertificates in webview ?

like image 451
Alok Kulkarni Avatar asked Oct 21 '22 18:10

Alok Kulkarni


1 Answers

So i could get this thing working until 4.3

  1. On Android 4.0 and 4.1 ,by overriding onReceivedClientCertRequest() of a class extending WebViewClient
  2. On 4.2 , 4.3 by overriding onReceivedClientCertRequest() of a class extending WebViewClientClassicExt.

I set the Private key and certificates ClientCertRequestHandler proceed() method.

Need a fix patch from Android for 4.4 and above

EDITED Solutions uptil 4.3 are given below

WebviewClientCustom.java

public class WebViewClientCustom extends WebViewClient {
    private X509Certificate[] certificatesChain;
    private PrivateKey clientCertPrivateKey;
    private IWebViewCallbacks webviewCallbacks;

    public WebViewClientCustom(IWebViewCallbacks webviewCallbacks) {
        this.webviewCallbacks = webviewCallbacks;
    }

    public void onReceivedClientCertRequest(WebView paramWebView,
            ClientCertRequestHandler paramClientCertRequestHandler,
            String paramString) {
        PrivateKey localPrivateKey = this.clientCertPrivateKey;
        X509Certificate[] arrayOfX509Certificate = this.certificatesChain;
        paramClientCertRequestHandler.proceed(localPrivateKey,
                arrayOfX509Certificate);
    }

    public void onReceivedError(WebView view, int errorCode,
            String description, String failingUrl) {
        webviewCallbacks.onReceivedError( view,  errorCode,
                 description,  failingUrl);

        super.onReceivedError( view,  errorCode,
                 description,  failingUrl);
    }


    public void setClientCertificate(PrivateKey paramPrivateKey,
            X509Certificate[] paramArrayOfX509Certificate) {
        this.clientCertPrivateKey = paramPrivateKey;
        this.certificatesChain = paramArrayOfX509Certificate;
    }

    public boolean shouldOverrideUrlLoading(WebView paramWebView,
            String paramString) {
        return webviewCallbacks.shouldOverrideUrlLoading(paramWebView,
                paramString);


    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        // TODO Auto-generated method stub

        webviewCallbacks.onPageStarted(view, url, favicon);
        super.onPageStarted(view, url, favicon);
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        // TODO Auto-generated method stub

        webviewCallbacks.onPageFinished(view, url);
        super.onPageFinished(view, url);
    }

}

WebViewClientCustomExt.java

public class WebViewClientCustomExt extends WebViewClientClassicExt {
    private X509Certificate[] certificatesChain;
    private PrivateKey clientCertPrivateKey;
    private IWebViewCallbacks webviewCallbacks;

    public WebViewClientCustomExt(IWebViewCallbacks webviewCallbacks) {
        this.webviewCallbacks = webviewCallbacks;
    }

    public void onReceivedClientCertRequest(WebView paramWebView,
            ClientCertRequestHandler paramClientCertRequestHandler,
            String paramString) {
        PrivateKey localPrivateKey = this.clientCertPrivateKey;
        X509Certificate[] arrayOfX509Certificate = this.certificatesChain;
        paramClientCertRequestHandler.proceed(localPrivateKey,
                arrayOfX509Certificate);
    }

    public void onReceivedError(WebView view, int errorCode,
            String description, String failingUrl) {
        webviewCallbacks.onReceivedError( view,  errorCode,
                 description,  failingUrl);

        super.onReceivedError( view,  errorCode,
                 description,  failingUrl);
    }



    public void setClientCertificate(PrivateKey paramPrivateKey,
            X509Certificate[] paramArrayOfX509Certificate) {
        this.clientCertPrivateKey = paramPrivateKey;
        this.certificatesChain = paramArrayOfX509Certificate;
    }

    public boolean shouldOverrideUrlLoading(WebView paramWebView,
            String paramString) {
        return webviewCallbacks.shouldOverrideUrlLoading(paramWebView, paramString);
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        // TODO Auto-generated method stub


        webviewCallbacks.onPageStarted(view, url, favicon);
        super.onPageStarted(view, url, favicon);
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        // TODO Auto-generated method stub

        webviewCallbacks.onPageFinished(view, url);
        super.onPageFinished(view, url);
    }
}

Usage

 */
    private void setCertificateData() {
        // TODO Auto-generated method stub
        try {
            KeyStore clientCertKeystore = KeyStore.getInstance("pkcs12");
            String clientCertPkcsPassword = getPkcsPassword();
            byte[] pkcs12;

            pkcs12 = getAuthP12Data();
            ByteArrayInputStream pkcs12BAIS = new ByteArrayInputStream(pkcs12);

            clientCertKeystore.load(pkcs12BAIS,
                    clientCertPkcsPassword.toCharArray());
            String alias = (clientCertKeystore.aliases().nextElement());
            Certificate[] arrayOfCertificate = clientCertKeystore
                    .getCertificateChain(alias);
            X509Certificate[] arrayOfX509Certificate = new X509Certificate[arrayOfCertificate.length];
            for (int i = 0; i < arrayOfCertificate.length; i++) {
                arrayOfX509Certificate[i] = (X509Certificate) arrayOfCertificate[i];
            }
            PrivateKey localPrivateKey = (PrivateKey) clientCertKeystore
                    .getKey(alias, clientCertPkcsPassword.toCharArray());
            if (android.os.Build.VERSION.SDK_INT <= 16) {
                WebViewClientCustom webvviewClient = new WebViewClientCustom(
                        myWebViewClient);
                webvviewClient.setClientCertificate(localPrivateKey,
                        arrayOfX509Certificate);
                webView.setWebViewClient(webvviewClient);

            } else {
                WebViewClientCustomExt webvviewClient = new WebViewClientCustomExt(
                        myWebViewClient);
                webvviewClient.setClientCertificate(localPrivateKey,
                        arrayOfX509Certificate);
                webView.setWebViewClient(webvviewClient);
            }
            // webView.getSettings().setJavaScriptEnabled(true);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
like image 194
Alok Kulkarni Avatar answered Oct 28 '22 22:10

Alok Kulkarni