无法处理在自定义X509TrustManager中抛出的CertificateException

时间:2017-03-14 10:45:13

标签: android xamarin.android x509trustmanager

我的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时,大多数人只想忽略所有证书错误。这对我有用,如果我检查证书并想要拒绝它,就会出现问题。

2 个答案:

答案 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)

我有同样的问题。经过数小时的反复尝试,我发现仅在调试模式下才处理该异常。如果该应用是在发布模式下构建的,则会捕获到异常。