runtime: Violation of nullability constraint for certificate validation during TLS renegotiation in HTTP request
Description
When TLS is renegotiated in the middle of HTTP request the validation callback receives null for HttpRequestMessage which violates the nullability annotations of the callback.
Configuration
.NET 5.0.7 Windows 11 build 22000.51 (triggers the re-negotiation scenario) x64
Regression?
The error doesn’t happen on Windows 10 for the same request. That suggests it’s triggered by something in the TLS stack that changed in Windows 11.
Other information
Stack trace:
> MailClient.dll!MailClient.Protocols.InteractionController.HttpClientCerificationValidationMessageHandler.ValidateCertificate(System.Net.Http.HttpRequestMessage message, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors) Line 498 C#
System.Net.Http.dll!System.Net.Http.ConnectHelper.EstablishSslConnectionAsync.AnonymousMethod__0(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors) Unknown
System.Net.Security.dll!System.Net.Security.SecureChannel.VerifyRemoteCertificate(System.Net.Security.RemoteCertificateValidationCallback remoteCertValidationCallback, ref System.Net.Security.ProtocolToken alertToken, out System.Net.Security.SslPolicyErrors sslPolicyErrors, out System.Security.Cryptography.X509Certificates.X509ChainStatusFlags chainStatus) Unknown
System.Net.Security.dll!System.Net.Security.SslStream.CompleteHandshake(ref System.Net.Security.ProtocolToken alertToken, out System.Net.Security.SslPolicyErrors sslPolicyErrors, out System.Security.Cryptography.X509Certificates.X509ChainStatusFlags chainStatus) Unknown
System.Net.Security.dll!System.Net.Security.SslStream.ForceAuthenticationAsync<System.Net.Security.AsyncReadWriteAdapter>(System.Net.Security.AsyncReadWriteAdapter adapter, bool receiveFirst, byte[] reAuthenticationData, bool isApm) Unknown
System.Net.Security.dll!System.Net.Security.SslStream.ReplyOnReAuthenticationAsync<System.Net.Security.AsyncReadWriteAdapter>(System.Net.Security.AsyncReadWriteAdapter adapter, byte[] buffer) Unknown
System.Net.Security.dll!System.Net.Security.SslStream.ReadAsyncInternal<System.Net.Security.AsyncReadWriteAdapter>(System.Net.Security.AsyncReadWriteAdapter adapter, System.Memory<byte> buffer) Unknown
System.Net.Security.dll!System.Net.Security.SslStream.ReadAsync(System.Memory<byte> buffer, System.Threading.CancellationToken cancellationToken) Unknown
System.Net.Http.dll!System.Net.Http.HttpConnection.FillAsync(bool async) Unknown
System.Net.Http.dll!System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(bool async, bool foldedHeadersAllowed) Unknown
System.Net.Http.dll!System.Net.Http.HttpConnection.SendAsyncCore(System.Net.Http.HttpRequestMessage request, bool async, System.Threading.CancellationToken cancellationToken) Unknown
[Resuming Async Method]
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Net.Http.HttpResponseMessage>.AsyncStateMachineBox<System.Net.Http.HttpConnection.<SendAsyncCore>d__56>.ExecutionContextCallback(object s) Unknown
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) Unknown
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.Net.Http.HttpResponseMessage>.AsyncStateMachineBox<System.Net.Http.HttpConnection.<SendAsyncCore>d__56>.MoveNext(System.Threading.Thread threadPoolThread) Unknown
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder<System.__Canon>.AsyncStateMachineBox<System.Net.Http.HttpConnection.<SendAsyncCore>d__56>.MoveNext() Unknown
System.Private.CoreLib.dll!System.Runtime.CompilerServices.TaskAwaiter.OutputWaitEtwEvents.AnonymousMethod__12_0(System.Action innerContinuation, System.Threading.Tasks.Task innerTask) Unknown
System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.ContinuationWrapper.Invoke() Unknown
System.Private.CoreLib.dll!System.Threading.Tasks.AwaitTaskContinuation.System.Threading.IThreadPoolWorkItem.Execute() Unknown
System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Unknown
System.Private.CoreLib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() Unknown
[Async Call Stack]
[Async] System.Net.Http.dll!System.Net.Http.AuthenticationHelper.SendWithNtAuthAsync(System.Net.Http.HttpRequestMessage request, System.Uri authUri, bool async, System.Net.ICredentials credentials, bool isProxyAuth, System.Net.Http.HttpConnection connection, System.Net.Http.HttpConnectionPool connectionPool, System.Threading.CancellationToken cancellationToken) Unknown
[Async] System.Net.Http.dll!System.Net.Http.HttpConnectionPool.SendWithRetryAsync(System.Net.Http.HttpRequestMessage request, bool async, bool doRequestAuth, System.Threading.CancellationToken cancellationToken) Unknown
[Async] System.Net.Http.dll!System.Net.Http.AuthenticationHelper.SendWithAuthAsync(System.Net.Http.HttpRequestMessage request, System.Uri authUri, bool async, System.Net.ICredentials credentials, bool preAuthenticate, bool isProxyAuth, bool doRequestAuth, System.Net.Http.HttpConnectionPool pool, System.Threading.CancellationToken cancellationToken) Unknown
[Async] System.Net.Http.dll!System.Net.Http.RedirectHandler.SendAsync(System.Net.Http.HttpRequestMessage request, bool async, System.Threading.CancellationToken cancellationToken) Unknown
[Async] System.Net.Http.dll!System.Net.Http.DecompressionHandler.SendAsync(System.Net.Http.HttpRequestMessage request, bool async, System.Threading.CancellationToken cancellationToken) Unknown
[Async] MailClient.dll!MailClient.Protocols.InteractionController.HttpClientCerificationValidationMessageHandler.SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) Line 515 C#
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 18 (18 by maintainers)
I think this is actually quite important to backport to 5.0. The conditions for hitting it are the following:
HttpClientto connect to HTTPS endpoints on Windows machineServerCertificateCustomValidationCallbackWe started hitting it on day one of Windows 11 being pushed to Windows Insiders for a released version of our application. I suppose that others will start hitting it too once TLS 1.3 becomes more common. Note that .NET 5 enables TLS 1.3 support by default, it would be less of an issue if it didn’t already do that.
correct. I’m proposing to fix 5.0 to match Framework. (and 6.0)
For the sake of completeness I retested it on .NET 6 Preview 5 and it does behave correctly.
yes it should. It is also most likely Windows specific. With https://github.com/dotnet/runtime/pull/43123 we should verify the callback is called only once (at least from SslStream) but obviously we don’t in some cases.