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