私はWebViewClient
のonReceivedSslError
メソッドは良いエントリポイントになると思います。
まず、https://developer.android.com/training/articles/security-ssl.html#UnknownCaのまったく同じスニペットにしたがって、TrustManagerを準備します。
TrustManagerFactory tmf = null;
private void initTrustStore() throws
java.security.cert.CertificateException, FileNotFoundException,
IOException, KeyStoreException, NoSuchAlgorithmException {
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore trustedKeyStore = KeyStore.getInstance(keyStoreType);
trustedKeyStore.load(null, null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(
getResources().getAssets().open("ca.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.d(TAG, "ca-root DN=" + ((X509Certificate) ca).getSubjectDN());
}
finally {
caInput.close();
}
trustedKeyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(trustedKeyStore);
}
続いて、最後にhttps://stackoverflow.com/a/6379434/1099884
private class CheckServerTrustedWebViewClient extends WebViewClient{
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
Log.d(TAG, "onReceivedSslError");
boolean passVerify = false;
if(error.getPrimaryError() == SslError.SSL_UNTRUSTED){
SslCertificate cert = error.getCertificate();
String subjectDN = cert.getIssuedTo().getDName();
Log.d(TAG, "subjectDN: "+subjectDN);
try{
Field f = cert.getClass().getDeclaredField("mX509Certificate");
f.setAccessible(true);
X509Certificate x509 = (X509Certificate)f.get(cert);
X509Certificate[] chain = {x509};
for (TrustManager trustManager: tmf.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
X509TrustManager x509TrustManager = (X509TrustManager)trustManager;
try{
x509TrustManager.checkServerTrusted(chain, "generic");
passVerify = true;break;
}catch(Exception e){
Log.e(TAG, "verify trustManager failed", e);
passVerify = false;
}
}
}
Log.d(TAG, "passVerify: "+passVerify);
}catch(Exception e){
Log.e(TAG, "verify cert fail", e);
}
}
if(passVerify == true)handler.proceed();
else handler.cancel();
}
}
からスニペットをチェックし、カスタムWebViewClientクラスを拡張し、一つの問題がある、しかしCheckServerTrustedWebViewClient
WebView
に
webView.setWebViewClient(new CheckServerTrustedWebViewClient());
を設定します。準備されたCA証明書は、サーバー証明書とまったく同じです(中間CA NOTルートCA)。ルートCA証明書のみを提供することはできません。 TrustManagerは実行時にサーバー証明書チェーンをダウンロードできませんか?なにか提案を?
報告する問題の解決方法の詳細が記載されていない「セキュリティスキャンプログラム」は避けてください。 – CommonsWare
@CommonsWareレポートの「お勧め」セクションは、上記のリンクのコードスニペットとまったく同じで、証明書ピン割り当てまたはカスタムキーストアを使用することを推奨します。これ以外の情報はありません。 – GreenTeaIterator
AFAIK、どちらも 'WebView'では使用できません。 – CommonsWare