weixin_39754616
weixin_39754616
2021-01-11 14:55

SslStream hangs on client when SslStream server fails on protocol mismatch

Ok, the new preview and my bug caused the public/private key issue. However, there is still one issue left. On protocol mismatch, the server side throws an SSL error (SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL). However, the client side is apparently unaware of the protocol failure and hangs (presumably waiting for server handshake to continue) . The only way to kick the client out of hang is to kill the underlaying connection on server, but then the exception showin in client is Authentication failed because the remote party has closed the transport stream. which is pretty useless for resolution. Once again, this is done and tested on Linux, I have not tried the same on Win/Mac.

csharp
using System;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;

namespace SslFail
{
    internal static class Program
    {
        private static async Task StartClientAndAuthenticate(ClientServerState state, IPEndPoint endPoint)
        {
            try
            {
                state.Client.Connect(endPoint.Address, endPoint.Port);
                state.ClientStream = new SslStream(state.Client.GetStream(), false,
                    (a1, a2, a3, a4) => true,
                    (a1, a2, a3, a4, a5) => null);
                await state.ClientStream.AuthenticateAsClientAsync("localhost", null, SslProtocols.Tls12, false);
                state.ClientAuthenticated.Set();
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception in Client: {e.Message} {e.InnerException?.Message}");
            }
        }

        private static async Task StartServerAndAuthenticate(ClientServerState state)
        {
            try
            {
                state.Listener.Start();

                var s = new X509Store(StoreName.My, StoreLocation.CurrentUser, OpenFlags.ReadOnly);
                var serverCert = s.Certificates[0];

                state.ServerClient = await state.Listener.AcceptTcpClientAsync();
                state.ServerStream = new SslStream(state.ServerClient.GetStream(), false,
                    (a1, a2, a3, a4) => true,
                    (a1, a2, a3, a4, a5) => serverCert, EncryptionPolicy.RequireEncryption);
                await state.ServerStream.AuthenticateAsServerAsync(serverCert, false, SslProtocols.Tls13, false);
                state.ServerAuthenticated.Set();
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception in Server: {e.Message} {e.InnerException?.Message}");
            }
            finally
            {
                // if I do not do this, the client is hang (presumably until connection dies)
                // even then, the error is dropped connection and not a protocol mismatch, so there is no
                // way to course correct. 
                // state.ServerClient?.Close();     
            }
        }

        private class ClientServerState
        {
            public TcpListener Listener { get; set; }
            public TcpClient Client { get; } = new TcpClient();
            public TcpClient ServerClient { get; set; }
            public SslStream ServerStream { get; set; }
            public SslStream ClientStream { get; set; }
            public AutoResetEvent ServerAuthenticated { get; } = new AutoResetEvent(false);
            public AutoResetEvent ClientAuthenticated { get; } = new AutoResetEvent(false);
        }

        private static void Main(string[] args)
        {
            var endPoint = new IPEndPoint(IPAddress.Loopback, 35454); 
            var state = new ClientServerState { Listener = new TcpListener(endPoint) };
            try
            {
                #pragma warning disable CS4014
                StartServerAndAuthenticate (state);
                StartClientAndAuthenticate (state, endPoint);
                #pragma warning enable CS4014
                state.ServerAuthenticated.WaitOne();
                state.ClientAuthenticated.WaitOne();
                Console.WriteLine("All is well, no bug detected!");
            } finally {
                state.ClientStream?.Dispose ();
                state.Client.Close ();
                state.ServerStream?.Dispose ();
                state.ServerClient?.Close ();
                state.Listener.Stop ();
            }
        }
    }
}

该提问来源于开源项目:dotnet/runtime

  • 点赞
  • 回答
  • 收藏
  • 复制链接分享

52条回答

为你推荐

换一换