runtime: SslStream: Authentication failed because the remote party has closed the transport stream

@SidharthNabar Hey … ran into an issue following the updates to System.Net.Sockets. Under 4.0.10-beta-*, I was using this to hit up a GoDaddy (yuck!) mail server …

using (var client = new TcpClient(server, port))
{
    using (var stream = new SslStream(client.GetStream(), false))
    {
        stream.AuthenticateAsClient(server);
        ... USE THE STREAM ...

… after the revision to System.Net.Sockets using 4.1.0-beta-*, I converted that over to …

using (var client = new TcpClient())
{
    await client.ConnectAsync(server, port);
    using (var stream = new SslStream(client.GetStream(), true))
        {
            stream.AuthenticateAsClient(server);
            ... USE THE STREAM ...

… it runs locally (note that I had to change the leaveInnerStreamOpen to true to even get it to run on IIS Express), but it throws on the server …

System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
 at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
 at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost)
 at MyApp.ContactController.<Index>d__5.MoveNext()

If I immediately re-submit the form, it throws slightly differently …

System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
 at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
 at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
 at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost)
 at MyApp.ContactController.<Index>d__5.MoveNext()

Am I coding that change correctly?

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 37 (10 by maintainers)

Most upvoted comments

@CIPop Can close this now. I know what the issue is. It’s cipher suites. There is some kind of mismatch. All I did on this latest exception … on this latest server test … was set the IISCrypto suites to “Best Practices,” because I had a very restrictive set of TLS1.2-only suites on there originally.

As soon as I loosened things up a bit, the connection was made and the servers were all talking to together 😄

I’m probably not going to bother to check and see which cipher suite was actually agreed on between my 2012R2 and the GoDaddy server, but I think we know what this whole exception is about now.

I would suggest though that the exception itself isn’t particularly helpful, since all it says is that the connection was unexpectedly dropped. It would be nice if there were a cipher suite mismatch that the exception could say so.

Anyway… thanks for your help, and I’m glad we came to a happy end on this one. I really, really needed this mail code to tide me over to the upcoming release of System.Net.Mail.

Thanks @GuardRex for the investigation!

I would suggest though that the exception itself isn’t particularly helpful, since all it says is that the connection was unexpectedly dropped. It would be nice if there were a cipher suite mismatch that the exception could say so.

Unfortunately, as you can see from the traces, we can’t find out that the issue was caused by a cyphersuite mismatch. The TLS protocol expects that the client submits a list of acceptable suites to the server. The server then intersects this with its own list and decides on the next action. In this case, IIS decided to terminate the TCP connection without sending any other information.

One interesting thing to note is that in CoreFX and .Net 4.6 (and above) applications we’ve enabled SCH_USE_STRONG_CRYPTO which eliminated a few of the crypto and hashing algorithms that are known to have security problems.

@CIPop Yes, it’s still happening …

System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
 at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
 at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
 at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
 --- End of stack trace from previous location where exception was thrown ---
 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
 at PlatformIssue.ContactController.<SendMailOnPort465>d__9.MoveNext()]

This is the same code trying to shoot a message to GoDaddy (yuck!) mail server on port 465 in this format …

using (var client = new TcpClient())
{
    await client.ConnectAsync(server, port);
    using (var stream = new SslStream(client.GetStream(), true))
    {
        await stream.AuthenticateAsClientAsync(server);
        using (var reader = new StreamReader(stream))
        using (var writer = new StreamWriter(stream) { AutoFlush = true })
        {
            writer.WriteLine("<WRITE_SOMETHING>");
            reader.ReadLine() // <---- READ SOMETHING
            writer.WriteLine("<WRITE_SOMETHING>");
            reader.ReadLine() // <---- READ SOMETHING
            ...
        }
    }
}

Using …

dnx-coreclr-win-x64.1.0.0-rc2-16357
System.Net.Security: 4.0.0-rc2-23623
System.Net.Sockets: 4.1.0-rc2-23623

The code runs fine and the mail is delivered on WS 2012 (not R2). The code throws (connection reset) on WS 2012 R2 at the HELO.

The Wireshark traces show that on WS 2012 (working) the HELLO packet is on protocol TLSv1.2good … while on WS 2012 R2 (not working) the HELLO packet is on protocol SSL and that’s where the connection gets reset … fail

These two machines have identical cipher suites (and SSL isn’t among them; TLS 1.0, 1.1, 1.2 only).

I have an schannel.etl from the working server (but not from the failing one for some reason … maybe I couldn’t get one … can’t recall), but it’s indecipherable because the symbols in the file aren’t resolved to plain English log entries.

I just need a safe (private) way to get these to you (payload is only 408KB), and I’m not sure what “//msconnect” is or how I would use it to get the files to you.

… unless you can think of something I might just try for a ✨ magical ✨ solution.