Android WebView处理onReceivedClientCertRequest

时间:2016-02-01 16:17:51

标签: android ssl webview client-certificates

我正在使用WebView中的客户端证书身份验证开发Android应用。证书(cert.pfx)和密码嵌入在应用程序中。

在WebView中执行带有ajax调用的客户端证书身份验证请求时,将调用以下函数:

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

正如我所说,我需要打电话:

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

任何想法如何从嵌入式证书创建PrivateKey和X509Certificate对象以继续请求。 顺便说一句,这是在Android应用程序上实现客户端证书身份验证的正确方法吗?如果没有,请通知。

2 个答案:

答案 0 :(得分:13)

使用KeyStore解决它以获取PrivateKey和X509Certificate对象:

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

答案 1 :(得分:0)

我遇到了同样的问题,并且已经通过以下方式解决了:

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

其中clientCertResourceId是与原始文件夹中的p12相关的resourceId。 然后,我以这种方式覆盖了onReveicedClientCertRequest:

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

我想知道这种方法是否正确,但目前可行