diff options
author | Stephen Toub <stoub@microsoft.com> | 2017-07-17 18:27:08 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-17 18:27:08 +0300 |
commit | 96dbafbd0f13f73ea76d2fb0ae006e59b5b7f55f (patch) | |
tree | 1f7a5e958d1ffd1c5dc1ff78b48e8081d7f711c3 /src/System.Net.Security | |
parent | a40fb93e08c3b42527739bbe727c22edc5e5ebdb (diff) |
Remove a few allocations from SslStream (#22304)
* Remove unnecessary X509CertificateCollection allocations
* Avoid delegate allocations per AuthenticateAs call in SslStream
Each call is allocating a delegate for the Begin and End method. We can avoid that by passing `this` in as state.
Diffstat (limited to 'src/System.Net.Security')
3 files changed, 59 insertions, 49 deletions
diff --git a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs index a1e7e8137c..f623b2fdbf 100644 --- a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs +++ b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs @@ -36,7 +36,7 @@ namespace System.Net.Security private X509Certificate _selectedClientCertificate; private bool _isRemoteCertificateAvailable; - private readonly X509CertificateCollection _clientCertificates; + private X509CertificateCollection _clientCertificates; private LocalCertSelectionCallback _certSelectionDelegate; // These are the MAX encrypt buffer output sizes, not the actual sizes. @@ -142,14 +142,6 @@ namespace System.Net.Security } } - internal X509CertificateCollection ClientCertificates - { - get - { - return _clientCertificates; - } - } - internal int HeaderSize { get @@ -384,7 +376,11 @@ namespace System.Net.Security { X509Certificate2Collection dummyCollection; remoteCert = CertificateValidationPal.GetRemoteCertificate(_securityContext, out dummyCollection); - clientCertificate = _certSelectionDelegate(_hostName, ClientCertificates, remoteCert, issuers); + if (_clientCertificates == null) + { + _clientCertificates = new X509CertificateCollection(); + } + clientCertificate = _certSelectionDelegate(_hostName, _clientCertificates, remoteCert, issuers); } finally { @@ -407,7 +403,7 @@ namespace System.Net.Security } else { - if (ClientCertificates.Count == 0) + if (_clientCertificates == null || _clientCertificates.Count == 0) { if (NetEventSource.IsEnabled) NetEventSource.Log.NoDelegateNoClientCert(this); @@ -423,7 +419,7 @@ namespace System.Net.Security { // This is where we attempt to restart a session by picking the FIRST cert from the collection. // Otherwise it is either server sending a client cert request or the session is renegotiated. - clientCertificate = ClientCertificates[0]; + clientCertificate = _clientCertificates[0]; sessionRestartAttempt = true; if (clientCertificate != null) { diff --git a/src/System.Net.Security/src/System/Net/Security/SslState.cs b/src/System.Net.Security/src/System/Net/Security/SslState.cs index aafe6e9238..f44975c581 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslState.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslState.cs @@ -120,11 +120,6 @@ namespace System.Net.Security throw new ArgumentNullException(nameof(serverCertificate)); } - if (clientCertificates == null) - { - clientCertificates = new X509CertificateCollection(); - } - if (targetHost.Length == 0) { targetHost = "?" + Interlocked.Increment(ref s_uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo); diff --git a/src/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/System.Net.Security/src/System/Net/Security/SslStream.cs index 0f55e769b8..22cefaa220 100644 --- a/src/System.Net.Security/src/System/Net/Security/SslStream.cs +++ b/src/System.Net.Security/src/System/Net/Security/SslStream.cs @@ -105,7 +105,7 @@ namespace System.Net.Security // public virtual IAsyncResult BeginAuthenticateAsClient(string targetHost, AsyncCallback asyncCallback, object asyncState) { - return BeginAuthenticateAsClient(targetHost, new X509CertificateCollection(), SecurityProtocol.SystemDefaultSecurityProtocols, false, + return BeginAuthenticateAsClient(targetHost, null, SecurityProtocol.SystemDefaultSecurityProtocols, false, asyncCallback, asyncState); } @@ -192,7 +192,7 @@ namespace System.Net.Security #region Synchronous methods public virtual void AuthenticateAsClient(string targetHost) { - AuthenticateAsClient(targetHost, new X509CertificateCollection(), SecurityProtocol.SystemDefaultSecurityProtocols, false); + AuthenticateAsClient(targetHost, null, SecurityProtocol.SystemDefaultSecurityProtocols, false); } public virtual void AuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation) @@ -226,44 +226,63 @@ namespace System.Net.Security #endregion #region Task-based async public methods - public virtual Task AuthenticateAsClientAsync(string targetHost) - { - return Task.Factory.FromAsync(BeginAuthenticateAsClient, EndAuthenticateAsClient, targetHost, null); - } - - public virtual Task AuthenticateAsClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation) - { - return AuthenticateAsClientAsync(targetHost, clientCertificates, SecurityProtocol.SystemDefaultSecurityProtocols, checkCertificateRevocation); - } + public virtual Task AuthenticateAsClientAsync(string targetHost) => + Task.Factory.FromAsync( + (arg1, callback, state) => ((SslStream)state).BeginAuthenticateAsClient(arg1, callback, state), + iar => ((SslStream)iar.AsyncState).EndAuthenticateAsClient(iar), + targetHost, + this); + + public virtual Task AuthenticateAsClientAsync(string targetHost, X509CertificateCollection clientCertificates, bool checkCertificateRevocation) => + Task.Factory.FromAsync( + (arg1, arg2, arg3, callback, state) => ((SslStream)state).BeginAuthenticateAsClient(arg1, arg2, SecurityProtocol.SystemDefaultSecurityProtocols, arg3, callback, state), + iar => ((SslStream)iar.AsyncState).EndAuthenticateAsClient(iar), + targetHost, clientCertificates, checkCertificateRevocation, + this); public virtual Task AuthenticateAsClientAsync(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { - return Task.Factory.FromAsync((callback, state) => BeginAuthenticateAsClient(targetHost, clientCertificates, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsClient, null); - } - - public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate) - { - return Task.Factory.FromAsync(BeginAuthenticateAsServer, EndAuthenticateAsServer, serverCertificate, null); - } - - public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation) - { - return AuthenticateAsServerAsync(serverCertificate, clientCertificateRequired, SecurityProtocol.SystemDefaultSecurityProtocols, checkCertificateRevocation); - } + var beginMethod = checkCertificateRevocation ? (Func<string, X509CertificateCollection, SslProtocols, AsyncCallback, object, IAsyncResult>) + ((arg1, arg2, arg3, callback, state) => ((SslStream)state).BeginAuthenticateAsClient(arg1, arg2, arg3, true, callback, state)) : + ((arg1, arg2, arg3, callback, state) => ((SslStream)state).BeginAuthenticateAsClient(arg1, arg2, arg3, false, callback, state)); + return Task.Factory.FromAsync( + beginMethod, + iar => ((SslStream)iar.AsyncState).EndAuthenticateAsClient(iar), + targetHost, clientCertificates, enabledSslProtocols, + this); + } + + public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate) => + Task.Factory.FromAsync( + (arg1, callback, state) => ((SslStream)state).BeginAuthenticateAsServer(arg1, callback, state), + iar => ((SslStream)iar.AsyncState).EndAuthenticateAsServer(iar), + serverCertificate, + this); + + public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation) => + Task.Factory.FromAsync( + (arg1, arg2, arg3, callback, state) => ((SslStream)state).BeginAuthenticateAsServer(arg1, arg2, SecurityProtocol.SystemDefaultSecurityProtocols, arg3, callback, state), + iar => ((SslStream)iar.AsyncState).EndAuthenticateAsServer(iar), + serverCertificate, clientCertificateRequired, checkCertificateRevocation, + this); public virtual Task AuthenticateAsServerAsync(X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { - - return Task.Factory.FromAsync((callback, state) => BeginAuthenticateAsServer(serverCertificate, clientCertificateRequired, enabledSslProtocols, checkCertificateRevocation, callback, state), EndAuthenticateAsServer, null); - } - - public virtual Task ShutdownAsync() - { + var beginMethod = checkCertificateRevocation ? (Func<X509Certificate, bool, SslProtocols, AsyncCallback, object, IAsyncResult>) + ((arg1, arg2, arg3, callback, state) => ((SslStream)state).BeginAuthenticateAsServer(arg1, arg2, arg3, true, callback, state)) : + ((arg1, arg2, arg3, callback, state) => ((SslStream)state).BeginAuthenticateAsServer(arg1, arg2, arg3, false, callback, state)); return Task.Factory.FromAsync( - (callback, state) => BeginShutdown(callback, state), - EndShutdown, - null); + beginMethod, + iar => ((SslStream)iar.AsyncState).EndAuthenticateAsServer(iar), + serverCertificate, clientCertificateRequired, enabledSslProtocols, + this); } + + public virtual Task ShutdownAsync() => + Task.Factory.FromAsync( + (callback, state) => ((SslStream)state).BeginShutdown(callback, state), + iar => ((SslStream)iar.AsyncState).EndShutdown(iar), + this); #endregion public override bool IsAuthenticated |