Skip to content

Using a SslStream with a socket that was disconnected with reuseSocket: true causes AuthenticationException #124353

@v3xro

Description

@v3xro

Description

Sockets support reusability through the reuseSocket parameter. When you disconnect the raw socket underneath the SslStream the subsequent reconnection and AuthenticateAsClientAsync call throws a AuthenticationException: Cannot determine the frame size or a corrupted frame was received.

Reproduction Steps

using System.Diagnostics;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;

var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.LingerState = new LingerOption(false, 0);
socket.NoDelay = true;

await socket.ConnectAsync(new DnsEndPoint("example.com", 443));
var tlsStream = new SslStream(new NetworkStream(socket));
await tlsStream.AuthenticateAsClientAsync("example.com");

byte[] getRequest = "GET / HTTP1.1\r\nHost: example.com\r\nConnection: close \r\n\r\n"u8.ToArray();
byte[] buffer = new byte[512];

await tlsStream.WriteAsync(getRequest);
var read = await tlsStream.ReadAsync(buffer);
Debug.Assert(read > 0);
await socket.DisconnectAsync(reuseSocket: true);

Thread.Sleep(1_500);

await socket.ConnectAsync(new DnsEndPoint("example.com", 443));
var tlsStream2 = new SslStream(new NetworkStream(socket));
await tlsStream2.AuthenticateAsClientAsync("example.com");
await tlsStream2.WriteAsync(getRequest);
read = await tlsStream2.ReadAsync(buffer);
Debug.Assert(read > 0);

Expected behavior

The SSL stream connects the same as the first attempt.

Actual behavior

Unhandled exception. System.Security.Authentication.AuthenticationException: Cannot determine the frame size or a corrupted frame was received.
   at System.Net.Security.SslStream.GetFrameSize(ReadOnlySpan`1 buffer)
   at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](CancellationToken cancellationToken, Int32 estimatedSize)
   at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
   at System.Net.Security.SslStream.ReceiveHandshakeFrameAsync[TIOAdapter](CancellationToken cancellationToken)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](Boolean receiveFirst, Byte[] reAuthenticationData, CancellationToken cancellationToken)

Regression?

No response

Known Workarounds

No response

Configuration

.NET 10.0.101
MacOS 15.7.3 arm64

Have not tested it on other OSes yet.

Other information

Not clear from the docs whether this should work or there are other calls that need to be done to reuse the socket.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions