5

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 ?

Community
  • 1
  • 1
Alok Kulkarni
  • 2,153
  • 19
  • 31

1 Answers1

3

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

    }
Alok Kulkarni
  • 2,153
  • 19
  • 31
  • I have 2 queries for this answer. One. Method WebViewClient.onReceivedClientCertRequest() is added in API Level 21(Lolipop), but you are saying that you have used this method on Android 4.0 and 4.1. Second. Did you find solution for Android 4.4 and above API level. Please reply? – Sagar Trehan Mar 29 '16 at 19:01
  • Sagar i have updated my answer for first part. I haven't checked for 4.4 above solution . – Alok Kulkarni Apr 22 '16 at 14:48
  • Hi, i have to do the same but the private key is in a cryptographic token. ho can i use it? – Indio Jan 13 '18 at 16:29
  • You need to check on how to take out Private key from token , rest of the steps shd be same as above – Alok Kulkarni Feb 15 '18 at 06:38