Recently I have implemented a security feature to check my request is connected with the valid host. For that, I'm checking the certs of that host and I used X509TrustManager for that case. So if X509TrustManager found some invalid cert it will throw an exception and according to that, I will show an alert to the user. But the issue is that X509TrustManager throws an exception only first time. But when I refresh the same request I did not catch invalid certification and I did not see any alert. Below I added my implementation. Let me know any issue with my implementation or any known issue with X509TrustManager. Thanks and Regards.
final X509TrustManager finalTrustManager = x509TrustManager;
TrustManager[] trustAllCerts = new TrustManager[0];
if (finalTrustManager != null) {
trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return finalTrustManager.getAcceptedIssuers();
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
try {
// If Application get any CertificateException in Splash screen we will show related alert in MainActivity
// We need to terminate app after showing alert but if we show alert in Splash screen it will get hide when Main Activity get visible.
// To avoid this scenario we added this implementation.
if (mIsSplashGetInvalidateCertificate && !(mLifecycleManager.getCurrentStackOfActivity().get(0) instanceof SplashActivity)) {
mAlertManager.showAlertMessageWithoutDuplicates(mLifecycleManager.getCurrentContext().getResources().getString(R.string.certificate_error_title), mLifecycleManager.getCurrentContext().getResources().getString(R.string.certificate_error_message), (FragmentActivity) mLifecycleManager.getCurrentStackOfActivity().get(0), true);
}
// Checking the certificate availability of host
if ((certs != null && certs.length != 0) && (authType != null && authType.length() != 0)) {
finalTrustManager.checkClientTrusted(certs, authType);
} else {
terminateApplicationWithAlert();
}
} catch (CertificateException e) {
terminateApplicationWithAlert();
}
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
try {
if (mIsSplashGetInvalidateCertificate && !(mLifecycleManager.getCurrentStackOfActivity().get(0) instanceof SplashActivity)) {
mAlertManager.showAlertMessageWithoutDuplicates(mLifecycleManager.getCurrentContext().getResources().getString(R.string.certificate_error_title), mLifecycleManager.getCurrentContext().getResources().getString(R.string.certificate_error_message), (FragmentActivity) mLifecycleManager.getCurrentStackOfActivity().get(0), true);
}
if ((certs != null && certs.length != 0) && (authType != null && authType.length() != 0)) {
finalTrustManager.checkServerTrusted(certs, authType);
} else {
terminateApplicationWithAlert();
}
} catch (CertificateException e) {
terminateApplicationWithAlert();
}
}
}
};
}
You're not actually flagging the certificate as invalid, because you're catching the CertificateException
and swallowing it. By not throwing CertificateException
, you are telling the HTTP library that the invalid certificate is valid, which it's presumably caching in order to not revalidate the certificate too many times.
You need to allow the CertificateException
to be thrown from the X509TrustManager
methods, catch the error at the HTTP call sites, and show the dialog from there.