我的应用程序使用 https 连接到服务器,对于使用自签名证书的服务器,webview 将调用其 onReceivedSslError 方法。我需要响应回调并显示一个可见的对话框来显示证书信息,尤其是 sha1 和 sha256 指纹。但是我对获得它们感到非常困惑,因为SslCertificate不支持任何getFingerprint方法。有什么想法吗?
onReceivedSslError 方法如下所示。
@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
Log.d(DEBUG_TAG, "onReceivedSslError " + error.getCertificate().toString());
// error.getCertificate().getSha1FingerPrint(); is not available
// below methods are available
// error.getCertificate().getIssuedBy();
// error.getCertificate().getIssuedTo();
// error.getCertificate().getValidNotAfterDate();
// error.getCertificate().getValidNotBeforeDate();
// error.getUrl();
if (error.getPrimaryError() == SslError.SSL_UNTRUSTED) {
final Account account = new Account(serverUrl, null, null);
SslConfirmDialog dialog = new SslConfirmDialog(account,
new SslConfirmDialog.Listener() {
@Override
public void onAccepted(boolean rememberChoice) {
CertsManager.instance().saveCertForAccount(account, rememberChoice);
// Ignore SSL certificate validate
handler.proceed();
}
@Override
public void onRejected() {
displaySSLError();
}
});
dialog.show(getSupportFragmentManager(), SslConfirmDialog.FRAGMENT_TAG);
return;
}
}
您可以执行此类操作来获取 X509 证书
public void onReceivedSslError(WebView view, SslErrorHandler handler,
SslError error) {
Bundle bundle = SslCertificate.saveState(error.getCertificate());
X509Certificate certificate;
byte[] bytes = bundle.getByteArray("x509-certificate");
if (bytes == null) {
certificate = null;
} else {
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
certificate = (X509Certificate) cert;
} catch (CertificateException e) {
certificate = null;
}
}
}
拥有 X509Certificate 后,您可以使用 X509TCertificate 的 getEncoded() API 获取指纹。
礼貌 : http://grepcode.com/file/repo1.maven.org/maven2/org.robolectric/android-all/4.3_r2-robolectric-0/android/net/http/SslCertificate.java#SslCertificate.restoreState%28android.os.Bundle%29
SslCertificate 类没有底层 X509TCertificate 的公共获取器,我们只能通过 hack 来做到这一点。这仅适用于 andorid 4.0+。所以我通过下面的一个小技巧解决了这个问题。
/**
* SslCertificate class does not has a public getter for the underlying
* X509Certificate, we can only do this by hack. This only works for andorid 4.0+
* @see https://groups.google.com/forum/#!topic/android-developers/eAPJ6b7mrmg
*/
public static X509Certificate getX509CertFromSslCertHack(SslCertificate sslCert) {
X509Certificate x509Certificate = null;
Bundle bundle = SslCertificate.saveState(sslCert);
byte[] bytes = bundle.getByteArray("x509-certificate");
if (bytes == null) {
x509Certificate = null;
} else {
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(bytes));
x509Certificate = (X509Certificate) cert;
} catch (CertificateException e) {
x509Certificate = null;
}
}
return x509Certificate;
}