CertificateException, выброшенное в пользовательском X509TrustManager, не может быть обработано
Мое приложение Xamarin.Android отправляет запросы веб-службе, работающей по протоколу https. Сертификат может быть самоподписанным, поэтому мне нужно выполнить проверку сертификата самостоятельно. Я настроил свой собственный TrustManager. Но из того, что я нашел, метод CheckServerTrusted
должен бросить CertificateException
если сертификат не является доверенным. Если я это сделаю, то мое приложение вылетает. CertificateException
нигде не обрабатывается.
var aUrl = new URL(url);
var connection = (HttpURLConnection)aUrl.OpenConnection();
try
{
var httpsConn = connection as HttpsURLConnection;
if (httpsConn != null)
{
var tm = new CustomX509TrustManager();
var sslCtx = SSLContext.GetInstance("TLSv1.2");
sslCtx.Init(null, new ITrustManager[] { tm }, null);
httpsConn.HostnameVerifier = new CustomHostnameVerifier();
httpsConn.SSLSocketFactory = sslCtx.SocketFactory;
}
System.Diagnostics.Debug.WriteLine("Connecting ...");
//connection.Connect();
await connection.ConnectAsync();
System.Diagnostics.Debug.WriteLine("Never reached");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Exception!\n{ex}");
}
finally
{
System.Diagnostics.Debug.WriteLine("Never reached");
}
System.Diagnostics.Debug.WriteLine("Never reached");
CustomX509TrustManager
так просто, как может быть:
class CustomX509TrustManager : Java.Lang.Object, IX509TrustManager
{
public void CheckClientTrusted(Java.Security.Cert.X509Certificate[] chain, string authType)
{
}
public void CheckServerTrusted(Java.Security.Cert.X509Certificate[] certificates, string authType)
{
throw new Java.Security.Cert.CertificateException();
}
Java.Security.Cert.X509Certificate[] IX509TrustManager.GetAcceptedIssuers()
{
return new Java.Security.Cert.X509Certificate[0];
}
}
В connection.ConnectAsync() происходит связь с удаленным сервером, и сертификат проверяется в CustomX509TrustManager.CheckServerTrusted. Это создает исключение CertificateException. Но это исключение не отражено в моем методе try/catch в вызывающем методе. Приложение вылетает с этой трассировкой стека:
UNHANDLED EXCEPTION:
Java.Security.Cert.CertificateException: Exception of type 'Java.Security.Cert.CertificateException' was thrown.
at SimpleWebRequest.MainActivity+CustomX509TrustManager.CheckServerTrusted (Java.Security.Cert.X509Certificate[] certificates, System.String authType) [0x00001] in D:\Temp\SimpleWebRequest\SimpleWebRequest\MainActivity.cs:162
at Javax.Net.Ssl.IX509TrustManagerInvoker.n_CheckServerTrusted_arrayLjava_security_cert_X509Certificate_Ljava_lang_String_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_chain, System.IntPtr native_authType) [0x00028] in /Users/builder/data/lanes/4009/9578cdcd/source/monodroid/src/Mono.Android/platforms/android-25/src/generated/Javax.Net.Ssl.IX509TrustManager.cs:129
at (wrapper dynamic-method) System.Object:5109f213-8693-4899-a3db-70ed54baf307 (intptr,intptr,intptr,intptr)
--- End of managed Java.Security.Cert.CertificateException stack trace ---
Я попробовал несколько вещей со странными результатами.
Если я использую connection.Connect()
вместо ConnectAsync
тогда catch
блок запущен, но finally
Блок не является, а также код после этого больше не работает. С ConnectAsync
, catch
Блок тоже не запускается.
Если я получу TrustManager по умолчанию и установите его в SSLSocketFactory
как я сделал с моим, то это работает. Сертификаты отклоняются, и исключение может быть перехвачено. Так что я не думаю, что у меня есть только улов на неправильной нити.
Если я использую свой собственный TrustManager, но я делегирую вызов CheckServerTrusted
к TrustManager по умолчанию, то он терпит неудачу, как если бы я сам выбрасывал исключение.
Так что я думаю, что я делаю что-то не так в моем CustomX509TrustManager
или как я передаю это SSLSocketFactory
,
К сожалению, при поиске пользовательских TrustMangager большинство людей просто хотят игнорировать все ошибки сертификата. Это работает для меня, проблема возникает, если я проверяю сертификат и хочу отклонить его.
1 ответ
У меня такая же проблема. После нескольких часов попыток и ошибок я обнаружил, что исключение не обрабатывается только в режиме отладки. Если приложение создано в режиме выпуска, перехватывается исключение.
Но из того, что я нашел, метод CheckServerTrusted должен генерировать CertificateException, если сертификат не является доверенным. Если я это сделаю, то мое приложение вылетает. CertificateException нигде не обрабатывается.
Я думаю, что проблема именно в том, как вы справляетесь с CheckServerTrusted
метод, вы кодировали так:
public void CheckServerTrusted(Java.Security.Cert.X509Certificate[] certificates, string authType)
{
throw new Java.Security.Cert.CertificateException();
}
Это всегда новый необработанный бросок CertificateException
Когда ваш CheckServerTrusted
метод называется.
Я думаю, что вы можете проверить этот блог: самоподписанные сертификаты и Xamarin.Android. Из того, что я вижу, CheckServerTrusted
Этот метод можно использовать для переноса диспетчера доверия в другой диспетчер доверия, чтобы разрешить проверку других сертификатов. Когда вы настраиваете этот метод, вам не нужно выбрасывать такое исключение.