带证书的Xamarin Android HttpWebClient:System.IO.IOException:身份验证或解密失败

时间:2016-12-14 11:03:08

标签: xamarin.android httpwebrequest x509certificate

我们正在使用Xamarin开发Android应用程序。应用程序通过HTTPS上的HttpWebRequest Post将工作数据发送到后端服务(使用证书保护的WCF)。一切正常,直到发送的消息超过限制大小。在这种情况下,在每次同步时,我们都会遇到以下错误之一:

  • System.IO.IOException:身份验证或解密失败。 ---> System.IO.IOException:发送TLS警报时出错(致命:InternalError):System.NullReferenceException:未将对象引用设置为对象的实例。

  • System.Net.WebException:获取响应流时出错(ReadDone1):ReceiveFailure ---> System.IO.IOException:身份验证或解密失败。 ---> System.IO.IOException:发送TLS警报时出错(致命:InternalError):System.IO.IOException:身份验证或解密失败。 ---> System.IO.IOException:无法将数据写入传输连接:由对等方重置连接。 ---> System.Net.Sockets.SocketException:通过对等方重置连接

导致错误的“大”消息是44KB(在utf8中为22KB)!

我们已尝试的内容:

  • 我们注意到的一件事是,如果我们在发送大消息之前使用一条小消息创建一个HttpWebRequest Post,它就可以正常工作。
  • 使用Restsharp进行测试,行为相同。 Restsharp也使用System.net.dll
  • 我们还使用Postman测试了导致移动应用程序出现问题并且消息成功发送的消息。所以这似乎与System.Net有关。

我们发现其他人似乎有这个问题,解决方案是使用ModernHttp但不适用于我们,因为它不支持客户端证书: HttpClient Error getting response stream (ReadDone1): ReceiveFailure

我们正在使用Xamarin版本:
Visual Studio 2015 Update 3
Xamarin 4.2.1.64
Xamarin.Android 7.0.2.37 - 使用Android 5.0.1和Android 6在Samsung Device S4和S5上测试

有什么想法吗?

第一个错误堆栈跟踪:

System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: Error while sending TLS Alert (Fatal:InternalError): System.NullReferenceException: Object reference not set to an instance of an object.
  at Mono.Security.Protocol.Tls.SslStreamBase.InternalBeginWrite (Mono.Security.Protocol.Tls.SslStreamBase+InternalAsyncResult asyncResult) [0x00031] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslStreamBase.cs:782  ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.NetworkStream'.
  at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback callback, System.Object state) [0x00014] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/referencesource/System/net/System/Net/Sockets/NetworkStream.cs:907 
  at Mono.Security.Protocol.Tls.RecordProtocol.BeginSendRecord (Mono.Security.Protocol.Tls.ContentType contentType, System.Byte[] recordData, System.AsyncCallback callback, System.Object state) [0x00026] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:765 
  at Mono.Security.Protocol.Tls.RecordProtocol.SendRecord (Mono.Security.Protocol.Tls.ContentType contentType, System.Byte[] recordData) [0x00000] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:786 
  at Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (Mono.Security.Protocol.Tls.Alert alert) [0x00027] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:633 
  at Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (System.Exception& ex) [0x00021] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:598 
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
  at Mono.Security.Protocol.Tls.SslStreamBase.InternalBeginWrite (Mono.Security.Protocol.Tls.SslStreamBase+InternalAsyncResult asyncResult) [0x00077] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslStreamBase.cs:791 
  at Mono.Security.Protocol.Tls.SslStreamBase.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 count, System.AsyncCallback callback, System.Object state) [0x000a3] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslStreamBase.cs:858 
  at Mono.Net.Security.Private.LegacySslStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 count, System.AsyncCallback asyncCallback, System.Object asyncState) [0x00006] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/Mono.Net.Security/LegacySslStream.cs:435 
  at System.Net.WebConnection.BeginWrite (System.Net.HttpWebRequest request, System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback cb, System.Object state) [0x0005f] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/System.Net/WebConnection.cs:1000 

第二个错误堆栈跟踪:

System.Net.WebException: Error getting response stream (ReadDone1): ReceiveFailure ---> System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: Error while sending TLS Alert (Fatal:InternalError): System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: Unable to read data from the transport connection: Connection reset by peer. ---> System.Net.Sockets.SocketException: Connection reset by peer
  at System.Net.Sockets.Socket.EndReceive (System.IAsyncResult result) [0x0002d] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/System.Net.Sockets/Socket.cs:2031 
  at System.Net.Sockets.NetworkStream.EndRead (System.IAsyncResult asyncResult) [0x0005f] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/referencesource/System/net/System/Net/Sockets/NetworkStream.cs:858 
   --- End of inner exception stack trace ---
  at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (System.IAsyncResult asyncResult) [0x0003a] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:430 
  at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (System.IAsyncResult ar, System.Boolean ignoreEmpty) [0x00000] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:256 
  at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (System.IAsyncResult result) [0x00071] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:418 
   --- End of inner exception stack trace ---
  at Mono.Security.Protocol.Tls.SslClientStream.EndNegotiateHandshake (System.IAsyncResult result) [0x00035] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:396 
  at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (System.IAsyncResult asyncResult) [0x0000c] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslStreamBase.cs:101  ---> System.IO.IOException: Unable to write data to the transport connection: The socket is not connected. ---> System.Net.Sockets.SocketException: The socket is not connected
  at System.Net.Sockets.Socket.BeginSend (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socket_flags, System.AsyncCallback callback, System.Object state) [0x00021] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/System.Net.Sockets/Socket.cs:2566 
  at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback callback, System.Object state) [0x000b4] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/referencesource/System/net/System/Net/Sockets/NetworkStream.cs:934 
   --- End of inner exception stack trace ---
  at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback callback, System.Object state) [0x000f2] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/referencesource/System/net/System/Net/Sockets/NetworkStream.cs:954 
  at Mono.Security.Protocol.Tls.RecordProtocol.BeginSendRecord (Mono.Security.Protocol.Tls.ContentType contentType, System.Byte[] recordData, System.AsyncCallback callback, System.Object state) [0x00026] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:765 
  at Mono.Security.Protocol.Tls.RecordProtocol.SendRecord (Mono.Security.Protocol.Tls.ContentType contentType, System.Byte[] recordData) [0x00000] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:786 
  at Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (Mono.Security.Protocol.Tls.Alert alert) [0x00027] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:633 
  at Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (System.Exception& ex) [0x00021] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:598 
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
  at Mono.Security.Protocol.Tls.SslStreamBase.EndRead (System.IAsyncResult asyncResult) [0x00051] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslStreamBase.cs:883 
  at Mono.Net.Security.Private.LegacySslStream.EndRead (System.IAsyncResult asyncResult) [0x00006] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/Mono.Net.Security/LegacySslStream.cs:494 
  at System.Net.WebConnection.ReadDone (System.IAsyncResult result) [0x0002a] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/System.Net/WebConnection.cs:468 
   --- End of inner exception stack trace ---
  at System.Net.HttpWebRequest.EndGetResponse (System.IAsyncResult asyncResult) [0x0005e] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/System.Net/HttpWebRequest.cs:1023 
  at System.Net.HttpWebRequest.GetResponse () [0x0000e] in /Users/builder/data/lanes/3511/77cb8568/source/mono/mcs/class/System/System.Net/HttpWebRequest.cs:1037 
  at MyOrg.Logistic.Mobile.Droid.CommunicationUtilities.RestPost[T] (MyOrg.Logistic.Droid.Mobile.ServiceTypes type, Communication.CommServerSettings commServerSettings, System.String requestPath, System.Object parameters, System.Boolean retry, System.Boolean closeHttpConnection) [0x000cf] in C:\Dev\Mobile\Application\main\Application\Mobile.App.Droid\CommunicationUtilities.cs:309 
  at MyOrg.Logistic.Droid.Mobile.Droid.Service.SendStoreSecondLayerEvent (MyOrg.Logistic.Droid.Messages.StoreSecondLayerEventMessage msg) [0x00001] in C:\Dev\Mobile\Application\main\Application\Mobile.App.Droid\Services\Service.cs:96 
  at MyOrg.Logistic.Droid.Mobile.SynchronizationExecutionViewModel+<Synchronize>d__38.MoveNext () [0x00173] in C:\Dev\Mobile\Application\main\Application\Mobile.App\ViewModels\SynchronizationExecutionViewModel.cs:172 

HttpWebRequest代码:

public static T RestPost<T>(ServiceTypes type, CommServerSettings commServerSettings, string requestPath,
        object parameters = null, bool retry = false, bool closeHttpConnection = true) where T : new()
{
//https://192.168.1.12:6206/Transmission/StoreSecondLayerEvent
var url = BuildServiceUrl(type,
    commServerSettings,
    requestPath);

HttpWebRequest.DefaultMaximumResponseHeadersLength = 128 * 1024; // 128kb

//specify to use TLS 1.2 as default connection
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

/* HttpWebRequest Variant */

string output = string.Empty;
if (parameters != null)
{
    output = JsonConvert.SerializeObject(parameters);
}

byte[] postDataByteArray = Encoding.UTF8.GetBytes(output);

var rq = new HttpWebRequest(new Uri(url));            

if (Certificate != null)
{
    rq.ClientCertificates = new X509Certificate2Collection(Certificate);
}

rq.KeepAlive = !closeHttpConnection;
//rq.PreAuthenticate = true;
//rq.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;

rq.Method = "POST";
rq.ContentType = "application/json";
rq.ContentLength = postDataByteArray.Length;

// write the data on the connection stream
using (var dataStream = rq.GetRequestStream())
{
    dataStream.Write(postDataByteArray, 0, postDataByteArray.Length);
    dataStream.Close();
}

string responseString;

using (HttpWebResponse rs = (HttpWebResponse) rq.GetResponse())
{
    using (Stream responseStream = rs.GetResponseStream())
    {
        using (StreamReader responseReader = new StreamReader(responseStream))
        {
            responseString = responseReader.ReadToEnd();
        }
    }
}

Console.WriteLine("Received: " + responseString);

var keyResponse = JsonConvert.DeserializeObject<T>(responseString);

return keyResponse;
}

static CommunicationUtilities()
{
try
{
    // # Sets the validation of the certificate to be always valid
    // # Check: https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback(v=vs.110).aspx
    ServicePointManager.ServerCertificateValidationCallback += (sender,
        certificate,
        chain,
        errors) => true;
}
catch (Exception ex)
{
    throw new Exception("Error initializing CommunicationUtilities class!", ex);
}

}

1 个答案:

答案 0 :(得分:1)

错误本身看起来像是一种TLS身份验证问题。 Xamarin的当前alpha版本对我们的TLS实现进行了一些更新。如果您查看Xamarin.iOS的发行说明,您将看到有关我们迁移TLS实现的一些信息:

https://developer.xamarin.com/releases/ios/xamarin.ios_10/xamarin.ios_10.4/

在撰写本文时,Android / Platform尚未更新其文档以提及类似内容,但它也适用于Android。

官方文档中心将在此处:

https://developer.xamarin.com/guides/cross-platform/transport-layer-security/