Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simplify SslStream.AuthenticateAs*Async() #453

Merged
merged 18 commits into from
Dec 18, 2019
Merged

Conversation

wfurt
Copy link
Member

@wfurt wfurt commented Dec 2, 2019

This implements task based processing for Async authentication functions instead of using APM wrapper. With this change we do less allocations but benchmarks from performance repo show only small improvement. Main benefit is simplification for now. For example, this is old https exception for certificate validation:

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 710
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 546
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 527
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 696
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 651
   at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 599
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 556
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 527
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 696
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 651
   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 831
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslStream.ThrowIfExceptional() in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 82
   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 472
   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 442
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.cs:line 237
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.cs:line 404
   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.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:line 145
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:line 161
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 651
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 666
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 332
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 524
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs:line 33
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:line 521
   at proxy_test.Program.fetch2(String uri) in /Users/furt/proxy-test/Program.cs:line 39
   at proxy_test.Program.Main(String[] args) in /Users/furt/proxy-test/Program.cs:line 55INNED ==== System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 710
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 546
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 527
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 696
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 651
   at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 599
   at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 556
   at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 527
   at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 696
   at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 651
   at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 831
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslStream.ThrowIfExceptional() in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 82
   at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 472
   at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 442
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.cs:line 237
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__65_1(IAsyncResult iar) in /Users/furt/github/corefx-30/src/System.Net.Security/src/System/Net/Security/SslStream.cs:line 404
   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.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) in /Users/furt/github/corefx-30/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:line 145
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at proxy_test.Program.Main(String[] args) in /Users/furt/proxy-test/Program.cs:line 73

same situation with new code it looks like:

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 794
   at System.Net.Security.SslStream.ForceAuthenticationAsync(Boolean receiveFirst, Byte[] buffer, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 426
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:line 146
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:line 162
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 650
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 665
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 331
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs:line 523
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs:line 33
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs:line 521
   at proxy_test.Program.fetch2(String uri) in /Users/furt/proxy-test/Program.cs:line 39
   at proxy_test.Program.Main(String[] args) in /Users/furt/proxy-test/Program.cs:line 55INNED ==== System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 794
   at System.Net.Security.SslStream.ForceAuthenticationAsync(Boolean receiveFirst, Byte[] buffer, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs:line 426
   at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) in /Users/furt/github/wfurt-runtime/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs:line 146
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at proxy_test.Program.Main(String[] args) in /Users/furt/proxy-test/Program.cs:line 73

there is more cleanup we can do but this is starting point to simplify processing.
As general improvements I updated handshake to avoid reading 5 byte chunks and context switch and use Span when possible. I plan to update 1 byte queue for OSX but I did not want to do it as part of this change.

Early feedback would be appreciated.

When working on this I bump to few test failures. Most notably WaitForSecureConnection used in CipherSuiteTest makes assumption that certain failures will happen synchronously.
I don't know if that is artifact of old implementation or if that is something we have to preserve. For now I updated test to handle asynchronous behavior. cc: @krwq

While looking at test failures I bump to few using memory stream. That makes it impossible to use Wireshark and decode and display message exchange. I added helper method and re-factored some existing tests so it is possible on-demand to use stream on top of TCP.

fixes https://github.com/dotnet/corefx/issues/35075

@wfurt wfurt changed the title WIP: simplify SslStream.AuthenticateAs*Async() simplify SslStream.AuthenticateAs*Async() Dec 3, 2019
@wfurt wfurt requested review from bartonjs and a team December 3, 2019 22:05
@wfurt
Copy link
Member Author

wfurt commented Dec 3, 2019

I removed more dead code and all tests should be passing now.
I think it would be worth of looking at locking logic - I think we may be able to simplify it but I would prefer to do it as separate change.

@wfurt
Copy link
Member Author

wfurt commented Dec 3, 2019

/azp run runtime-libraries outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@davidsh davidsh added this to the 5.0 milestone Dec 11, 2019
@wfurt
Copy link
Member Author

wfurt commented Dec 12, 2019

/azp run runtime-libraries outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@wfurt
Copy link
Member Author

wfurt commented Dec 12, 2019

/azp run runtime-libraries stress-ssl

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@wfurt
Copy link
Member Author

wfurt commented Dec 12, 2019

/azp run runtime-libraries stress-ssl

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@wfurt
Copy link
Member Author

wfurt commented Dec 16, 2019

/azp run runtime-libraries stress-ssl

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@wfurt
Copy link
Member Author

wfurt commented Dec 17, 2019

/azp run runtime-libraries stress-ssl

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@wfurt
Copy link
Member Author

wfurt commented Dec 18, 2019

Windows_NT failures seems like infrastructure.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants