我正在使用WebView中的客户端证书身份验证开发Android应用。证书(cert.pfx)和密码嵌入在应用程序中。
在WebView中执行带有ajax调用的客户端证书身份验证请求时,将调用以下函数:
@Override
public void onReceivedClientCertRequest(WebView view, final ClientCertRequest request) {}
正如我所说,我需要打电话:
request.proceed(PrivateKey privateKey, X509Certificate[] chain)
任何想法如何从嵌入式证书创建PrivateKey和X509Certificate对象以继续请求。 顺便说一句,这是在Android应用程序上实现客户端证书身份验证的正确方法吗?如果没有,请通知。
答案 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();
}
}
我想知道这种方法是否正确,但目前可行