我的Xamarin.Android应用程序向运行在https上的Web服务发出请求。证书可能是自签名的,因此我需要自己进行证书检查。我配置了自己的TrustManager。但是根据我的发现,如果证书不可信,方法CheckServerTrusted
应该抛出CertificateException
。如果我这样做,那么我的应用程序崩溃了。 <{1}}不会在任何地方处理。
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
在connection.ConnectAsync()中联系远程服务器,并在CustomX509TrustManager.CheckServerTrusted中检查证书。这会抛出CertificateException。但是在调用方法的try / catch中没有捕获到该异常。应用程序崩溃与此堆栈跟踪:
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];
}
}
我尝试了几件奇怪的结果。
如果我使用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
块也不会运行。
如果我得到默认的TrustManager并将其设置在catch
中,就像我对我的那样,那么它就可以了。证书被拒绝,可以捕获异常。所以我不认为我只是错误地抓住了。
如果我使用自己的TrustManager,但是我将对SSLSocketFactory
的调用委托给默认的TrustManager,那么它就会失败,就像我自己抛出异常一样。
所以我认为我在CheckServerTrusted
或我将其传递给CustomX509TrustManager
的方式做错了。
不幸的是,当您搜索自定义TrustMangagers时,大多数人只想忽略所有证书错误。这对我有用,如果我检查证书并想要拒绝它,就会出现问题。
答案 0 :(得分:0)
但是从我发现的情况来看,如果证书不受信任,CheckServerTrusted方法应抛出CertificateException。如果我这样做,那么我的应用程序崩溃了。 CertificateException不会在任何地方处理。
我认为问题正是你如何处理CheckServerTrusted
方法,你编码如下:
public void CheckServerTrusted(Java.Security.Cert.X509Certificate[] certificates, string authType)
{
throw new Java.Security.Cert.CertificateException();
}
调用CertificateException
方法时,始终会抛出未处理的新CheckServerTrusted
。
我想你可以查看这个博客:Self-Signed Certificates and Xamarin.Android。根据我的看法,CheckServerTrusted
方法可用于将信任管理器包装在另一个信任管理器中,以允许验证其他证书。当您自定义此方法时,您不需要抛出此类异常。
答案 1 :(得分:0)
我有同样的问题。经过数小时的反复尝试,我发现仅在调试模式下才处理该异常。如果该应用是在发布模式下构建的,则会捕获到异常。