Dev*_*Dev 16 android ca self-signed ssl-certificate webviewclient
我想覆盖onReceivedSslError()一个WebViewClient.在这里,我想检查error.getCertificate()证书是否是从自签名CA签名的,只有在这种情况下,才能调用handler.proceed().在伪代码中:
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
SslCertificate serverCertificate = error.getCertificate();
if (/* signed from my self-signed CA */) {
handler.proceed();
}
else {
super.onReceivedSslError(view, handler, error);
}
}
Run Code Online (Sandbox Code Playgroud)
我的CA的公钥保存在名为的BouncyCastle资源中rootca.bks.我能怎么做?
BNK*_*BNK 19
我想你可以尝试如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
WebView webView = (WebView) findViewById(R.id.webView);
if (webView != null) {
// Get cert from raw resource...
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.rootca); // stored at \app\src\main\res\raw
final Certificate certificate = cf.generateCertificate(caInput);
caInput.close();
String url = "https://www.yourserver.com";
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// Get cert from SslError
SslCertificate sslCertificate = error.getCertificate();
Certificate cert = getX509Certificate(sslCertificate);
if (cert != null && certificate != null){
try {
// Reference: https://developer.android.com/reference/java/security/cert/Certificate.html#verify(java.security.PublicKey)
cert.verify(certificate.getPublicKey()); // Verify here...
handler.proceed();
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) {
super.onReceivedSslError(view, handler, error);
e.printStackTrace();
}
} else {
super.onReceivedSslError(view, handler, error);
}
}
});
webView.loadUrl(url);
}
} catch (Exception e){
e.printStackTrace();
}
}
// credits to @Heath Borders at http://stackoverflow.com/questions/20228800/how-do-i-validate-an-android-net-http-sslcertificate-with-an-x509trustmanager
private Certificate getX509Certificate(SslCertificate sslCertificate){
Bundle bundle = SslCertificate.saveState(sslCertificate);
byte[] bytes = bundle.getByteArray("x509-certificate");
if (bytes == null) {
return null;
} else {
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return certFactory.generateCertificate(new ByteArrayInputStream(bytes));
} catch (CertificateException e) {
return null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果验证失败,logcat将会有一些信息,例如 java.security.SignatureException: Signature was not verified...
如果成功,这是一个截图:
我认为这应该有效(SSL_IDMISMATCH意思是“主机名不匹配”)。
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
SslCertificate serverCertificate = error.getCertificate();
if (error.hasError(SSL_UNTRUSTED)) {
// Check if Cert-Domain equals the Uri-Domain
String certDomain = serverCertificate.getIssuedTo().getCName();
if(certDomain.equals(new URL(error.getUrl()).getHost())) {
handler.proceed();
}
}
else {
super.onReceivedSslError(view, handler, error);
}
}
Run Code Online (Sandbox Code Playgroud)
如果“hasError()”不起作用,请尝试 error.getPrimaryError() == SSL_IDMISMATCH
检查所有错误类型的 SslError 文档。
编辑:我在自己的自证书服务器(它是 Xampp)上测试了该功能,但出现错误 #3。这意味着您必须检查error.hasError(SslError.SSL_UNTRUSTED)自签名证书。
基于文档:
getIssuedBy().getDName()您是否尝试过使用SslCertificate 类的方法?此方法返回一个表示“颁发此证书的实体”的字符串。
看看这里:http://developer.android.com/reference/android/net/http/SslCertificate.html#getIssuedBy()
然后您只需要知道自签名时返回的字符串即可。
编辑:我认为如果它是自签名的,那么应该返回空字符串,如果不是,它将返回实体
问候
| 归档时间: |
|
| 查看次数: |
8189 次 |
| 最近记录: |