SslStreamSecurityUpgradeProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / SslStreamSecurityUpgradeProvider.cs / 1 / SslStreamSecurityUpgradeProvider.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------

namespace System.ServiceModel.Channels 
{
    using System.Collections.ObjectModel; 
    using System.ServiceModel; 
    using System.ServiceModel.Description;
    using System.Diagnostics; 
    using System.IO;
    using System.IdentityModel.Policy;
    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens; 
    using System.Net.Security;
    using System.Security.Authentication; 
    using System.Security.Cryptography.X509Certificates; 
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Security; 

    using System.ServiceModel.Security.Tokens;

    class SslStreamSecurityUpgradeProvider : StreamSecurityUpgradeProvider 
    {
        SecurityTokenAuthenticator clientCertificateAuthenticator; 
        SecurityTokenManager clientSecurityTokenManager; 
        SecurityTokenProvider serverTokenProvider;
        EndpointIdentity identity; 
        IdentityVerifier identityVerifier;
        X509Certificate2 serverCertificate;
        bool requireClientCertificate;
        string scheme; 

        SslStreamSecurityUpgradeProvider(IDefaultCommunicationTimeouts timeouts, SecurityTokenManager clientSecurityTokenManager, bool requireClientCertificate, string scheme, IdentityVerifier identityVerifier) 
            : base(timeouts) 
        {
            this.identityVerifier = identityVerifier; 
            this.scheme = scheme;
            this.clientSecurityTokenManager = clientSecurityTokenManager;
            this.requireClientCertificate = requireClientCertificate;
        } 

        SslStreamSecurityUpgradeProvider(IDefaultCommunicationTimeouts timeouts, SecurityTokenProvider serverTokenProvider, bool requireClientCertificate, SecurityTokenAuthenticator clientCertificateAuthenticator, string scheme, IdentityVerifier identityVerifier) 
            : base(timeouts) 
        {
            this.serverTokenProvider = serverTokenProvider; 
            this.requireClientCertificate = requireClientCertificate;
            this.clientCertificateAuthenticator = clientCertificateAuthenticator;
            this.identityVerifier = identityVerifier;
            this.scheme = scheme; 
        }
 
        public static SslStreamSecurityUpgradeProvider CreateClientProvider( 
            SslStreamSecurityBindingElement bindingElement, BindingContext context)
        { 
            SecurityCredentialsManager credentialProvider = context.BindingParameters.Find();

            if (credentialProvider == null)
            { 
                credentialProvider = ClientCredentials.CreateDefaultCredentials();
            } 
            SecurityTokenManager tokenManager = credentialProvider.CreateSecurityTokenManager(); 

            return new SslStreamSecurityUpgradeProvider(context.Binding, tokenManager, bindingElement.RequireClientCertificate, context.Binding.Scheme, bindingElement.IdentityVerifier); 
        }

        public static SslStreamSecurityUpgradeProvider CreateServerProvider(
            SslStreamSecurityBindingElement bindingElement, BindingContext context) 
        {
            SecurityCredentialsManager credentialProvider = 
                context.BindingParameters.Find(); 

            if (credentialProvider == null) 
            {
                credentialProvider = ServiceCredentials.CreateDefaultCredentials();
            }
 
            SecurityTokenManager tokenManager = credentialProvider.CreateSecurityTokenManager();
 
            RecipientServiceModelSecurityTokenRequirement serverCertRequirement = new RecipientServiceModelSecurityTokenRequirement(); 
            serverCertRequirement.TokenType = SecurityTokenTypes.X509Certificate;
            serverCertRequirement.RequireCryptographicToken = true; 
            serverCertRequirement.KeyUsage = SecurityKeyUsage.Exchange;
            serverCertRequirement.TransportScheme = context.Binding.Scheme;
            SecurityTokenProvider tokenProvider = tokenManager.CreateSecurityTokenProvider(serverCertRequirement);
            if (tokenProvider == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ClientCredentialsUnableToCreateLocalTokenProvider, serverCertRequirement))); 
            } 

            SecurityTokenAuthenticator certificateAuthenticator = 
                TransportSecurityHelpers.GetCertificateTokenAuthenticator(tokenManager, context.Binding.Scheme);

            return new SslStreamSecurityUpgradeProvider(context.Binding, tokenProvider, bindingElement.RequireClientCertificate,
                certificateAuthenticator, context.Binding.Scheme, bindingElement.IdentityVerifier); 
        }
 
        public override EndpointIdentity Identity 
        {
            get 
            {
                if ((this.identity == null) && (this.serverCertificate != null))
                {
                    this.identity = SecurityUtils.GetServiceCertificateIdentity(this.serverCertificate); 
                }
                return this.identity; 
            } 
        }
 
        public IdentityVerifier IdentityVerifier
        {
            get
            { 
                return this.identityVerifier;
            } 
        } 

        public bool RequireClientCertificate 
        {
            get
            {
                return this.requireClientCertificate; 
            }
        } 
 
        public X509Certificate2 ServerCertificate
        { 
            get
            {
                return this.serverCertificate;
            } 
        }
 
        public SecurityTokenAuthenticator ClientCertificateAuthenticator 
        {
            get 
            {
                if (this.clientCertificateAuthenticator == null)
                {
                    this.clientCertificateAuthenticator = new X509SecurityTokenAuthenticator(X509ClientCertificateAuthentication.DefaultCertificateValidator); 
                }
 
                return this.clientCertificateAuthenticator; 
            }
        } 

        public SecurityTokenManager ClientSecurityTokenManager
        {
            get 
            {
                return this.clientSecurityTokenManager; 
            } 
        }
 
        public string Scheme
        {
            get { return this.scheme; }
        } 

        public override StreamUpgradeAcceptor CreateUpgradeAcceptor() 
        { 
            ThrowIfDisposedOrNotOpen();
            return new SslStreamSecurityUpgradeAcceptor(this); 
        }

        public override StreamUpgradeInitiator CreateUpgradeInitiator(EndpointAddress remoteAddress, Uri via)
        { 
            ThrowIfDisposedOrNotOpen();
            return new SslStreamSecurityUpgradeInitiator(this, remoteAddress, via); 
        } 

        protected override void OnAbort() 
        {
            if (this.clientCertificateAuthenticator != null)
            {
                SecurityUtils.AbortTokenAuthenticatorIfRequired(this.clientCertificateAuthenticator); 
            }
            CleanupServerCertificate(); 
        } 

        protected override void OnClose(TimeSpan timeout) 
        {
            if (this.clientCertificateAuthenticator != null)
            {
                SecurityUtils.CloseTokenAuthenticatorIfRequired(this.clientCertificateAuthenticator, timeout); 
            }
            CleanupServerCertificate(); 
        } 

        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) 
        {
            return SecurityUtils.BeginCloseTokenAuthenticatorIfRequired(this.clientCertificateAuthenticator, timeout, callback, state);
        }
 
        protected override void OnEndClose(IAsyncResult result)
        { 
            SecurityUtils.EndCloseTokenAuthenticatorIfRequired(result); 
            CleanupServerCertificate();
        } 

        void SetupServerCertificate(SecurityToken token)
        {
            X509SecurityToken x509Token = token as X509SecurityToken; 
            if (x509Token == null)
            { 
                SecurityUtils.AbortTokenProviderIfRequired(this.serverTokenProvider); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
                    SR.InvalidTokenProvided, this.serverTokenProvider.GetType(), typeof(X509SecurityToken)))); 
            }
            this.serverCertificate = new X509Certificate2(x509Token.Certificate);
        }
 
        void CleanupServerCertificate()
        { 
            if (this.serverCertificate != null) 
            {
                this.serverCertificate.Reset(); 
                this.serverCertificate = null;
            }
        }
 
        protected override void OnOpen(TimeSpan timeout)
        { 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
            SecurityUtils.OpenTokenAuthenticatorIfRequired(this.ClientCertificateAuthenticator, timeoutHelper.RemainingTime());
 
            if (this.serverTokenProvider != null)
            {
                SecurityUtils.OpenTokenProviderIfRequired(this.serverTokenProvider, timeoutHelper.RemainingTime());
                SecurityToken token = this.serverTokenProvider.GetToken(timeout); 
                SetupServerCertificate(token);
                SecurityUtils.CloseTokenProviderIfRequired(this.serverTokenProvider, timeoutHelper.RemainingTime()); 
                this.serverTokenProvider = null; 
            }
        } 

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new OpenAsyncResult(this, timeout, callback, state); 
        }
 
        protected override void OnEndOpen(IAsyncResult result) 
        {
            OpenAsyncResult.End(result); 
        }

        class OpenAsyncResult : AsyncResult
        { 
            SslStreamSecurityUpgradeProvider parent;
            TimeoutHelper timeoutHelper; 
            AsyncCallback onOpenTokenAuthenticator; 
            AsyncCallback onOpenTokenProvider;
            AsyncCallback onGetToken; 
            AsyncCallback onCloseTokenProvider;

            public OpenAsyncResult(SslStreamSecurityUpgradeProvider parent, TimeSpan timeout,
                AsyncCallback callback, object state) 
                : base(callback, state)
            { 
                this.parent = parent; 
                this.timeoutHelper = new TimeoutHelper(timeout);
 
                // since we're at channel.Open and not per-message, minimize our statics overhead and leverage GC for our callbacks
                this.onOpenTokenAuthenticator = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnOpenTokenAuthenticator));
                IAsyncResult result = SecurityUtils.BeginOpenTokenAuthenticatorIfRequired(parent.ClientCertificateAuthenticator,
                    timeoutHelper.RemainingTime(), onOpenTokenAuthenticator, this); 

                if (!result.CompletedSynchronously) 
                { 
                    return;
                } 

                if (HandleOpenAuthenticatorComplete(result))
                {
                    base.Complete(true); 
                }
            } 
 
            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result);
            }

            bool HandleOpenAuthenticatorComplete(IAsyncResult result) 
            {
                SecurityUtils.EndOpenTokenAuthenticatorIfRequired(result); 
                if (parent.serverTokenProvider == null) 
                {
                    return true; 
                }

                this.onOpenTokenProvider = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnOpenTokenProvider));
                IAsyncResult openTokenProviderResult = SecurityUtils.BeginOpenTokenProviderIfRequired( 
                    parent.serverTokenProvider, timeoutHelper.RemainingTime(), onOpenTokenProvider, this);
 
                if (!openTokenProviderResult.CompletedSynchronously) 
                {
                    return false; 
                }

                return HandleOpenTokenProviderComplete(openTokenProviderResult);
            } 

            bool HandleOpenTokenProviderComplete(IAsyncResult result) 
            { 
                SecurityUtils.EndOpenTokenProviderIfRequired(result);
                this.onGetToken = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetToken)); 

                IAsyncResult getTokenResult = parent.serverTokenProvider.BeginGetToken(timeoutHelper.RemainingTime(),
                    onGetToken, this);
 
                if (!getTokenResult.CompletedSynchronously)
                { 
                    return false; 
                }
 
                return HandleGetTokenComplete(getTokenResult);
            }

            bool HandleGetTokenComplete(IAsyncResult result) 
            {
                SecurityToken token = parent.serverTokenProvider.EndGetToken(result); 
                parent.SetupServerCertificate(token); 
                this.onCloseTokenProvider = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnCloseTokenProvider));
                IAsyncResult closeTokenProviderResult = 
                    SecurityUtils.BeginCloseTokenProviderIfRequired(parent.serverTokenProvider, timeoutHelper.RemainingTime(),
                    onCloseTokenProvider, this);

                if (!closeTokenProviderResult.CompletedSynchronously) 
                {
                    return false; 
                } 

                return HandleCloseTokenProviderComplete(closeTokenProviderResult); 
            }

            bool HandleCloseTokenProviderComplete(IAsyncResult result)
            { 
                SecurityUtils.EndCloseTokenProviderIfRequired(result);
                parent.serverTokenProvider = null; 
                return true; 
            }
 
            void OnOpenTokenAuthenticator(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                { 
                    return;
                } 
 
                Exception completionException = null;
                bool completeSelf = false; 
                try
                {
                    completeSelf = this.HandleOpenAuthenticatorComplete(result);
                } 
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e) 
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw;
                    }

                    completeSelf = true; 
                    completionException = e;
                } 
 
                if (completeSelf)
                { 
                    base.Complete(false, completionException);
                }
            }
 
            void OnOpenTokenProvider(IAsyncResult result)
            { 
                if (result.CompletedSynchronously) 
                {
                    return; 
                }

                Exception completionException = null;
                bool completeSelf = false; 
                try
                { 
                    completeSelf = this.HandleOpenTokenProviderComplete(result); 
                }
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e))
                    { 
                        throw;
                    } 
 
                    completeSelf = true;
                    completionException = e; 
                }

                if (completeSelf)
                { 
                    base.Complete(false, completionException);
                } 
            } 

            void OnGetToken(IAsyncResult result) 
            {
                if (result.CompletedSynchronously)
                {
                    return; 
                }
 
                Exception completionException = null; 
                bool completeSelf = false;
                try 
                {
                    completeSelf = this.HandleGetTokenComplete(result);
                }
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw; 
                    }

                    completeSelf = true;
                    completionException = e; 
                }
 
                if (completeSelf) 
                {
                    base.Complete(false, completionException); 
                }
            }

            void OnCloseTokenProvider(IAsyncResult result) 
            {
                if (result.CompletedSynchronously) 
                { 
                    return;
                } 

                Exception completionException = null;
                bool completeSelf = false;
                try 
                {
                    completeSelf = this.HandleCloseTokenProviderComplete(result); 
                } 
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e))
                    {
                        throw; 
                    }
 
                    completeSelf = true; 
                    completionException = e;
                } 

                if (completeSelf)
                {
                    base.Complete(false, completionException); 
                }
            } 
 
        }
    } 

    class SslStreamSecurityUpgradeAcceptor : StreamSecurityUpgradeAcceptorBase
    {
        SslStreamSecurityUpgradeProvider parent; 
        SecurityMessageProperty clientSecurity;
        // for audit 
        X509Certificate2 clientCertificate = null; 

        public SslStreamSecurityUpgradeAcceptor(SslStreamSecurityUpgradeProvider parent) 
            : base(FramingUpgradeString.SslOrTls)
        {
            this.parent = parent;
            this.clientSecurity = new SecurityMessageProperty(); 
        }
 
        protected override Stream OnAcceptUpgrade(Stream stream, out SecurityMessageProperty remoteSecurity) 
        {
            SslStream sslStream = new SslStream(stream, false, this.ValidateRemoteCertificate); 

            try
            {
                sslStream.AuthenticateAsServer(this.parent.ServerCertificate, this.parent.RequireClientCertificate, 
                    SslProtocols.Default, false);
            } 
            catch (AuthenticationException exception) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(exception.Message, 
                    exception));
            }
            catch (IOException ioException)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(
                    SR.GetString(SR.NegotiationFailedIO, ioException.Message), ioException)); 
            } 
            if (SecurityUtils.ShouldValidateSslCipherStrength())
            { 
                SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
            }

            remoteSecurity = this.clientSecurity; 
            return sslStream;
        } 
 
        protected override IAsyncResult OnBeginAcceptUpgrade(Stream stream, AsyncCallback callback, object state)
        { 
            AcceptUpgradeAsyncResult result = new AcceptUpgradeAsyncResult(this, callback, state);
            result.Begin(stream);
            return result;
        } 

        protected override Stream OnEndAcceptUpgrade(IAsyncResult result, out SecurityMessageProperty remoteSecurity) 
        { 
            return AcceptUpgradeAsyncResult.End(result, out remoteSecurity);
        } 

        bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
        { 
            if (this.parent.RequireClientCertificate)
            { 
                if (certificate == null) 
                {
                    if (DiagnosticUtility.ShouldTraceError) 
                    {
                        TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.SslClientCertMissing, this);
                    }
                    return false; 
                }
                // Note: add ref to handle since the caller will reset the cert after the callback return. 
                X509Certificate2 certificate2 = new X509Certificate2(certificate); 
                this.clientCertificate = certificate2;
                try 
                {
                    SecurityToken token = new X509SecurityToken(certificate2, false);
                    ReadOnlyCollection authorizationPolicies = this.parent.ClientCertificateAuthenticator.ValidateToken(token);
                    this.clientSecurity = new SecurityMessageProperty(); 
                    this.clientSecurity.TransportToken = new SecurityTokenSpecification(token, authorizationPolicies);
                    this.clientSecurity.ServiceSecurityContext = new ServiceSecurityContext(authorizationPolicies); 
                } 
                catch (SecurityTokenException e)
                { 
                    if (DiagnosticUtility.ShouldTraceInformation)
                    {
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
                    } 
                    return false;
                } 
            } 
            return true;
        } 

        public override SecurityMessageProperty GetRemoteSecurity()
        {
            if (this.clientSecurity.TransportToken != null) 
            {
                return this.clientSecurity; 
            } 
            if (this.clientCertificate != null)
            { 
                SecurityToken token = new X509SecurityToken(this.clientCertificate);
                ReadOnlyCollection authorizationPolicies = SecurityUtils.NonValidatingX509Authenticator.ValidateToken(token);
                this.clientSecurity = new SecurityMessageProperty();
                this.clientSecurity.TransportToken = new SecurityTokenSpecification(token, authorizationPolicies); 
                this.clientSecurity.ServiceSecurityContext = new ServiceSecurityContext(authorizationPolicies);
                return this.clientSecurity; 
            } 
            return base.GetRemoteSecurity();
        } 

        class AcceptUpgradeAsyncResult : StreamSecurityUpgradeAcceptorAsyncResult
        {
            SslStreamSecurityUpgradeAcceptor acceptor; 
            SslStream sslStream;
 
            public AcceptUpgradeAsyncResult(SslStreamSecurityUpgradeAcceptor acceptor, AsyncCallback callback, 
                object state)
                : base(callback, state) 
            {
                this.acceptor = acceptor;
            }
 
            protected override IAsyncResult OnBegin(Stream stream, AsyncCallback callback)
            { 
                this.sslStream = new SslStream(stream, false, this.acceptor.ValidateRemoteCertificate); 
                return this.sslStream.BeginAuthenticateAsServer(this.acceptor.parent.ServerCertificate,
                    this.acceptor.parent.RequireClientCertificate, SslProtocols.Default, false, callback, this); 
            }

            protected override Stream OnCompleteAuthenticateAsServer(IAsyncResult result)
            { 
                this.sslStream.EndAuthenticateAsServer(result);
                if (SecurityUtils.ShouldValidateSslCipherStrength()) 
                { 
                    SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
                } 
                return this.sslStream;
            }

            protected override SecurityMessageProperty ValidateCreateSecurity() 
            {
                return this.acceptor.clientSecurity; 
            } 
        }
    } 

    class SslStreamSecurityUpgradeInitiator : StreamSecurityUpgradeInitiatorBase
    {
        SslStreamSecurityUpgradeProvider parent; 
        SecurityMessageProperty serverSecurity;
        SecurityTokenProvider clientCertificateProvider; 
        X509SecurityToken clientToken; 
        SecurityTokenAuthenticator serverCertificateAuthenticator;
 
        static LocalCertificateSelectionCallback clientCertificateSelectionCallback;

        public SslStreamSecurityUpgradeInitiator(SslStreamSecurityUpgradeProvider parent,
            EndpointAddress remoteAddress, Uri via) 
            : base(FramingUpgradeString.SslOrTls, remoteAddress, via)
        { 
            this.parent = parent; 

            InitiatorServiceModelSecurityTokenRequirement serverCertRequirement = new InitiatorServiceModelSecurityTokenRequirement(); 
            serverCertRequirement.TokenType = SecurityTokenTypes.X509Certificate;
            serverCertRequirement.RequireCryptographicToken = true;
            serverCertRequirement.KeyUsage = SecurityKeyUsage.Exchange;
            serverCertRequirement.TargetAddress = remoteAddress; 
            serverCertRequirement.Via = via;
            serverCertRequirement.TransportScheme = this.parent.Scheme; 
            SecurityTokenResolver dummy; 
            this.serverCertificateAuthenticator = (parent.ClientSecurityTokenManager.CreateSecurityTokenAuthenticator(serverCertRequirement, out dummy));
 
            if (parent.RequireClientCertificate)
            {
                InitiatorServiceModelSecurityTokenRequirement clientCertRequirement = new InitiatorServiceModelSecurityTokenRequirement();
                clientCertRequirement.TokenType = SecurityTokenTypes.X509Certificate; 
                clientCertRequirement.RequireCryptographicToken = true;
                clientCertRequirement.KeyUsage = SecurityKeyUsage.Signature; 
                clientCertRequirement.TargetAddress = remoteAddress; 
                clientCertRequirement.Via = via;
                clientCertRequirement.TransportScheme = this.parent.Scheme; 
                this.clientCertificateProvider = parent.ClientSecurityTokenManager.CreateSecurityTokenProvider(clientCertRequirement);
                if (clientCertificateProvider == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ClientCredentialsUnableToCreateLocalTokenProvider, clientCertRequirement))); 
                }
            } 
        } 

        static LocalCertificateSelectionCallback ClientCertificateSelectionCallback 
        {
            get
            {
                if (clientCertificateSelectionCallback == null) 
                {
                    clientCertificateSelectionCallback = new LocalCertificateSelectionCallback(SelectClientCertificate); 
                } 
                return clientCertificateSelectionCallback;
            } 
        }

        IAsyncResult BaseBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        { 
            return base.BeginOpen(timeout, callback, state);
        } 
 
        void BaseEndOpen(IAsyncResult result)
        { 
            base.EndOpen(result);
        }

        internal override IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state) 
        {
            return new OpenAsyncResult(this, timeout, callback, state); 
        } 

        internal override void EndOpen(IAsyncResult result) 
        {
            OpenAsyncResult.End(result);
        }
 
        internal override void Open(TimeSpan timeout)
        { 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
            base.Open(timeoutHelper.RemainingTime());
            if (this.clientCertificateProvider != null) 
            {
                SecurityUtils.OpenTokenProviderIfRequired(this.clientCertificateProvider, timeoutHelper.RemainingTime());
                this.clientToken = (X509SecurityToken)this.clientCertificateProvider.GetToken(timeoutHelper.RemainingTime());
            } 
        }
 
        IAsyncResult BaseBeginClose(TimeSpan timeout, AsyncCallback callback, object state) 
        {
            return base.BeginClose(timeout, callback, state); 
        }

        void BaseEndClose(IAsyncResult result)
        { 
            base.EndClose(result);
        } 
 
        internal override IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        { 
            return new CloseAsyncResult(this, timeout, callback, state);
        }

        internal override void EndClose(IAsyncResult result) 
        {
            CloseAsyncResult.End(result); 
        } 

        internal override void Close(TimeSpan timeout) 
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            base.Close(timeoutHelper.RemainingTime());
            if (this.clientCertificateProvider != null) 
            {
                SecurityUtils.CloseTokenProviderIfRequired(this.clientCertificateProvider, timeoutHelper.RemainingTime()); 
            } 
        }
 
        protected override IAsyncResult OnBeginInitiateUpgrade(Stream stream, AsyncCallback callback, object state)
        {
            InitiateUpgradeAsyncResult result = new InitiateUpgradeAsyncResult(this, callback, state);
            result.Begin(stream); 
            return result;
        } 
 
        protected override Stream OnEndInitiateUpgrade(IAsyncResult result,
            out SecurityMessageProperty remoteSecurity) 
        {
            return InitiateUpgradeAsyncResult.End(result, out remoteSecurity);
        }
 
        protected override Stream OnInitiateUpgrade(Stream stream, out SecurityMessageProperty remoteSecurity)
        { 
            X509CertificateCollection clientCertificates = null; 
            LocalCertificateSelectionCallback selectionCallback = null;
            if (this.clientToken != null) 
            {
                clientCertificates = new X509CertificateCollection();
                clientCertificates.Add(clientToken.Certificate);
                selectionCallback = ClientCertificateSelectionCallback; 
            }
 
            SslStream sslStream = new SslStream(stream, false, this.ValidateRemoteCertificate, selectionCallback); 
            try
            { 
                sslStream.AuthenticateAsClient(string.Empty, clientCertificates, SslProtocols.Default, false);
            }
            catch (SecurityTokenValidationException tokenValidationException)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(tokenValidationException.Message,
                    tokenValidationException)); 
            } 
            catch (AuthenticationException exception)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(exception.Message,
                    exception));
            }
            catch (IOException ioException) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException( 
                    SR.GetString(SR.NegotiationFailedIO, ioException.Message), ioException)); 
            }
 
            if (SecurityUtils.ShouldValidateSslCipherStrength())
            {
                SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
            } 

            remoteSecurity = this.serverSecurity; 
            return sslStream; 
        }
 
        static X509Certificate SelectClientCertificate(object sender, string targetHost,
            X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
        {
            return localCertificates[0]; 
        }
 
        bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, 
            SslPolicyErrors sslPolicyErrors)
        { 
            // Note: add ref to handle since the caller will reset the cert after the callback return.
            X509Certificate2 certificate2 = new X509Certificate2(certificate);
            SecurityToken token = new X509SecurityToken(certificate2, false);
            ReadOnlyCollection authorizationPolicies = this.serverCertificateAuthenticator.ValidateToken(token); 
            this.serverSecurity = new SecurityMessageProperty();
            this.serverSecurity.TransportToken = new SecurityTokenSpecification(token, authorizationPolicies); 
            this.serverSecurity.ServiceSecurityContext = new ServiceSecurityContext(authorizationPolicies); 

            AuthorizationContext authzContext = this.serverSecurity.ServiceSecurityContext.AuthorizationContext; 
            this.parent.IdentityVerifier.EnsureOutgoingIdentity(this.RemoteAddress, this.Via, authzContext);

            return true;
        } 

        class InitiateUpgradeAsyncResult : StreamSecurityUpgradeInitiatorAsyncResult 
        { 
            X509CertificateCollection clientCertificates;
            SslStreamSecurityUpgradeInitiator initiator; 
            LocalCertificateSelectionCallback selectionCallback;
            SslStream sslStream;

            public InitiateUpgradeAsyncResult(SslStreamSecurityUpgradeInitiator initiator, AsyncCallback callback, 
                object state)
                : base(callback, state) 
            { 
                this.initiator = initiator;
                if (initiator.clientToken != null) 
                {
                    this.clientCertificates = new X509CertificateCollection();
                    this.clientCertificates.Add(initiator.clientToken.Certificate);
                    this.selectionCallback = ClientCertificateSelectionCallback; 
                }
            } 
 
            protected override IAsyncResult OnBeginAuthenticateAsClient(Stream stream, AsyncCallback callback)
            { 
                this.sslStream = new SslStream(stream, false, this.initiator.ValidateRemoteCertificate,
                    this.selectionCallback);

                try 
                {
                    return this.sslStream.BeginAuthenticateAsClient(string.Empty, this.clientCertificates, 
                        SslProtocols.Default, false, callback, this); 
                }
                catch (SecurityTokenValidationException tokenValidationException) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(tokenValidationException.Message,
                        tokenValidationException));
                } 
            }
 
            protected override Stream OnCompleteAuthenticateAsClient(IAsyncResult result) 
            {
                try 
                {
                    this.sslStream.EndAuthenticateAsClient(result);
                }
                catch (SecurityTokenValidationException tokenValidationException) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(tokenValidationException.Message, 
                        tokenValidationException)); 
                }
 
                if (SecurityUtils.ShouldValidateSslCipherStrength())
                {
                    SecurityUtils.ValidateSslCipherStrength(sslStream.CipherStrength);
                } 

                return this.sslStream; 
            } 

            protected override SecurityMessageProperty ValidateCreateSecurity() 
            {
                return this.initiator.serverSecurity;
            }
        } 

        class OpenAsyncResult : AsyncResult 
        { 
            SslStreamSecurityUpgradeInitiator parent;
            TimeoutHelper timeoutHelper; 
            AsyncCallback onBaseOpen;
            AsyncCallback onOpenTokenProvider;
            AsyncCallback onGetClientToken;
 
            public OpenAsyncResult(SslStreamSecurityUpgradeInitiator parent, TimeSpan timeout,
                AsyncCallback callback, object state) 
                : base(callback, state) 
            {
                this.parent = parent; 
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);

                // since we're at channel.Open and not per-message, minimize our statics overhead and leverage GC for our callback
                this.onBaseOpen = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnBaseOpen)); 
                if (parent.clientCertificateProvider != null)
                { 
                    this.onOpenTokenProvider = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnOpenTokenProvider)); 
                    this.onGetClientToken = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnGetClientToken));
                } 
                IAsyncResult result = parent.BaseBeginOpen(timeoutHelper.RemainingTime(), onBaseOpen, this);

                if (!result.CompletedSynchronously)
                { 
                    return;
                } 
 
                if (HandleBaseOpenComplete(result))
                { 
                    base.Complete(true);
                }
            }
 
            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result); 
            }
 
            bool HandleBaseOpenComplete(IAsyncResult result)
            {
                parent.BaseEndOpen(result);
                if (parent.clientCertificateProvider == null) 
                {
                    return true; 
                } 

                IAsyncResult openTokenProviderResult = SecurityUtils.BeginOpenTokenProviderIfRequired( 
                    parent.clientCertificateProvider, timeoutHelper.RemainingTime(), onOpenTokenProvider, this);

                if (!openTokenProviderResult.CompletedSynchronously)
                { 
                    return false;
                } 
 
                return HandleOpenTokenProviderComplete(openTokenProviderResult);
            } 

            bool HandleOpenTokenProviderComplete(IAsyncResult result)
            {
                SecurityUtils.EndOpenTokenProviderIfRequired(result); 
                IAsyncResult getTokenResult = parent.clientCertificateProvider.BeginGetToken(timeoutHelper.RemainingTime(),
                    onGetClientToken, this); 
 
                if (!getTokenResult.CompletedSynchronously)
                { 
                    return false;
                }

                return HandleGetTokenComplete(getTokenResult); 
            }
 
            bool HandleGetTokenComplete(IAsyncResult result) 
            {
                parent.clientToken = (X509SecurityToken)parent.clientCertificateProvider.EndGetToken(result); 
                return true;
            }

            void OnBaseOpen(IAsyncResult result) 
            {
                if (result.CompletedSynchronously) 
                { 
                    return;
                } 

                Exception completionException = null;
                bool completeSelf = false;
                try 
                {
                    completeSelf = this.HandleBaseOpenComplete(result); 
                } 
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e))
                    {
                        throw; 
                    }
 
                    completeSelf = true; 
                    completionException = e;
                } 

                if (completeSelf)
                {
                    base.Complete(false, completionException); 
                }
            } 
 
            void OnOpenTokenProvider(IAsyncResult result)
            { 
                if (result.CompletedSynchronously)
                {
                    return;
                } 

                Exception completionException = null; 
                bool completeSelf = false; 
                try
                { 
                    completeSelf = this.HandleOpenTokenProviderComplete(result);
                }
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e) 
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                    { 
                        throw;
                    } 

                    completeSelf = true;
                    completionException = e;
                } 

                if (completeSelf) 
                { 
                    base.Complete(false, completionException);
                } 
            }

            void OnGetClientToken(IAsyncResult result)
            { 
                if (result.CompletedSynchronously)
                { 
                    return; 
                }
 
                Exception completionException = null;
                bool completeSelf = false;
                try
                { 
                    completeSelf = this.HandleGetTokenComplete(result);
                } 
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    {
                        throw;
                    } 

                    completeSelf = true; 
                    completionException = e; 
                }
 
                if (completeSelf)
                {
                    base.Complete(false, completionException);
                } 
            }
        } 
 
        class CloseAsyncResult : AsyncResult
        { 
            SslStreamSecurityUpgradeInitiator parent;
            TimeoutHelper timeoutHelper;
            AsyncCallback onBaseClose;
            AsyncCallback onCloseTokenProvider; 

            public CloseAsyncResult(SslStreamSecurityUpgradeInitiator parent, TimeSpan timeout, 
                AsyncCallback callback, object state) 
                : base(callback, state)
            { 
                this.parent = parent;
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);

                // since we're at channel.Open and not per-message, minimize our statics overhead and leverage GC for our callback 
                this.onBaseClose = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnBaseClose));
                if (parent.clientCertificateProvider != null) 
                { 
                    this.onCloseTokenProvider = DiagnosticUtility.ThunkAsyncCallback(new AsyncCallback(OnCloseTokenProvider));
                } 
                IAsyncResult result = parent.BaseBeginClose(timeoutHelper.RemainingTime(), onBaseClose, this);

                if (!result.CompletedSynchronously)
                { 
                    return;
                } 
 
                if (HandleBaseCloseComplete(result))
                { 
                    base.Complete(true);
                }
            }
 
            public static void End(IAsyncResult result)
            { 
                AsyncResult.End(result); 
            }
 
            bool HandleBaseCloseComplete(IAsyncResult result)
            {
                parent.BaseEndClose(result);
                if (parent.clientCertificateProvider == null) 
                {
                    return true; 
                } 

                IAsyncResult closeTokenProviderResult = SecurityUtils.BeginCloseTokenProviderIfRequired( 
                    parent.clientCertificateProvider, timeoutHelper.RemainingTime(), onCloseTokenProvider, this);

                if (!closeTokenProviderResult.CompletedSynchronously)
                { 
                    return false;
                } 
 
                SecurityUtils.EndCloseTokenProviderIfRequired(closeTokenProviderResult);
                return true; 
            }

            void OnBaseClose(IAsyncResult result)
            { 
                if (result.CompletedSynchronously)
                { 
                    return; 
                }
 
                Exception completionException = null;
                bool completeSelf = false;
                try
                { 
                    completeSelf = this.HandleBaseCloseComplete(result);
                } 
#pragma warning suppress 56500 // [....], transferring exception to another thread 
                catch (Exception e)
                { 
                    if (DiagnosticUtility.IsFatal(e))
                    {
                        throw;
                    } 

                    completeSelf = true; 
                    completionException = e; 
                }
 
                if (completeSelf)
                {
                    base.Complete(false, completionException);
                } 
            }
 
            void OnCloseTokenProvider(IAsyncResult result) 
            {
                if (result.CompletedSynchronously) 
                {
                    return;
                }
 
                Exception completionException = null;
                try 
                { 
                    SecurityUtils.EndCloseTokenProviderIfRequired(result);
                } 
#pragma warning suppress 56500 // [....], transferring exception to another thread
                catch (Exception e)
                {
                    if (DiagnosticUtility.IsFatal(e)) 
                    {
                        throw; 
                    } 

                    completionException = e; 
                }

                base.Complete(false, completionException);
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK