Android WebView handle onReceivedClientCertRequest

浪子不回头ぞ 提交于 2019-12-03 09:32:42

问题


I'm developing an Android app using Client Certificate Authentication within WebView. The certificate (cert.pfx) and password are embedded in the application.

When executing Client Certificate Authentication request with ajax call in the WebView, the following function getting called :

@Override
public void onReceivedClientCertRequest(WebView view, final ClientCertRequest request) {}

As I understend I need to call :

request.proceed(PrivateKey privateKey, X509Certificate[] chain)

Any idea how to create the PrivateKey and X509Certificate objects from the embedded certificate in order to proceed with the request. BTW, is this the correct way to implement Client Certificate Authentication on Android app ? if no, please advice.


回答1:


Solved it using KeyStore to obtain the PrivateKey and X509Certificate objects :

    private X509Certificate[] mCertificates;
    private PrivateKey mPrivateKey;

    private void loadCertificateAndPrivateKey() {
          try {
                InputStream certificateFileStream = getClass().getResourceAsStream("/assets/cert.pfx");

                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                String password = "password";
                keyStore.load(certificateFileStream, password != null ? password.toCharArray() : null);

                Enumeration<String> aliases = keyStore.aliases();
                String alias = aliases.nextElement();

                Key key = keyStore.getKey(alias, password.toCharArray());
                if (key instanceof PrivateKey) {
                    mPrivateKey = (PrivateKey)key;
                    Certificate cert = keyStore.getCertificate(alias);
                    mCertificates = new X509Certificate[1];
                    mCertificates[0] = (X509Certificate)cert;
                 }

                 certificateFileStream.close();

            } catch (Exception e) {
                 Log.e(TAG, e.getMessage());
         }
    }


    private WebViewClient mWebViewClient = new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return false;
        }

        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            handler.proceed();
        }

        @Override
        public void onReceivedClientCertRequest(WebView view, final ClientCertRequest request) {
            if (mCertificates == null || mPrivateKey == null) {
                loadCertificateAndPrivateKey();
            } 
            request.proceed(mPrivateKey, mCertificates);
        }
    };



回答2:


I encountered the same problem, and I have resolved in this way :

private void initPrivateKeyAndX509Certificate(int clientCertResourceId, String clientCertPassword) throws UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException {
        try {
            InputStream certificateFileStream = null;
            if (clientCertResourceId > 0) {
                certificateFileStream = new ByteArrayInputStream(Utility.readbyteFromResources(clientCertResourceId, MYApplication.getAppContext()));
            }

            if (certificateFileStream != null) {
                KeyStore keyStore = KeyStore.getInstance("PKCS12");
                keyStore.load(certificateFileStream, clientCertPassword != null ? clientCertPassword.toCharArray() : null);

                Enumeration<String> aliases = keyStore.aliases();

                while (aliases.hasMoreElements()) {
                    String alias = aliases.nextElement();
                    Key key = keyStore.getKey(alias, clientCertPassword.toCharArray());
                    if (key instanceof PrivateKey) {
                        mPrivateKey = (PrivateKey) key;
                        Certificate[] arrayOfCertificate = keyStore.getCertificateChain(alias);
                        mCertificates = new X509Certificate[arrayOfCertificate.length];
                        for (int i = 0; i < mCertificates.length; i++) {
                            mCertificates[i] = ((X509Certificate) arrayOfCertificate[i]);
                        }
                        break;
                    }
                }

                certificateFileStream.close();
            }

        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            throw e;
        }
    }

Where the clientCertResourceId is the resourceId related of the p12 which is in raw folder. Then I have overrided the onReveicedClientCertRequest in this way :

@Override
    public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
        if (mPrivateKey != null && mCertificates != null && mCertificates.length != 0) {
            request.proceed(mPrivateKey, mCertificates);
        } else {
            request.cancel();
        }
    }

I wondering if this way to do is the correct one, but currently it works



来源:https://stackoverflow.com/questions/35135225/android-webview-handle-onreceivedclientcertrequest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!