< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.SslStreamSecurityUpgradeProvider
Assembly: CoreWCF.NetFramingBase
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Channels/SslStreamSecurityUpgradeProvider.cs
Line coverage
59%
Covered lines: 50
Uncovered lines: 34
Coverable lines: 84
Total lines: 323
Line coverage: 59.5%
Branch coverage
33%
Covered branches: 10
Total branches: 30
Branch coverage: 33.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Channels/SslStreamSecurityUpgradeProvider.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.ObjectModel;
 6using System.Diagnostics;
 7using System.IO;
 8using System.Net.Security;
 9using System.Security.Authentication;
 10using System.Security.Authentication.ExtendedProtection;
 11using System.Security.Cryptography.X509Certificates;
 12using System.Threading;
 13using System.Threading.Tasks;
 14using CoreWCF.Description;
 15using CoreWCF.IdentityModel.Policy;
 16using CoreWCF.IdentityModel.Selectors;
 17using CoreWCF.IdentityModel.Tokens;
 18using CoreWCF.Runtime;
 19using CoreWCF.Security;
 20using CoreWCF.Security.Tokens;
 21
 22namespace CoreWCF.Channels
 23{
 24    internal class SslStreamSecurityUpgradeProvider : StreamSecurityUpgradeProvider, IStreamUpgradeChannelBindingProvide
 25    {
 26        private SecurityTokenAuthenticator _clientCertificateAuthenticator;
 27        private SecurityTokenProvider _serverTokenProvider;
 28        private EndpointIdentity _identity;
 29        private bool _enableChannelBinding;
 30        // This is the equivalent of X509ClientCertificateAuthentication.DefaultCertificateValidator
 031        private static X509CertificateValidator s_defaultX509CertificateValidator = X509CertificateValidator.CreateChain
 32
 33        private SslStreamSecurityUpgradeProvider(IDefaultCommunicationTimeouts timeouts, SecurityTokenProvider serverTok
 534            : base(timeouts)
 35        {
 536            _serverTokenProvider = serverTokenProvider;
 537            RequireClientCertificate = requireClientCertificate;
 538            _clientCertificateAuthenticator = clientCertificateAuthenticator;
 539            IdentityVerifier = identityVerifier;
 540            Scheme = scheme;
 541            SslProtocols = sslProtocols;
 542            ClientSecurityTokenManager = null; // Used for client but there's public api which need this and the compile
 543        }
 44
 45        public static SslStreamSecurityUpgradeProvider CreateServerProvider(
 46            SslStreamSecurityBindingElement bindingElement, BindingContext context)
 47        {
 548            SecurityCredentialsManager credentialProvider =
 549                context.BindingParameters.Find<SecurityCredentialsManager>();
 50
 551            if (credentialProvider == null)
 52            {
 053                credentialProvider = new ServiceCredentials();
 54            }
 55
 556            Uri listenUri = TransportSecurityHelpers.GetListenUri(context.ListenUriBaseAddress, context.ListenUriRelativ
 557            SecurityTokenManager tokenManager = credentialProvider.CreateSecurityTokenManager();
 58
 559            RecipientServiceModelSecurityTokenRequirement serverCertRequirement = new RecipientServiceModelSecurityToken
 560            {
 561                TokenType = SecurityTokenTypes.X509Certificate,
 562                RequireCryptographicToken = true,
 563                KeyUsage = SecurityKeyUsage.Exchange,
 564                TransportScheme = context.Binding.Scheme,
 565                ListenUri = listenUri
 566            };
 67
 568            SecurityTokenProvider tokenProvider = tokenManager.CreateSecurityTokenProvider(serverCertRequirement);
 569            if (tokenProvider == null)
 70            {
 071                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.Cli
 72            }
 73
 574            SecurityTokenAuthenticator certificateAuthenticator =
 575                TransportSecurityHelpers.GetCertificateTokenAuthenticator(tokenManager, context.Binding.Scheme, listenUr
 76
 577            return new SslStreamSecurityUpgradeProvider(context.Binding, tokenProvider, bindingElement.RequireClientCert
 578                certificateAuthenticator, context.Binding.Scheme, bindingElement.IdentityVerifier, bindingElement.SslPro
 79        }
 80
 81        public override EndpointIdentity Identity
 82        {
 83            get
 84            {
 585                if ((_identity == null) && (ServerCertificate != null))
 86                {
 587                    _identity = SecurityUtils.GetServiceCertificateIdentity(ServerCertificate);
 88                }
 589                return _identity;
 90            }
 91        }
 92
 093        public IdentityVerifier IdentityVerifier { get; }
 94
 1495        public bool RequireClientCertificate { get; }
 96
 2297        public X509Certificate2 ServerCertificate { get; private set; }
 98
 99        public SecurityTokenAuthenticator ClientCertificateAuthenticator
 100        {
 101            get
 102            {
 7103                if (_clientCertificateAuthenticator == null)
 104                {
 0105                    _clientCertificateAuthenticator = new X509SecurityTokenAuthenticator(s_defaultX509CertificateValidat
 106                }
 107
 7108                return _clientCertificateAuthenticator;
 109            }
 110        }
 111
 0112        public SecurityTokenManager ClientSecurityTokenManager { get; }
 113
 0114        public string Scheme { get; }
 115
 7116        public SslProtocols SslProtocols { get; }
 117
 118        public override T GetProperty<T>()
 119        {
 0120            if (typeof(T) == typeof(IChannelBindingProvider) || typeof(T) == typeof(IStreamUpgradeChannelBindingProvider
 121            {
 0122                return (T)(object)this;
 123            }
 0124            return base.GetProperty<T>();
 125        }
 126
 127        ChannelBinding IStreamUpgradeChannelBindingProvider.GetChannelBinding(StreamUpgradeAcceptor upgradeAcceptor, Cha
 128        {
 0129            if (upgradeAcceptor == null)
 130            {
 0131                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(upgradeAcceptor));
 132            }
 133
 134
 0135            if (!(upgradeAcceptor is SslStreamSecurityUpgradeAcceptor sslupgradeAcceptor))
 136            {
 0137                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(upgradeAcceptor), SR.Format(SR.Unsup
 138            }
 139
 0140            if (kind != ChannelBindingKind.Endpoint)
 141            {
 0142                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(kind), SR.Format(SR.StreamUpgradeUns
 143            }
 144
 0145            return sslupgradeAcceptor.ChannelBinding;
 146        }
 147
 148        void IChannelBindingProvider.EnableChannelBindingSupport()
 149        {
 0150            _enableChannelBinding = true;
 0151        }
 152
 153
 7154        bool IChannelBindingProvider.IsChannelBindingSupportEnabled => _enableChannelBinding;
 155
 156        public override StreamUpgradeAcceptor CreateUpgradeAcceptor()
 157        {
 7158            ThrowIfDisposedOrNotOpen();
 7159            return new SslStreamSecurityUpgradeAcceptor(this);
 160        }
 161
 162        protected override void OnAbort()
 163        {
 0164            if (_clientCertificateAuthenticator != null)
 165            {
 0166                SecurityUtils.AbortTokenAuthenticatorIfRequired(_clientCertificateAuthenticator);
 167            }
 0168            CleanupServerCertificate();
 0169        }
 170
 171        protected override async Task OnCloseAsync(CancellationToken token)
 172        {
 0173            if (_clientCertificateAuthenticator != null)
 174            {
 0175                await SecurityUtils.CloseTokenAuthenticatorIfRequiredAsync(_clientCertificateAuthenticator, token);
 176            }
 0177            CleanupServerCertificate();
 0178        }
 179
 180        private void SetupServerCertificate(SecurityToken token)
 181        {
 5182            if (!(token is X509SecurityToken x509Token))
 183            {
 0184                SecurityUtils.AbortTokenProviderIfRequired(_serverTokenProvider);
 0185                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(
 0186                    SR.InvalidTokenProvided, _serverTokenProvider.GetType(), typeof(X509SecurityToken))));
 187            }
 5188            ServerCertificate = new X509Certificate2(x509Token.Certificate);
 5189        }
 190
 191        private void CleanupServerCertificate()
 192        {
 0193            if (ServerCertificate != null)
 194            {
 0195                SecurityUtils.ResetCertificate(ServerCertificate);
 0196                ServerCertificate = null;
 197            }
 0198        }
 199
 200        protected override async Task OnOpenAsync(CancellationToken token)
 201        {
 5202            await SecurityUtils.OpenTokenAuthenticatorIfRequiredAsync(ClientCertificateAuthenticator, token);
 203
 5204            if (_serverTokenProvider != null)
 205            {
 5206                await SecurityUtils.OpenTokenProviderIfRequiredAsync(_serverTokenProvider, token);
 207                // TODO: Solve issue with GetToken/GetTokenAsync needing timeouts and there is only a token available
 5208                SecurityToken securityToken = await _serverTokenProvider.GetTokenAsync(token);
 5209                SetupServerCertificate(securityToken);
 5210                await SecurityUtils.CloseTokenProviderIfRequiredAsync(_serverTokenProvider, token);
 5211                _serverTokenProvider = null;
 212            }
 5213        }
 214    }
 215
 216    internal class SslStreamSecurityUpgradeAcceptor : StreamSecurityUpgradeAcceptorBase
 217    {
 218        private readonly SslStreamSecurityUpgradeProvider _parent;
 219        private SecurityMessageProperty _clientSecurity;
 220
 221        // for audit
 222        private X509Certificate2 _clientCertificate = null;
 223        private ChannelBinding _channelBindingToken;
 224
 225        public SslStreamSecurityUpgradeAcceptor(SslStreamSecurityUpgradeProvider parent)
 226            : base(Framing.FramingUpgradeString.SslOrTls)
 227        {
 228            _parent = parent;
 229            _clientSecurity = new SecurityMessageProperty();
 230        }
 231
 232        internal ChannelBinding ChannelBinding
 233        {
 234            get
 235            {
 236                Fx.Assert(IsChannelBindingSupportEnabled, "A request for the ChannelBinding is not permitted without ena
 237                return _channelBindingToken;
 238            }
 239        }
 240
 241        internal bool IsChannelBindingSupportEnabled => ((IChannelBindingProvider)_parent).IsChannelBindingSupportEnable
 242
 243        protected override async Task<(Stream, SecurityMessageProperty)> OnAcceptUpgradeAsync(Stream stream)
 244        {
 245            var sslStream = new SslStream(stream, false, ValidateRemoteCertificate);
 246
 247            try
 248            {
 249                await sslStream.AuthenticateAsServerAsync(_parent.ServerCertificate, _parent.RequireClientCertificate,
 250                    _parent.SslProtocols, false);
 251            }
 252            catch (AuthenticationException exception)
 253            {
 254                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(exception.Mes
 255                    exception));
 256            }
 257            catch (IOException ioException)
 258            {
 259                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(
 260                    SR.Format(SR.NegotiationFailedIO, ioException.Message), ioException));
 261            }
 262
 263            SecurityMessageProperty remoteSecurity = _clientSecurity;
 264
 265            if (IsChannelBindingSupportEnabled)
 266            {
 267                _channelBindingToken = ChannelBindingUtility.GetToken(sslStream);
 268            }
 269
 270            return (sslStream, remoteSecurity);
 271        }
 272
 273        // callback from schannel
 274        private bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain,
 275            SslPolicyErrors sslPolicyErrors)
 276        {
 277            if (_parent.RequireClientCertificate)
 278            {
 279                if (certificate == null)
 280                {
 281                    return false;
 282                }
 283                // Note: add ref to handle since the caller will reset the cert after the callback return.
 284                X509Certificate2 certificate2 = new X509Certificate2(certificate);
 285                _clientCertificate = certificate2;
 286                try
 287                {
 288                    SecurityToken token = new X509SecurityToken(certificate2, false);
 289                    ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies;
 290                    var validationValueTask = _parent.ClientCertificateAuthenticator.ValidateTokenAsync(token);
 291                    authorizationPolicies = validationValueTask.IsCompleted
 292                        ? validationValueTask.Result
 293                        : validationValueTask.AsTask().GetAwaiter().GetResult();
 294
 295                    _clientSecurity = new SecurityMessageProperty
 296                    {
 297                        TransportToken = new SecurityTokenSpecification(token, authorizationPolicies),
 298                        ServiceSecurityContext = new ServiceSecurityContext(authorizationPolicies)
 299                    };
 300                }
 301                catch (SecurityTokenException e)
 302                {
 303                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
 304                    return false;
 305                }
 306            }
 307            return true;
 308        }
 309
 310        public override SecurityMessageProperty GetRemoteSecurity()
 311        {
 312            if (_clientSecurity.TransportToken != null)
 313            {
 314                return _clientSecurity;
 315            }
 316            if (_clientCertificate != null)
 317            {
 318                return _clientSecurity;
 319            }
 320            return base.GetRemoteSecurity();
 321        }
 322    }
 323}