File: System\ServiceModel\Channels\SecurityBindingElement.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Channels
{
    using System;
    using System.Diagnostics;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens;
    using System.Net.Security;
    using System.Runtime;
    using System.Security.Authentication.ExtendedProtection;
    using System.ServiceModel;
    using System.ServiceModel.Configuration;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Description;
    using System.ServiceModel.Security;
    using System.ServiceModel.Security.Tokens;
    using System.Text;
    using System.Xml;
 
    public abstract class SecurityBindingElement : BindingElement
    {
        internal const string defaultAlgorithmSuiteString = ConfigurationStrings.Default;
        internal static readonly SecurityAlgorithmSuite defaultDefaultAlgorithmSuite = SecurityAlgorithmSuite.Default;
        internal const bool defaultIncludeTimestamp = true;
        internal const bool defaultAllowInsecureTransport = false;
        internal const MessageProtectionOrder defaultMessageProtectionOrder = MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature;
        internal const bool defaultRequireSignatureConfirmation = false;
        internal const bool defaultEnableUnsecuredResponse = false;
        internal const bool defaultProtectTokens = false;
        
        SecurityAlgorithmSuite defaultAlgorithmSuite;
        SupportingTokenParameters endpointSupportingTokenParameters;
        SupportingTokenParameters optionalEndpointSupportingTokenParameters;
        bool includeTimestamp;
        SecurityKeyEntropyMode keyEntropyMode;
        Dictionary<string, SupportingTokenParameters> operationSupportingTokenParameters;
        Dictionary<string, SupportingTokenParameters> optionalOperationSupportingTokenParameters;
        LocalClientSecuritySettings localClientSettings;
        LocalServiceSecuritySettings localServiceSettings;
        MessageSecurityVersion messageSecurityVersion;
        SecurityHeaderLayout securityHeaderLayout;
        InternalDuplexBindingElement internalDuplexBindingElement;
        long maxReceivedMessageSize = TransportDefaults.MaxReceivedMessageSize;
        XmlDictionaryReaderQuotas readerQuotas;
        bool doNotEmitTrust = false; // true if user create a basic http standard binding, the custombinding equivalent will not set this flag 
        bool supportsExtendedProtectionPolicy;
        bool allowInsecureTransport;
        bool enableUnsecuredResponse;
        bool protectTokens = defaultProtectTokens;
 
        internal SecurityBindingElement()
            : base()
        {
            this.messageSecurityVersion = MessageSecurityVersion.Default;
            this.keyEntropyMode = AcceleratedTokenProvider.defaultKeyEntropyMode;
            this.includeTimestamp = defaultIncludeTimestamp;
            this.defaultAlgorithmSuite = defaultDefaultAlgorithmSuite;
            this.localClientSettings = new LocalClientSecuritySettings();
            this.localServiceSettings = new LocalServiceSecuritySettings();
            this.endpointSupportingTokenParameters = new SupportingTokenParameters();
            this.optionalEndpointSupportingTokenParameters = new SupportingTokenParameters();
            this.operationSupportingTokenParameters = new Dictionary<string, SupportingTokenParameters>();
            this.optionalOperationSupportingTokenParameters = new Dictionary<string, SupportingTokenParameters>();
            this.securityHeaderLayout = SecurityProtocolFactory.defaultSecurityHeaderLayout;
            this.allowInsecureTransport = defaultAllowInsecureTransport;
            this.enableUnsecuredResponse = defaultEnableUnsecuredResponse;
            this.protectTokens = defaultProtectTokens;
        }
 
        internal SecurityBindingElement(SecurityBindingElement elementToBeCloned)
            : base(elementToBeCloned)
        {
            if (elementToBeCloned == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("elementToBeCloned");
 
            this.defaultAlgorithmSuite = elementToBeCloned.defaultAlgorithmSuite;
            this.includeTimestamp = elementToBeCloned.includeTimestamp;
            this.keyEntropyMode = elementToBeCloned.keyEntropyMode;
            this.messageSecurityVersion = elementToBeCloned.messageSecurityVersion;
            this.securityHeaderLayout = elementToBeCloned.securityHeaderLayout;
            this.endpointSupportingTokenParameters = (SupportingTokenParameters)elementToBeCloned.endpointSupportingTokenParameters.Clone();
            this.optionalEndpointSupportingTokenParameters = (SupportingTokenParameters)elementToBeCloned.optionalEndpointSupportingTokenParameters.Clone();
            this.operationSupportingTokenParameters = new Dictionary<string, SupportingTokenParameters>();
            foreach (string key in elementToBeCloned.operationSupportingTokenParameters.Keys)
            {
                this.operationSupportingTokenParameters[key] = (SupportingTokenParameters)elementToBeCloned.operationSupportingTokenParameters[key].Clone();
            }
            this.optionalOperationSupportingTokenParameters = new Dictionary<string, SupportingTokenParameters>();
            foreach (string key in elementToBeCloned.optionalOperationSupportingTokenParameters.Keys)
            {
                this.optionalOperationSupportingTokenParameters[key] = (SupportingTokenParameters)elementToBeCloned.optionalOperationSupportingTokenParameters[key].Clone();
            }
            this.localClientSettings = (LocalClientSecuritySettings)elementToBeCloned.localClientSettings.Clone();
            this.localServiceSettings = (LocalServiceSecuritySettings)elementToBeCloned.localServiceSettings.Clone();
            this.internalDuplexBindingElement = elementToBeCloned.internalDuplexBindingElement;
            this.maxReceivedMessageSize = elementToBeCloned.maxReceivedMessageSize;
            this.readerQuotas = elementToBeCloned.readerQuotas;
            this.doNotEmitTrust = elementToBeCloned.doNotEmitTrust;
            this.allowInsecureTransport = elementToBeCloned.allowInsecureTransport;
            this.enableUnsecuredResponse = elementToBeCloned.enableUnsecuredResponse;
            this.supportsExtendedProtectionPolicy = elementToBeCloned.supportsExtendedProtectionPolicy;
            this.protectTokens = elementToBeCloned.protectTokens;
        }
 
        internal bool SupportsExtendedProtectionPolicy
        {
            get { return this.supportsExtendedProtectionPolicy; }
            set { this.supportsExtendedProtectionPolicy = value; }
        }
 
        public SupportingTokenParameters EndpointSupportingTokenParameters
        {
            get
            {
                return this.endpointSupportingTokenParameters;
            }
        }
 
        public SupportingTokenParameters OptionalEndpointSupportingTokenParameters
        {
            get
            {
                return this.optionalEndpointSupportingTokenParameters;
            }
        }
 
 
        public IDictionary<string, SupportingTokenParameters> OperationSupportingTokenParameters
        {
            get
            {
                return this.operationSupportingTokenParameters;
            }
        }
 
        public IDictionary<string, SupportingTokenParameters> OptionalOperationSupportingTokenParameters
        {
            get
            {
                return this.optionalOperationSupportingTokenParameters;
            }
        }
 
        public SecurityHeaderLayout SecurityHeaderLayout
        {
            get
            {
                return this.securityHeaderLayout;
            }
            set
            {
                if (!SecurityHeaderLayoutHelper.IsDefined(value))
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
 
                this.securityHeaderLayout = value;
            }
        }
 
        public MessageSecurityVersion MessageSecurityVersion
        {
            get
            {
                return this.messageSecurityVersion;
            }
            set
            {
                if (value == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
                this.messageSecurityVersion = value;
            }
        }
 
        public bool EnableUnsecuredResponse
        {
            get
            {
                return this.enableUnsecuredResponse;
            }
            set
            {
                this.enableUnsecuredResponse = value;
            }
        }
 
        public bool IncludeTimestamp
        {
            get
            {
                return this.includeTimestamp;
            }
            set
            {
                this.includeTimestamp = value;
            }
        }
 
        public bool AllowInsecureTransport
        {
            get
            {
                return this.allowInsecureTransport;
            }
            set
            {
                this.allowInsecureTransport = value;
            }
        }
 
        public SecurityAlgorithmSuite DefaultAlgorithmSuite
        {
            get
            {
                return this.defaultAlgorithmSuite;
            }
            set
            {
                if (value == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("value"));
                this.defaultAlgorithmSuite = value;
            }
        }
 
        public bool ProtectTokens
        {
            get
            {
                return this.protectTokens;
            }
            set
            {
                this.protectTokens = value;
            }
        }
 
        public LocalClientSecuritySettings LocalClientSettings
        {
            get
            {
                return this.localClientSettings;
            }
        }
 
        public LocalServiceSecuritySettings LocalServiceSettings
        {
            get
            {
                return this.localServiceSettings;
            }
        }
 
        public SecurityKeyEntropyMode KeyEntropyMode
        {
            get
            {
                return this.keyEntropyMode;
            }
            set
            {
                if (!SecurityKeyEntropyModeHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
                this.keyEntropyMode = value;
            }
        }
 
        internal virtual bool SessionMode
        {
            get { return false; }
        }
 
        internal virtual bool SupportsDuplex
        {
            get { return false; }
        }
 
        internal virtual bool SupportsRequestReply
        {
            get { return false; }
        }
 
        internal long MaxReceivedMessageSize
        {
            get { return this.maxReceivedMessageSize; }
            set { this.maxReceivedMessageSize = value; }
        }
 
        internal bool DoNotEmitTrust
        {
            get { return this.doNotEmitTrust; }
            set { this.doNotEmitTrust = value; }
        }
 
        internal XmlDictionaryReaderQuotas ReaderQuotas
        {
            get { return this.readerQuotas; }
            set { this.readerQuotas = value; }
        }
 
        void GetSupportingTokensCapabilities(ICollection<SecurityTokenParameters> parameters, out bool supportsClientAuth, out bool supportsWindowsIdentity)
        {
            supportsClientAuth = false;
            supportsWindowsIdentity = false;
            foreach (SecurityTokenParameters p in parameters)
            {
                if (p.SupportsClientAuthentication)
                    supportsClientAuth = true;
                if (p.SupportsClientWindowsIdentity)
                    supportsWindowsIdentity = true;
            }
        }
 
        void GetSupportingTokensCapabilities(SupportingTokenParameters requirements, out bool supportsClientAuth, out bool supportsWindowsIdentity)
        {
            supportsClientAuth = false;
            supportsWindowsIdentity = false;
            bool tmpSupportsClientAuth;
            bool tmpSupportsWindowsIdentity;
            this.GetSupportingTokensCapabilities(requirements.Endorsing, out tmpSupportsClientAuth, out tmpSupportsWindowsIdentity);
            supportsClientAuth = supportsClientAuth || tmpSupportsClientAuth;
            supportsWindowsIdentity = supportsWindowsIdentity || tmpSupportsWindowsIdentity;
 
            this.GetSupportingTokensCapabilities(requirements.SignedEndorsing, out tmpSupportsClientAuth, out tmpSupportsWindowsIdentity);
            supportsClientAuth = supportsClientAuth || tmpSupportsClientAuth;
            supportsWindowsIdentity = supportsWindowsIdentity || tmpSupportsWindowsIdentity;
 
            this.GetSupportingTokensCapabilities(requirements.SignedEncrypted, out tmpSupportsClientAuth, out tmpSupportsWindowsIdentity);
            supportsClientAuth = supportsClientAuth || tmpSupportsClientAuth;
            supportsWindowsIdentity = supportsWindowsIdentity || tmpSupportsWindowsIdentity;
        }
 
        internal void GetSupportingTokensCapabilities(out bool supportsClientAuth, out bool supportsWindowsIdentity)
        {
            this.GetSupportingTokensCapabilities(this.EndpointSupportingTokenParameters, out supportsClientAuth, out supportsWindowsIdentity);
        }
 
        // SecureConversation needs a demuxer below security to 1) demux between the security sessions and 2) demux the SCT issue and renewal messages
        // to the authenticator
        internal void AddDemuxerForSecureConversation(ChannelBuilder builder, BindingContext secureConversationBindingContext)
        {
            // add a demuxer element  right below security unless there's a demuxer already present below and the only 
            // binding elements between security and the demuxer are "ancillary" binding elements like message encoding element and
            // stream-security upgrade element. We could always add the channel demuxer below security but not doing so in the ancillary
            // binding elements case improves perf
            int numChannelDemuxersBelowSecurity = 0;
            bool doesBindingHaveShapeChangingElements = false;
            for (int i = 0; i < builder.Binding.Elements.Count; ++i)
            {
                if ((builder.Binding.Elements[i] is MessageEncodingBindingElement) || (builder.Binding.Elements[i] is StreamUpgradeBindingElement))
                {
                    continue;
                }
                if (builder.Binding.Elements[i] is ChannelDemuxerBindingElement)
                {
                    ++numChannelDemuxersBelowSecurity;
                }
                else if (builder.Binding.Elements[i] is TransportBindingElement)
                {
                    break;
                }
                else
                {
                    doesBindingHaveShapeChangingElements = true;
                }
            }
            if (numChannelDemuxersBelowSecurity == 1 && !doesBindingHaveShapeChangingElements)
            {
                return;
            }
 
            ChannelDemuxerBindingElement demuxer = new ChannelDemuxerBindingElement(false);
            demuxer.MaxPendingSessions = this.LocalServiceSettings.MaxPendingSessions;
            demuxer.PeekTimeout = this.LocalServiceSettings.NegotiationTimeout;
 
            builder.Binding.Elements.Insert(0, demuxer);
            secureConversationBindingContext.RemainingBindingElements.Insert(0, demuxer);
        }
 
        internal void ApplyPropertiesOnDemuxer(ChannelBuilder builder, BindingContext context)
        {
            Collection<ChannelDemuxerBindingElement> demuxerElements = builder.Binding.Elements.FindAll<ChannelDemuxerBindingElement>();
            foreach (ChannelDemuxerBindingElement element in demuxerElements)
            {
                if (element != null)
                {
                    element.MaxPendingSessions = this.LocalServiceSettings.MaxPendingSessions;
                    element.PeekTimeout = this.LocalServiceSettings.NegotiationTimeout;
                }
            }
        }
        
        static BindingContext CreateIssuerBindingContextForNegotiation(BindingContext issuerBindingContext)
        {
            TransportBindingElement transport = issuerBindingContext.RemainingBindingElements.Find<TransportBindingElement>();
            if (transport == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.TransportBindingElementNotFound)));
            }
            ChannelDemuxerBindingElement demuxer = null;
            // pick the demuxer above transport (i.e. the last demuxer in the array)
            for (int i = 0; i < issuerBindingContext.RemainingBindingElements.Count; ++i)
            {
                if (issuerBindingContext.RemainingBindingElements[i] is ChannelDemuxerBindingElement)
                {
                    demuxer = (ChannelDemuxerBindingElement) issuerBindingContext.RemainingBindingElements[i];
                }
            }
            if (demuxer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ChannelDemuxerBindingElementNotFound)));
            }
            BindingElementCollection negotiationBindingElements = new BindingElementCollection();
            negotiationBindingElements.Add(demuxer.Clone());
            negotiationBindingElements.Add(transport.Clone());
            CustomBinding binding = new CustomBinding(negotiationBindingElements);
            binding.OpenTimeout = issuerBindingContext.Binding.OpenTimeout;
            binding.CloseTimeout = issuerBindingContext.Binding.CloseTimeout;
            binding.SendTimeout = issuerBindingContext.Binding.SendTimeout;
            binding.ReceiveTimeout = issuerBindingContext.Binding.ReceiveTimeout;
            if (issuerBindingContext.ListenUriBaseAddress != null)
            {
                return new BindingContext(binding, new BindingParameterCollection(issuerBindingContext.BindingParameters), issuerBindingContext.ListenUriBaseAddress,
                    issuerBindingContext.ListenUriRelativeAddress, issuerBindingContext.ListenUriMode);
            }
            else
            {
                return new BindingContext(binding, new BindingParameterCollection(issuerBindingContext.BindingParameters));
            }
        }
 
        protected static void SetIssuerBindingContextIfRequired(SecurityTokenParameters parameters, BindingContext issuerBindingContext)
        {
            if (parameters is SslSecurityTokenParameters)
            {
                ((SslSecurityTokenParameters)parameters).IssuerBindingContext = CreateIssuerBindingContextForNegotiation(issuerBindingContext);
            }
            else if (parameters is SspiSecurityTokenParameters)
            {
                ((SspiSecurityTokenParameters)parameters).IssuerBindingContext = CreateIssuerBindingContextForNegotiation(issuerBindingContext);
            }
        }
 
        static void SetIssuerBindingContextIfRequired(SupportingTokenParameters supportingParameters, BindingContext issuerBindingContext)
        {
            for (int i = 0; i < supportingParameters.Endorsing.Count; ++i)
            {
                SetIssuerBindingContextIfRequired(supportingParameters.Endorsing[i], issuerBindingContext);
            }
            for (int i = 0; i < supportingParameters.SignedEndorsing.Count; ++i)
            {
                SetIssuerBindingContextIfRequired(supportingParameters.SignedEndorsing[i], issuerBindingContext);
            }
            for (int i = 0; i < supportingParameters.Signed.Count; ++i)
            {
                SetIssuerBindingContextIfRequired(supportingParameters.Signed[i], issuerBindingContext);
            }
            for (int i = 0; i < supportingParameters.SignedEncrypted.Count; ++i)
            {
                SetIssuerBindingContextIfRequired(supportingParameters.SignedEncrypted[i], issuerBindingContext);
            }
        }
 
        void SetIssuerBindingContextIfRequired(BindingContext issuerBindingContext)
        {
            SetIssuerBindingContextIfRequired(this.EndpointSupportingTokenParameters, issuerBindingContext);
            SetIssuerBindingContextIfRequired(this.OptionalEndpointSupportingTokenParameters, issuerBindingContext);
            foreach (SupportingTokenParameters parameters in this.OperationSupportingTokenParameters.Values)
            {
                SetIssuerBindingContextIfRequired(parameters, issuerBindingContext);
            }
            foreach (SupportingTokenParameters parameters in this.OptionalOperationSupportingTokenParameters.Values)
            {
                SetIssuerBindingContextIfRequired(parameters, issuerBindingContext);
            }
        }
 
        internal bool RequiresChannelDemuxer(SecurityTokenParameters parameters)
        {
            return ((parameters is SecureConversationSecurityTokenParameters)
                    || (parameters is SslSecurityTokenParameters)
                    || (parameters is SspiSecurityTokenParameters));
        }
 
        internal virtual bool RequiresChannelDemuxer()
        {
            foreach (SecurityTokenParameters parameters in EndpointSupportingTokenParameters.Endorsing)
            {
                if (RequiresChannelDemuxer(parameters))
                {
                    return true;
                }
            }
            foreach (SecurityTokenParameters parameters in EndpointSupportingTokenParameters.SignedEndorsing)
            {
                if (RequiresChannelDemuxer(parameters))
                {
                    return true;
                }
            }
            foreach (SecurityTokenParameters parameters in OptionalEndpointSupportingTokenParameters.Endorsing)
            {
                if (RequiresChannelDemuxer(parameters))
                {
                    return true;
                }
            }
            foreach (SecurityTokenParameters parameters in OptionalEndpointSupportingTokenParameters.SignedEndorsing)
            {
                if (RequiresChannelDemuxer(parameters))
                {
                    return true;
                }
            }
            foreach (SupportingTokenParameters supportingParameters in OperationSupportingTokenParameters.Values)
            {
                foreach (SecurityTokenParameters parameters in supportingParameters.Endorsing)
                {
                    if (RequiresChannelDemuxer(parameters))
                    {
                        return true;
                    }
                }
                foreach (SecurityTokenParameters parameters in supportingParameters.SignedEndorsing)
                {
                    if (RequiresChannelDemuxer(parameters))
                    {
                        return true;
                    }
                }
            }
            foreach (SupportingTokenParameters supportingParameters in OptionalOperationSupportingTokenParameters.Values)
            {
                foreach (SecurityTokenParameters parameters in supportingParameters.Endorsing)
                {
                    if (RequiresChannelDemuxer(parameters))
                    {
                        return true;
                    }
                }
                foreach (SecurityTokenParameters parameters in supportingParameters.SignedEndorsing)
                {
                    if (RequiresChannelDemuxer(parameters))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
 
        internal bool IsUnderlyingListenerDuplex<TChannel>(BindingContext context)
        {
            return ((typeof(TChannel) == typeof(IDuplexSessionChannel)) && context.CanBuildInnerChannelListener<IDuplexChannel>()
                && !context.CanBuildInnerChannelListener<IDuplexSessionChannel>());
        }
 
        void SetPrivacyNoticeUriIfRequired(SecurityProtocolFactory factory, Binding binding)
        {
            PrivacyNoticeBindingElement privacyElement = binding.CreateBindingElements().Find<PrivacyNoticeBindingElement>();
            if (privacyElement != null)
            {
                factory.PrivacyNoticeUri = privacyElement.Url;
                factory.PrivacyNoticeVersion = privacyElement.Version;
            }
        }
 
        internal void ConfigureProtocolFactory(SecurityProtocolFactory factory, SecurityCredentialsManager credentialsManager, bool isForService, BindingContext issuerBindingContext, Binding binding)
        {
            if (factory == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("factory"));
            if (credentialsManager == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("credentialsManager"));
 
            factory.AddTimestamp = this.IncludeTimestamp;
            factory.IncomingAlgorithmSuite = this.DefaultAlgorithmSuite;
            factory.OutgoingAlgorithmSuite = this.DefaultAlgorithmSuite;
            factory.SecurityHeaderLayout = this.SecurityHeaderLayout;
 
            if (!isForService)
            {
                factory.TimestampValidityDuration = this.LocalClientSettings.TimestampValidityDuration;
                factory.DetectReplays = this.LocalClientSettings.DetectReplays;
                factory.MaxCachedNonces = this.LocalClientSettings.ReplayCacheSize;
                factory.MaxClockSkew = this.LocalClientSettings.MaxClockSkew;
                factory.ReplayWindow = this.LocalClientSettings.ReplayWindow;
 
                if (this.LocalClientSettings.DetectReplays)
                {
                  factory.NonceCache = this.LocalClientSettings.NonceCache;
                }
            }
            else
            {
                factory.TimestampValidityDuration = this.LocalServiceSettings.TimestampValidityDuration;
                factory.DetectReplays = this.LocalServiceSettings.DetectReplays;
                factory.MaxCachedNonces = this.LocalServiceSettings.ReplayCacheSize;
                factory.MaxClockSkew = this.LocalServiceSettings.MaxClockSkew;
                factory.ReplayWindow = this.LocalServiceSettings.ReplayWindow;
 
                if (this.LocalServiceSettings.DetectReplays)
                {
                   factory.NonceCache = this.LocalServiceSettings.NonceCache;
                }
            }
            
            factory.SecurityBindingElement = (SecurityBindingElement) this.Clone();
            factory.SecurityBindingElement.SetIssuerBindingContextIfRequired(issuerBindingContext);
            factory.SecurityTokenManager = credentialsManager.CreateSecurityTokenManager();
            SecurityTokenSerializer tokenSerializer = factory.SecurityTokenManager.CreateSecurityTokenSerializer(this.messageSecurityVersion.SecurityTokenVersion);
            factory.StandardsManager = new SecurityStandardsManager(this.messageSecurityVersion, tokenSerializer);
            if (!isForService)
            {
                SetPrivacyNoticeUriIfRequired(factory, binding);
            }
        }
 
        internal abstract SecurityProtocolFactory CreateSecurityProtocolFactory<TChannel>(BindingContext context, SecurityCredentialsManager credentialsManager,
        bool isForService, BindingContext issuanceBindingContext);
 
        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
 
            if (!this.CanBuildChannelFactory<TChannel>(context))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)), "TChannel"));
            }
 
            this.readerQuotas = context.GetInnerProperty<XmlDictionaryReaderQuotas>();
            if (readerQuotas == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.EncodingBindingElementDoesNotHandleReaderQuotas)));
            }
 
            TransportBindingElement transportBindingElement = null;
            
            if (context.RemainingBindingElements != null)
                transportBindingElement = context.RemainingBindingElements.Find<TransportBindingElement>();
 
            if (transportBindingElement != null)
                this.maxReceivedMessageSize = transportBindingElement.MaxReceivedMessageSize;
 
            IChannelFactory<TChannel> result = this.BuildChannelFactoryCore<TChannel>(context);
 
            // attach the ExtendedProtectionPolicy to the securityProtcolFactory so it will be 
            // available when building the channel.
            if (transportBindingElement != null)
            {
                SecurityChannelFactory<TChannel> scf = result as SecurityChannelFactory<TChannel>;
                if (scf != null && scf.SecurityProtocolFactory != null)
                {
                    scf.SecurityProtocolFactory.ExtendedProtectionPolicy = transportBindingElement.GetProperty<ExtendedProtectionPolicy>(context);
                }
            }
 
            return result;
 
        }
 
        protected abstract IChannelFactory<TChannel> BuildChannelFactoryCore<TChannel>(BindingContext context);
 
        public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
 
            InternalDuplexBindingElement.AddDuplexFactorySupport(context, ref this.internalDuplexBindingElement);
 
            if (this.SessionMode)
            {
                return this.CanBuildSessionChannelFactory<TChannel>(context);
            }
 
            if (!context.CanBuildInnerChannelFactory<TChannel>())
            {
                return false;
            }
 
            return typeof(TChannel) == typeof(IOutputChannel) || typeof(TChannel) == typeof(IOutputSessionChannel) ||
                (this.SupportsDuplex && (typeof(TChannel) == typeof(IDuplexChannel) || typeof(TChannel) == typeof(IDuplexSessionChannel))) ||
                (this.SupportsRequestReply && (typeof(TChannel) == typeof(IRequestChannel) || typeof(TChannel) == typeof(IRequestSessionChannel)));
        }
 
        bool CanBuildSessionChannelFactory<TChannel>(BindingContext context)
        {
            if (!(context.CanBuildInnerChannelFactory<IRequestChannel>()
                || context.CanBuildInnerChannelFactory<IRequestSessionChannel>()
                || context.CanBuildInnerChannelFactory<IDuplexChannel>()
                || context.CanBuildInnerChannelFactory<IDuplexSessionChannel>()))
            {
                return false;
            }
 
            if (typeof(TChannel) == typeof(IRequestSessionChannel))
            {
                return (context.CanBuildInnerChannelFactory<IRequestChannel>() || context.CanBuildInnerChannelFactory<IRequestSessionChannel>());
            }
            else if (typeof(TChannel) == typeof(IDuplexSessionChannel))
            {
                return (context.CanBuildInnerChannelFactory<IDuplexChannel>() || context.CanBuildInnerChannelFactory<IDuplexSessionChannel>());
            }
            else
            {
                return false;
            }
        }
 
        public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
        {
            if (context == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
 
            if (!this.CanBuildChannelListener<TChannel>(context))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)), "TChannel"));
            }
 
            this.readerQuotas = context.GetInnerProperty<XmlDictionaryReaderQuotas>();
            if (readerQuotas == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.EncodingBindingElementDoesNotHandleReaderQuotas)));
            }
 
            TransportBindingElement transportBindingElement = null;
            if (context.RemainingBindingElements != null)
                transportBindingElement = context.RemainingBindingElements.Find<TransportBindingElement>();
 
            if (transportBindingElement != null)
                this.maxReceivedMessageSize = transportBindingElement.MaxReceivedMessageSize;
 
            return this.BuildChannelListenerCore<TChannel>(context);
        }
 
        protected abstract IChannelListener<TChannel> BuildChannelListenerCore<TChannel>(BindingContext context)
            where TChannel : class, IChannel;
 
        public override bool CanBuildChannelListener<TChannel>(BindingContext context)
        {
            if (context == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
 
            InternalDuplexBindingElement.AddDuplexListenerSupport(context, ref this.internalDuplexBindingElement);
 
            if (this.SessionMode)
            {
                return this.CanBuildSessionChannelListener<TChannel>(context);
            }
 
            if (!context.CanBuildInnerChannelListener<TChannel>())
            {
                return false;
            }
 
            return typeof(TChannel) == typeof(IInputChannel) || typeof(TChannel) == typeof(IInputSessionChannel) ||
                (this.SupportsDuplex && (typeof(TChannel) == typeof(IDuplexChannel) || typeof(TChannel) == typeof(IDuplexSessionChannel))) ||
                (this.SupportsRequestReply && (typeof(TChannel) == typeof(IReplyChannel) || typeof(TChannel) == typeof(IReplySessionChannel)));
        }
 
        bool CanBuildSessionChannelListener<TChannel>(BindingContext context)
            where TChannel : class, IChannel
        {
            if (!(context.CanBuildInnerChannelListener<IReplyChannel>()
                || context.CanBuildInnerChannelListener<IReplySessionChannel>()
                || context.CanBuildInnerChannelListener<IDuplexChannel>()
                || context.CanBuildInnerChannelListener<IDuplexSessionChannel>()))
            {
                return false;
            }
 
            if (typeof(TChannel) == typeof(IReplySessionChannel))
            {
                return (context.CanBuildInnerChannelListener<IReplyChannel>() || context.CanBuildInnerChannelListener<IReplySessionChannel>());
            }
            else if (typeof(TChannel) == typeof(IDuplexSessionChannel))
            {
                return (context.CanBuildInnerChannelListener<IDuplexChannel>() || context.CanBuildInnerChannelListener<IDuplexSessionChannel>());
            }
            else
            {
                return false;
            }
        }
 
        public virtual void SetKeyDerivation(bool requireDerivedKeys)
        {
            this.EndpointSupportingTokenParameters.SetKeyDerivation(requireDerivedKeys);
            this.OptionalEndpointSupportingTokenParameters.SetKeyDerivation(requireDerivedKeys);
            foreach (SupportingTokenParameters t in this.OperationSupportingTokenParameters.Values)
                t.SetKeyDerivation(requireDerivedKeys);
            foreach (SupportingTokenParameters t in this.OptionalOperationSupportingTokenParameters.Values)
            {
                t.SetKeyDerivation(requireDerivedKeys);
            }
        }
 
        internal virtual bool IsSetKeyDerivation(bool requireDerivedKeys)
        {
            if (!this.EndpointSupportingTokenParameters.IsSetKeyDerivation(requireDerivedKeys))
                return false;
 
            if (!this.OptionalEndpointSupportingTokenParameters.IsSetKeyDerivation(requireDerivedKeys))
                return false;
 
            foreach (SupportingTokenParameters t in this.OperationSupportingTokenParameters.Values)
            {
                if (!t.IsSetKeyDerivation(requireDerivedKeys))
                    return false;
            }
            foreach (SupportingTokenParameters t in this.OptionalOperationSupportingTokenParameters.Values)
            {
                if (!t.IsSetKeyDerivation(requireDerivedKeys))
                    return false;
            }
            return true;
        }
 
        internal ChannelProtectionRequirements GetProtectionRequirements(AddressingVersion addressing, ProtectionLevel defaultProtectionLevel)
        {
            if (addressing == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("addressing");
 
            ChannelProtectionRequirements result = new ChannelProtectionRequirements();
            ProtectionLevel supportedRequestProtectionLevel = this.GetIndividualProperty<ISecurityCapabilities>().SupportedRequestProtectionLevel;
            ProtectionLevel supportedResponseProtectionLevel = this.GetIndividualProperty<ISecurityCapabilities>().SupportedResponseProtectionLevel;
 
            bool canSupportMoreThanTheDefault = 
                (ProtectionLevelHelper.IsStrongerOrEqual(supportedRequestProtectionLevel, defaultProtectionLevel)
                && ProtectionLevelHelper.IsStrongerOrEqual(supportedResponseProtectionLevel, defaultProtectionLevel));
            if (canSupportMoreThanTheDefault)
            {
                MessagePartSpecification signedParts = new MessagePartSpecification();
                MessagePartSpecification encryptedParts = new MessagePartSpecification();
                if (defaultProtectionLevel != ProtectionLevel.None)
                {
                    signedParts.IsBodyIncluded = true;
                    if (defaultProtectionLevel == ProtectionLevel.EncryptAndSign)
                    {
                        encryptedParts.IsBodyIncluded = true;
                    }
                }
                signedParts.MakeReadOnly();
                encryptedParts.MakeReadOnly();
                if (addressing.FaultAction != null)
                {
                    // Addressing faults
                    result.IncomingSignatureParts.AddParts(signedParts, addressing.FaultAction);
                    result.OutgoingSignatureParts.AddParts(signedParts, addressing.FaultAction);
                    result.IncomingEncryptionParts.AddParts(encryptedParts, addressing.FaultAction);
                    result.OutgoingEncryptionParts.AddParts(encryptedParts, addressing.FaultAction);
                }
                if (addressing.DefaultFaultAction != null)
                {
                    // Faults that do not specify a particular action
                    result.IncomingSignatureParts.AddParts(signedParts, addressing.DefaultFaultAction);
                    result.OutgoingSignatureParts.AddParts(signedParts, addressing.DefaultFaultAction);
                    result.IncomingEncryptionParts.AddParts(encryptedParts, addressing.DefaultFaultAction);
                    result.OutgoingEncryptionParts.AddParts(encryptedParts, addressing.DefaultFaultAction);
                }
                // Infrastructure faults
                result.IncomingSignatureParts.AddParts(signedParts, FaultCodeConstants.Actions.NetDispatcher);
                result.OutgoingSignatureParts.AddParts(signedParts, FaultCodeConstants.Actions.NetDispatcher);
                result.IncomingEncryptionParts.AddParts(encryptedParts, FaultCodeConstants.Actions.NetDispatcher);
                result.OutgoingEncryptionParts.AddParts(encryptedParts, FaultCodeConstants.Actions.NetDispatcher);
            }
 
            return result;
        }
 
        public override T GetProperty<T>(BindingContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
            if (typeof(T) == typeof(ISecurityCapabilities))
            {
                return (T)(object)GetSecurityCapabilities(context);
            }
            else if (typeof(T) == typeof(IdentityVerifier))
            {
                return (T)(object)this.localClientSettings.IdentityVerifier;
            }
            else
            {
                return context.GetInnerProperty<T>();
            }
        }
 
        internal abstract ISecurityCapabilities GetIndividualISecurityCapabilities();
 
        ISecurityCapabilities GetSecurityCapabilities(BindingContext context)
        {
            ISecurityCapabilities thisSecurityCapability = this.GetIndividualISecurityCapabilities();
            ISecurityCapabilities lowerSecurityCapability = context.GetInnerProperty<ISecurityCapabilities>();
            if (lowerSecurityCapability == null)
            {
                return thisSecurityCapability;
            }
            else
            {
                bool supportsClientAuth = thisSecurityCapability.SupportsClientAuthentication;
                bool supportsClientWindowsIdentity = thisSecurityCapability.SupportsClientWindowsIdentity;
                bool supportsServerAuth = thisSecurityCapability.SupportsServerAuthentication || lowerSecurityCapability.SupportsServerAuthentication;
                ProtectionLevel requestProtectionLevel = ProtectionLevelHelper.Max(thisSecurityCapability.SupportedRequestProtectionLevel, lowerSecurityCapability.SupportedRequestProtectionLevel);
                ProtectionLevel responseProtectionLevel = ProtectionLevelHelper.Max(thisSecurityCapability.SupportedResponseProtectionLevel, lowerSecurityCapability.SupportedResponseProtectionLevel);
                return new SecurityCapabilities(supportsClientAuth, supportsServerAuth, supportsClientWindowsIdentity, requestProtectionLevel, responseProtectionLevel);
            }
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsMutualCertificateBinding() method.
        static public SecurityBindingElement CreateMutualCertificateBindingElement()
        {
            return CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11);
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsMutualCertificateBinding(SecurityBindingElement sbe)
        {
            return IsMutualCertificateBinding(sbe, false);
        }
 
        static public AsymmetricSecurityBindingElement CreateCertificateSignatureBindingElement()
        {
            AsymmetricSecurityBindingElement result;
 
            result = new AsymmetricSecurityBindingElement(
                new X509SecurityTokenParameters( // recipient
                    X509KeyIdentifierClauseType.Any,
                    SecurityTokenInclusionMode.Never, false),
                new X509SecurityTokenParameters( // initiator
                    X509KeyIdentifierClauseType.Any,
                    SecurityTokenInclusionMode.AlwaysToRecipient, false));
 
            // this is a one way binding so the client cannot detect replays
            result.IsCertificateSignatureBinding = true;
            result.LocalClientSettings.DetectReplays = false;
            result.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
 
            return result;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsMutualCertificateBinding() method.
        static public SecurityBindingElement CreateMutualCertificateBindingElement(MessageSecurityVersion version)
        {
            return CreateMutualCertificateBindingElement(version, false);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsMutualCertificateBinding() method.
        static public SecurityBindingElement CreateMutualCertificateBindingElement(MessageSecurityVersion version, bool allowSerializedSigningTokenOnReply)
        {
            if (version == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
            }
            SecurityBindingElement result;
 
            if (version.SecurityVersion == SecurityVersion.WSSecurity10)
            {
                result = new AsymmetricSecurityBindingElement(
                    new X509SecurityTokenParameters( // recipient
                        X509KeyIdentifierClauseType.Any,
                        SecurityTokenInclusionMode.Never, 
                        false),
                    new X509SecurityTokenParameters( // initiator
                        X509KeyIdentifierClauseType.Any,
                        SecurityTokenInclusionMode.AlwaysToRecipient, false),
                    allowSerializedSigningTokenOnReply);
            }
            else
            {
                result = new SymmetricSecurityBindingElement(
                    new X509SecurityTokenParameters( // protection
                        X509KeyIdentifierClauseType.Thumbprint,
                        SecurityTokenInclusionMode.Never));
                result.EndpointSupportingTokenParameters.Endorsing.Add(
                    new X509SecurityTokenParameters(
                        X509KeyIdentifierClauseType.Thumbprint,
                        SecurityTokenInclusionMode.AlwaysToRecipient, 
                        false));
                ((SymmetricSecurityBindingElement)result).RequireSignatureConfirmation = true;
            }
 
            result.MessageSecurityVersion = version;
 
            return result;
        }
 
        // this method reverses CreateMutualCertificateDuplexBindingElement() logic
 
        internal static bool IsMutualCertificateDuplexBinding(SecurityBindingElement sbe)
        {
 
            // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
 
            AsymmetricSecurityBindingElement asbe = sbe as AsymmetricSecurityBindingElement;
            if (asbe != null)
            {
                X509SecurityTokenParameters recipient = asbe.RecipientTokenParameters as X509SecurityTokenParameters;
                if (recipient == null || (recipient.X509ReferenceStyle != X509KeyIdentifierClauseType.Any  && recipient.X509ReferenceStyle != X509KeyIdentifierClauseType.Thumbprint) || recipient.InclusionMode != SecurityTokenInclusionMode.AlwaysToInitiator)
                    return false;
 
                X509SecurityTokenParameters initiator = asbe.InitiatorTokenParameters as X509SecurityTokenParameters;
                if (initiator == null || (initiator.X509ReferenceStyle != X509KeyIdentifierClauseType.Any && initiator.X509ReferenceStyle != X509KeyIdentifierClauseType.Thumbprint) || initiator.InclusionMode != SecurityTokenInclusionMode.AlwaysToRecipient)
                    return false;
 
                if (!sbe.EndpointSupportingTokenParameters.IsEmpty())
                    return false;
 
                return true;
            }
            else
            {
                return false;
            }
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsMutualCertificateBinding(SecurityBindingElement sbe, bool allowSerializedSigningTokenOnReply)
        {
 
            // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
 
            AsymmetricSecurityBindingElement asbe = sbe as AsymmetricSecurityBindingElement;
            if (asbe != null)
            {
                X509SecurityTokenParameters recipient = asbe.RecipientTokenParameters as X509SecurityTokenParameters;
                if (recipient == null || recipient.X509ReferenceStyle != X509KeyIdentifierClauseType.Any || recipient.InclusionMode != SecurityTokenInclusionMode.Never)
                    return false;
 
                X509SecurityTokenParameters initiator = asbe.InitiatorTokenParameters as X509SecurityTokenParameters;
                if (initiator == null || initiator.X509ReferenceStyle != X509KeyIdentifierClauseType.Any || initiator.InclusionMode != SecurityTokenInclusionMode.AlwaysToRecipient)
                    return false;
 
                if (!sbe.EndpointSupportingTokenParameters.IsEmpty())
                    return false;
            }
            else
            {
                SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
                if (ssbe == null)
                    return false;
 
                X509SecurityTokenParameters x509Parameters = ssbe.ProtectionTokenParameters as X509SecurityTokenParameters;
                if (x509Parameters == null || x509Parameters.X509ReferenceStyle != X509KeyIdentifierClauseType.Thumbprint || x509Parameters.InclusionMode != SecurityTokenInclusionMode.Never)
                    return false;
 
                SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
                if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 0 || parameters.Endorsing.Count != 1 || parameters.SignedEndorsing.Count != 0)
                    return false;
 
                x509Parameters = parameters.Endorsing[0] as X509SecurityTokenParameters;
                if (x509Parameters == null || x509Parameters.X509ReferenceStyle != X509KeyIdentifierClauseType.Thumbprint || x509Parameters.InclusionMode != SecurityTokenInclusionMode.AlwaysToRecipient)
                    return false;
 
                if (!ssbe.RequireSignatureConfirmation)
                    return false;
 
            }
            return true;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsAnonymousForCertificateBinding() method.
        static public SymmetricSecurityBindingElement CreateAnonymousForCertificateBindingElement()
        {
            SymmetricSecurityBindingElement result;
 
            result = new SymmetricSecurityBindingElement(
                new X509SecurityTokenParameters( // protection
                    X509KeyIdentifierClauseType.Thumbprint,
                    SecurityTokenInclusionMode.Never));
            result.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
            result.RequireSignatureConfirmation = true;
 
            return result;
        }
 
        // this method reverses CreateAnonymousForCertificateBindingElement() logic
        internal static bool IsAnonymousForCertificateBinding(SecurityBindingElement sbe)
        {
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe == null)
                return false;
 
            if (!ssbe.RequireSignatureConfirmation)
                return false;
 
            // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
 
            X509SecurityTokenParameters x509Parameters = ssbe.ProtectionTokenParameters as X509SecurityTokenParameters;
            if (x509Parameters == null || x509Parameters.X509ReferenceStyle != X509KeyIdentifierClauseType.Thumbprint || x509Parameters.InclusionMode != SecurityTokenInclusionMode.Never)
                return false;
 
            if (!sbe.EndpointSupportingTokenParameters.IsEmpty())
                return false;
 
            return true;
        }
 
        static public AsymmetricSecurityBindingElement CreateMutualCertificateDuplexBindingElement()
        {
            return CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11);
        }
 
        static public AsymmetricSecurityBindingElement CreateMutualCertificateDuplexBindingElement(MessageSecurityVersion version)
        {
            if (version == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
            }
            AsymmetricSecurityBindingElement result;
 
            if (version.SecurityVersion == SecurityVersion.WSSecurity10)
            {
                result = new AsymmetricSecurityBindingElement(
                    new X509SecurityTokenParameters( // recipient
                        X509KeyIdentifierClauseType.Any,
                        SecurityTokenInclusionMode.AlwaysToInitiator, 
                        false),
                    new X509SecurityTokenParameters( // initiator
                        X509KeyIdentifierClauseType.Any,
                        SecurityTokenInclusionMode.AlwaysToRecipient,
                        false));
            }
            else
            {
                result = new AsymmetricSecurityBindingElement(
                    new X509SecurityTokenParameters( // recipient
                        X509KeyIdentifierClauseType.Thumbprint,
                        SecurityTokenInclusionMode.AlwaysToInitiator, 
                        false),
                    new X509SecurityTokenParameters( // initiator
                        X509KeyIdentifierClauseType.Thumbprint,
                        SecurityTokenInclusionMode.AlwaysToRecipient,
                        false));
            }
 
            result.MessageSecurityVersion = version;
 
            return result;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsUserNameForCertificateBinding() method.
        static public SymmetricSecurityBindingElement CreateUserNameForCertificateBindingElement()
        {
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(
                new X509SecurityTokenParameters(
                    X509KeyIdentifierClauseType.Thumbprint,
                    SecurityTokenInclusionMode.Never));
            result.EndpointSupportingTokenParameters.SignedEncrypted.Add(
                new UserNameSecurityTokenParameters());
            result.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
 
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsUserNameForCertificateBinding(SecurityBindingElement sbe)
        {
            // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
 
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe == null)
                return false;
 
            X509SecurityTokenParameters x509Parameters = ssbe.ProtectionTokenParameters as X509SecurityTokenParameters;
            if (x509Parameters == null || x509Parameters.X509ReferenceStyle != X509KeyIdentifierClauseType.Thumbprint || x509Parameters.InclusionMode != SecurityTokenInclusionMode.Never)
                return false;
 
            SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 1 || parameters.Endorsing.Count != 0 || parameters.SignedEndorsing.Count != 0)
                return false;
 
            UserNameSecurityTokenParameters userNameParameters = parameters.SignedEncrypted[0] as UserNameSecurityTokenParameters;
            if (userNameParameters == null)
                return false;
 
            return true;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsKerberosBinding() method.
        static public SymmetricSecurityBindingElement CreateKerberosBindingElement()
        {
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(
                new KerberosSecurityTokenParameters());
            result.DefaultAlgorithmSuite = SecurityAlgorithmSuite.KerberosDefault;
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsKerberosBinding(SecurityBindingElement sbe)
        {
            // do not check DefaultAlgorithmSuite match: it is often changed by the caller of CreateKerberosBindingElement
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe == null)
                return false;
 
            KerberosSecurityTokenParameters parameters = ssbe.ProtectionTokenParameters as KerberosSecurityTokenParameters;
            if (parameters == null)
                return false;
 
            if (!sbe.EndpointSupportingTokenParameters.IsEmpty())
                return false;
 
            return true;
        }
 
        static public SymmetricSecurityBindingElement CreateSspiNegotiationBindingElement()
        {
            return CreateSspiNegotiationBindingElement(SspiSecurityTokenParameters.defaultRequireCancellation);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsSspiNegotiationBinding() method.
        static public SymmetricSecurityBindingElement CreateSspiNegotiationBindingElement(bool requireCancellation)
        {
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(
                new SspiSecurityTokenParameters(requireCancellation));
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsSspiNegotiationBinding(SecurityBindingElement sbe, bool requireCancellation)
        {
            SymmetricSecurityBindingElement ssbe  = sbe as SymmetricSecurityBindingElement;
 
            if (ssbe == null)
                return false;
 
            if (!sbe.EndpointSupportingTokenParameters.IsEmpty())
                return false;
 
            SspiSecurityTokenParameters sspiParameters = ssbe.ProtectionTokenParameters as SspiSecurityTokenParameters;
            if (sspiParameters == null)
                return false;
 
            return sspiParameters.RequireCancellation == requireCancellation;
        }
 
 
        static public SymmetricSecurityBindingElement CreateSslNegotiationBindingElement(bool requireClientCertificate)
        {
            return CreateSslNegotiationBindingElement(requireClientCertificate, SslSecurityTokenParameters.defaultRequireCancellation);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsSslNegotiationBinding() method.
        static public SymmetricSecurityBindingElement CreateSslNegotiationBindingElement(bool requireClientCertificate, bool requireCancellation)
        {
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(
                new SslSecurityTokenParameters(requireClientCertificate, requireCancellation));
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsSslNegotiationBinding(SecurityBindingElement sbe, bool requireClientCertificate, bool requireCancellation)
        {
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe == null)
                return false;
 
            if (!sbe.EndpointSupportingTokenParameters.IsEmpty())
                return false;
 
            SslSecurityTokenParameters sslParameters = ssbe.ProtectionTokenParameters as SslSecurityTokenParameters;
            if (sslParameters == null)
                return false;
 
            return sslParameters.RequireClientCertificate == requireClientCertificate && sslParameters.RequireCancellation == requireCancellation;
 
        }
        static public SymmetricSecurityBindingElement CreateIssuedTokenBindingElement(IssuedSecurityTokenParameters issuedTokenParameters)
        {
            if (issuedTokenParameters == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("issuedTokenParameters");
            if (issuedTokenParameters.KeyType != SecurityKeyType.SymmetricKey)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.IssuedTokenAuthenticationModeRequiresSymmetricIssuedKey));
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(issuedTokenParameters);
            return result;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsIssuedTokenForCertificateBinding() method.
        static public SymmetricSecurityBindingElement CreateIssuedTokenForCertificateBindingElement(IssuedSecurityTokenParameters issuedTokenParameters)
        {
            if (issuedTokenParameters == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("issuedTokenParameters");
 
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(
                new X509SecurityTokenParameters(
                    X509KeyIdentifierClauseType.Thumbprint,
                    SecurityTokenInclusionMode.Never));
            if (issuedTokenParameters.KeyType == SecurityKeyType.BearerKey)
            {
                result.EndpointSupportingTokenParameters.SignedEncrypted.Add(issuedTokenParameters);
                result.MessageSecurityVersion = MessageSecurityVersion.WSSXDefault;
            }
            else
            {
                result.EndpointSupportingTokenParameters.Endorsing.Add(issuedTokenParameters);
                result.MessageSecurityVersion = MessageSecurityVersion.Default;
            }
            result.RequireSignatureConfirmation = true;
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsIssuedTokenForCertificateBinding(SecurityBindingElement sbe, out IssuedSecurityTokenParameters issuedTokenParameters)
        {
            issuedTokenParameters = null;
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe == null)
                return false;
 
            if (!ssbe.RequireSignatureConfirmation)
                return false;
 
            // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
 
            X509SecurityTokenParameters x509Parameters = ssbe.ProtectionTokenParameters as X509SecurityTokenParameters;
            if (x509Parameters == null || x509Parameters.X509ReferenceStyle != X509KeyIdentifierClauseType.Thumbprint || x509Parameters.InclusionMode != SecurityTokenInclusionMode.Never)
                return false;
 
            SupportingTokenParameters parameters = ssbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || (parameters.SignedEncrypted.Count == 0 && parameters.Endorsing.Count == 0) || parameters.SignedEndorsing.Count != 0)
                return false;
 
            if ((parameters.SignedEncrypted.Count == 1) && (parameters.Endorsing.Count == 0))
            {
                issuedTokenParameters = parameters.SignedEncrypted[0] as IssuedSecurityTokenParameters;
                if (issuedTokenParameters != null && issuedTokenParameters.KeyType != SecurityKeyType.BearerKey)
                    return false;
            }
            else if ((parameters.Endorsing.Count == 1) && (parameters.SignedEncrypted.Count == 0))
            {
                issuedTokenParameters = parameters.Endorsing[0] as IssuedSecurityTokenParameters;
                if (issuedTokenParameters != null && (issuedTokenParameters.KeyType != SecurityKeyType.SymmetricKey && issuedTokenParameters.KeyType != SecurityKeyType.AsymmetricKey))
                    return false;
            }
            return (issuedTokenParameters != null);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsIssuedTokenForSslBinding() method.
        static public SymmetricSecurityBindingElement CreateIssuedTokenForSslBindingElement(IssuedSecurityTokenParameters issuedTokenParameters)
        {
            return CreateIssuedTokenForSslBindingElement(issuedTokenParameters, SslSecurityTokenParameters.defaultRequireCancellation);
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsIssuedTokenForSslBinding(SecurityBindingElement sbe, out IssuedSecurityTokenParameters issuedTokenParameters)
        {
            return IsIssuedTokenForSslBinding(sbe, SslSecurityTokenParameters.defaultRequireCancellation, out issuedTokenParameters);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsIssuedTokenForSslBinding() method.
        static public SymmetricSecurityBindingElement CreateIssuedTokenForSslBindingElement(IssuedSecurityTokenParameters issuedTokenParameters, bool requireCancellation)
        {
            if (issuedTokenParameters == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("issuedTokenParameters");
 
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(
                new SslSecurityTokenParameters(false, requireCancellation));
            if (issuedTokenParameters.KeyType == SecurityKeyType.BearerKey)
            {
                result.EndpointSupportingTokenParameters.SignedEncrypted.Add(issuedTokenParameters);
                result.MessageSecurityVersion = MessageSecurityVersion.WSSXDefault;
            }
            else
            {
                result.EndpointSupportingTokenParameters.Endorsing.Add(issuedTokenParameters);
                result.MessageSecurityVersion = MessageSecurityVersion.Default;
            }
            result.RequireSignatureConfirmation = true;
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsIssuedTokenForSslBinding(SecurityBindingElement sbe, bool requireCancellation, out IssuedSecurityTokenParameters issuedTokenParameters)
        {
            issuedTokenParameters = null;
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe == null)
                return false;
 
            if (!ssbe.RequireSignatureConfirmation)
                return false;
 
            // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
 
            SslSecurityTokenParameters sslParameters = ssbe.ProtectionTokenParameters as SslSecurityTokenParameters;
            if (sslParameters == null)
                return false;
 
            if (sslParameters.RequireClientCertificate || sslParameters.RequireCancellation != requireCancellation)
                return false;
 
            SupportingTokenParameters parameters = ssbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || (parameters.SignedEncrypted.Count == 0 && parameters.Endorsing.Count == 0) || parameters.SignedEndorsing.Count != 0)
                return false;
 
            if ((parameters.SignedEncrypted.Count == 1) && (parameters.Endorsing.Count == 0))
            {
                issuedTokenParameters = parameters.SignedEncrypted[0] as IssuedSecurityTokenParameters;
                if (issuedTokenParameters != null && issuedTokenParameters.KeyType != SecurityKeyType.BearerKey)
                    return false;
            }
            else if ((parameters.Endorsing.Count == 1) && (parameters.SignedEncrypted.Count == 0))
            {
                issuedTokenParameters = parameters.Endorsing[0] as IssuedSecurityTokenParameters;
                if (issuedTokenParameters != null && (issuedTokenParameters.KeyType != SecurityKeyType.SymmetricKey && issuedTokenParameters.KeyType != SecurityKeyType.AsymmetricKey))
                    return false;
            }
            return (issuedTokenParameters != null);
        }
 
        static public SymmetricSecurityBindingElement CreateUserNameForSslBindingElement()
        {
            return CreateUserNameForSslBindingElement(SslSecurityTokenParameters.defaultRequireCancellation);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsUserNameForSslBinding() method.
        static public SymmetricSecurityBindingElement CreateUserNameForSslBindingElement(bool requireCancellation)
        {
            SymmetricSecurityBindingElement result = new SymmetricSecurityBindingElement(
                new SslSecurityTokenParameters(false, requireCancellation));
            result.EndpointSupportingTokenParameters.SignedEncrypted.Add(
                new UserNameSecurityTokenParameters());
            result.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11;
 
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsUserNameForSslBinding(SecurityBindingElement sbe, bool requireCancellation)
        {
            // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
 
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe == null)
                return false;
 
            SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 1 || parameters.Endorsing.Count != 0 || parameters.SignedEndorsing.Count != 0)
                return false;
 
            if (!(parameters.SignedEncrypted[0] is UserNameSecurityTokenParameters))
                return false;
 
            SslSecurityTokenParameters sslParameters = ssbe.ProtectionTokenParameters as SslSecurityTokenParameters;
            if (sslParameters == null)
                return false;
 
            return sslParameters.RequireCancellation == requireCancellation && !sslParameters.RequireClientCertificate;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsUserNameOverTransportBinding() method.
        static public TransportSecurityBindingElement CreateUserNameOverTransportBindingElement()
        {
            TransportSecurityBindingElement result = new TransportSecurityBindingElement();
            result.EndpointSupportingTokenParameters.SignedEncrypted.Add(
                new UserNameSecurityTokenParameters());
            result.IncludeTimestamp = true;
            result.LocalClientSettings.DetectReplays = false;
            result.LocalServiceSettings.DetectReplays = false;
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsUserNameOverTransportBinding(SecurityBindingElement sbe)
        {
            // do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
            if (!sbe.IncludeTimestamp)
                return false;
 
            if (!(sbe is TransportSecurityBindingElement))
                return false;
 
            SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 1 || parameters.Endorsing.Count != 0 || parameters.SignedEndorsing.Count != 0)
                return false;
 
            UserNameSecurityTokenParameters userNameParameters = parameters.SignedEncrypted[0] as UserNameSecurityTokenParameters;
            if (userNameParameters == null)
                return false;
 
            return true;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsCertificateOverTransportBinding() method.
        static public TransportSecurityBindingElement CreateCertificateOverTransportBindingElement()
        {
            return CreateCertificateOverTransportBindingElement(MessageSecurityVersion.Default);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsCertificateOverTransportBinding() method.
        static public TransportSecurityBindingElement CreateCertificateOverTransportBindingElement(MessageSecurityVersion version)
        {
            if (version == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("version");
            }
            X509KeyIdentifierClauseType x509ReferenceType;
 
            if (version.SecurityVersion == SecurityVersion.WSSecurity10)
            {
                x509ReferenceType = X509KeyIdentifierClauseType.Any;
            }
            else
            {
                x509ReferenceType = X509KeyIdentifierClauseType.Thumbprint;
            }
 
            TransportSecurityBindingElement result = new TransportSecurityBindingElement();
            X509SecurityTokenParameters x509Parameters = new X509SecurityTokenParameters(
                    x509ReferenceType,
                    SecurityTokenInclusionMode.AlwaysToRecipient,
                    false);
            result.EndpointSupportingTokenParameters.Endorsing.Add(
                x509Parameters
                );
            result.IncludeTimestamp = true;
            result.LocalClientSettings.DetectReplays = false;
            result.LocalServiceSettings.DetectReplays = false;
            result.MessageSecurityVersion = version;
 
            return result;
        }
 
        // this method reverses CreateMutualCertificateBindingElement() logic
        internal static bool IsCertificateOverTransportBinding(SecurityBindingElement sbe)
        {
            // do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
            if (!sbe.IncludeTimestamp)
                return false;
 
            if (!(sbe is TransportSecurityBindingElement))
                return false;
 
            SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 0 || parameters.Endorsing.Count != 1 || parameters.SignedEndorsing.Count != 0)
                return false;
 
            X509SecurityTokenParameters x509Parameters = parameters.Endorsing[0] as X509SecurityTokenParameters;
            if (x509Parameters == null)
                return false;
 
            if (x509Parameters.InclusionMode != SecurityTokenInclusionMode.AlwaysToRecipient)
                return false;
 
            return x509Parameters.X509ReferenceStyle == X509KeyIdentifierClauseType.Any || x509Parameters.X509ReferenceStyle == X509KeyIdentifierClauseType.Thumbprint;
        }
 
        static public TransportSecurityBindingElement CreateKerberosOverTransportBindingElement()
        {
            TransportSecurityBindingElement result = new TransportSecurityBindingElement();
            KerberosSecurityTokenParameters kerberosParameters = new KerberosSecurityTokenParameters();
            kerberosParameters.RequireDerivedKeys = false;
            result.EndpointSupportingTokenParameters.Endorsing.Add(
                kerberosParameters);
            result.IncludeTimestamp = true;
            result.LocalClientSettings.DetectReplays = false;
            result.LocalServiceSettings.DetectReplays = false;
            result.DefaultAlgorithmSuite = SecurityAlgorithmSuite.KerberosDefault;
            result.SupportsExtendedProtectionPolicy = true;
 
            return result;
        }
#if NO
        // this is reversing of the CreateKerberosOverTransportBindingElement() logic
        static bool IsKerberosOverTransportBinding(SecurityBindingElement sbe)
        {
            if (sbe.DefaultAlgorithmSuite != SecurityAlgorithmSuite.KerberosDefault)
                return false;
 
            // do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
 
            if (!sbe.IncludeTimestamp)
                return false;
 
            if (!(sbe is TransportSecurityBindingElement))
                return false;
 
            SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 0 || parameters.Endorsing.Count != 1 || parameters.SignedEndorsing.Count != 0)
                return false;
 
            KerberosSecurityTokenParameters kerberosParameters = parameters.Endorsing[0] as KerberosSecurityTokenParameters;
            if (kerberosParameters == null)
                return false;
 
            if (kerberosParameters.RequireDerivedKeys)
                return false;
 
            return true;
        }
#endif
        static public TransportSecurityBindingElement CreateSspiNegotiationOverTransportBindingElement()
        {
            return CreateSspiNegotiationOverTransportBindingElement(true);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsSspiNegotiationOverTransportBinding() method.
        static public TransportSecurityBindingElement CreateSspiNegotiationOverTransportBindingElement(bool requireCancellation)
        {
            TransportSecurityBindingElement result = new TransportSecurityBindingElement();
            SspiSecurityTokenParameters sspiParameters = new SspiSecurityTokenParameters(requireCancellation);
            sspiParameters.RequireDerivedKeys = false;
            result.EndpointSupportingTokenParameters.Endorsing.Add(
                sspiParameters);
            result.IncludeTimestamp = true;
            result.LocalClientSettings.DetectReplays = false;
            result.LocalServiceSettings.DetectReplays = false;
            result.SupportsExtendedProtectionPolicy = true;
 
            return result;
        }
 
        // this method reverses CreateSspiNegotiationOverTransportBindingElement() logic
        internal static bool IsSspiNegotiationOverTransportBinding(SecurityBindingElement sbe, bool requireCancellation)
        {
            // do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
 
            if (!sbe.IncludeTimestamp)
                return false;
 
            SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
            if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 0 || parameters.Endorsing.Count != 1 || parameters.SignedEndorsing.Count != 0)
                return false;
            SspiSecurityTokenParameters sspiParameters = parameters.Endorsing[0] as SspiSecurityTokenParameters;
            if (sspiParameters == null)
                return false;
 
            if (sspiParameters.RequireDerivedKeys)
                return false;
 
            if (sspiParameters.RequireCancellation != requireCancellation)
                return false;
 
            if (!(sbe is TransportSecurityBindingElement))
                return false;
 
            return true;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsIssuedTokenOverTransportBinding() method.
        static public TransportSecurityBindingElement CreateIssuedTokenOverTransportBindingElement(IssuedSecurityTokenParameters issuedTokenParameters)
        {
            if (issuedTokenParameters == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("issuedTokenParameters");
 
            issuedTokenParameters.RequireDerivedKeys = false;
            TransportSecurityBindingElement result = new TransportSecurityBindingElement();
            if (issuedTokenParameters.KeyType == SecurityKeyType.BearerKey)
            {
                result.EndpointSupportingTokenParameters.Signed.Add(issuedTokenParameters);
                result.MessageSecurityVersion = MessageSecurityVersion.WSSXDefault;
            }
            else
            {
                result.EndpointSupportingTokenParameters.Endorsing.Add(issuedTokenParameters);
                result.MessageSecurityVersion = MessageSecurityVersion.Default;
            }
            result.LocalClientSettings.DetectReplays = false;
            result.LocalServiceSettings.DetectReplays = false;
            result.IncludeTimestamp = true;
 
            return result;
        }
 
        // this method reverses CreateIssuedTokenOverTransportBindingElement() logic
        internal static bool IsIssuedTokenOverTransportBinding(SecurityBindingElement sbe, out IssuedSecurityTokenParameters issuedTokenParameters)
        {
            issuedTokenParameters = null;
            if (!(sbe is TransportSecurityBindingElement))
                return false;
 
            if (!sbe.IncludeTimestamp)
                return false;
 
            // do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
 
            SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
            if (parameters.SignedEncrypted.Count != 0 || (parameters.Signed.Count == 0 && parameters.Endorsing.Count == 0) || parameters.SignedEndorsing.Count != 0)
                return false;
            if ((parameters.Signed.Count == 1) && (parameters.Endorsing.Count == 0))
            {
                issuedTokenParameters = parameters.Signed[0] as IssuedSecurityTokenParameters;
                if (issuedTokenParameters != null && issuedTokenParameters.KeyType != SecurityKeyType.BearerKey)
                    return false;
            }
            else if ((parameters.Endorsing.Count == 1) && (parameters.Signed.Count == 0))
            {
                issuedTokenParameters = parameters.Endorsing[0] as IssuedSecurityTokenParameters;
                if (issuedTokenParameters != null && (issuedTokenParameters.KeyType != SecurityKeyType.SymmetricKey && issuedTokenParameters.KeyType != SecurityKeyType.AsymmetricKey))
                    return false;
            }
            if (issuedTokenParameters == null)
                return false;
            if (issuedTokenParameters.RequireDerivedKeys)
                return false;
 
            return true;
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsSecureConversationBinding() method.
        static public SecurityBindingElement CreateSecureConversationBindingElement(SecurityBindingElement bootstrapSecurity)
        {
            return CreateSecureConversationBindingElement(bootstrapSecurity, SecureConversationSecurityTokenParameters.defaultRequireCancellation, null);
        }
 
        // this method reverses CreateSecureConversationBindingElement() logic
        internal static bool IsSecureConversationBinding(SecurityBindingElement sbe, out SecurityBindingElement bootstrapSecurity)
        {
            return IsSecureConversationBinding(sbe, SecureConversationSecurityTokenParameters.defaultRequireCancellation, out bootstrapSecurity);
        }
 
        static public SecurityBindingElement CreateSecureConversationBindingElement(SecurityBindingElement bootstrapSecurity, bool requireCancellation)
        {
            return CreateSecureConversationBindingElement(bootstrapSecurity, requireCancellation, null);
        }
 
        // If any changes are made to this method, please make sure that they are
        // reflected in the corresponding IsSecureConversationBinding() method.
        static public SecurityBindingElement CreateSecureConversationBindingElement(SecurityBindingElement bootstrapSecurity, bool requireCancellation, ChannelProtectionRequirements bootstrapProtectionRequirements)
        {
            if (bootstrapSecurity == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bootstrapBinding");
 
            SecurityBindingElement result;
 
            if (bootstrapSecurity is TransportSecurityBindingElement)
            {
                // there is no need to do replay detection or key derivation for transport bindings
                TransportSecurityBindingElement primary = new TransportSecurityBindingElement();                
                SecureConversationSecurityTokenParameters scParameters = new SecureConversationSecurityTokenParameters(
                        bootstrapSecurity,
                        requireCancellation,
                        bootstrapProtectionRequirements);
                scParameters.RequireDerivedKeys = false;
                primary.EndpointSupportingTokenParameters.Endorsing.Add(
                    scParameters);                
                primary.LocalClientSettings.DetectReplays = false;
                primary.LocalServiceSettings.DetectReplays = false;
                primary.IncludeTimestamp = true;
                result = primary;
            }
            else // Symmetric- or AsymmetricSecurityBindingElement
            {
                SymmetricSecurityBindingElement primary = new SymmetricSecurityBindingElement(
                    new SecureConversationSecurityTokenParameters(
                        bootstrapSecurity,
                        requireCancellation,
                        bootstrapProtectionRequirements));
                // there is no need for signature confirmation on the steady state binding
                primary.RequireSignatureConfirmation = false;
                result = primary;
            }
 
            return result;
        }
 
        // this method reverses CreateSecureConversationBindingElement() logic
        internal static bool IsSecureConversationBinding(SecurityBindingElement sbe, bool requireCancellation, out SecurityBindingElement bootstrapSecurity)
        {
            bootstrapSecurity = null;
            SymmetricSecurityBindingElement ssbe = sbe as SymmetricSecurityBindingElement;
            if (ssbe != null)
            {
                if (ssbe.RequireSignatureConfirmation)
                    return false;
 
                SecureConversationSecurityTokenParameters parameters = ssbe.ProtectionTokenParameters as SecureConversationSecurityTokenParameters;
                if (parameters == null)
                    return false;
                if (parameters.RequireCancellation != requireCancellation)
                    return false;
                bootstrapSecurity = parameters.BootstrapSecurityBindingElement;
            }
            else
            {
                if (!sbe.IncludeTimestamp)
                    return false;
 
                // do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
 
                if (!(sbe is TransportSecurityBindingElement))
                    return false;
 
                SupportingTokenParameters parameters = sbe.EndpointSupportingTokenParameters;
                if (parameters.Signed.Count != 0 || parameters.SignedEncrypted.Count != 0 || parameters.Endorsing.Count != 1 || parameters.SignedEndorsing.Count != 0)
                    return false;
                SecureConversationSecurityTokenParameters scParameters = parameters.Endorsing[0] as SecureConversationSecurityTokenParameters;
                if (scParameters == null)
                    return false;
 
                if (scParameters.RequireCancellation != requireCancellation)
                    return false;
 
                bootstrapSecurity = scParameters.BootstrapSecurityBindingElement;
 
            }
 
            if (bootstrapSecurity != null && bootstrapSecurity.SecurityHeaderLayout != SecurityProtocolFactory.defaultSecurityHeaderLayout)
                return false;
 
            return bootstrapSecurity != null;
        }
 
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
 
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "{0}:", this.GetType().ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "DefaultAlgorithmSuite: {0}", this.defaultAlgorithmSuite.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "IncludeTimestamp: {0}", this.includeTimestamp.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "KeyEntropyMode: {0}", this.keyEntropyMode.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "MessageSecurityVersion: {0}", this.MessageSecurityVersion.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "SecurityHeaderLayout: {0}", this.securityHeaderLayout.ToString()));
            sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "ProtectTokens: {0}", this.protectTokens.ToString()));
            sb.AppendLine("EndpointSupportingTokenParameters:");
            sb.AppendLine("  " + this.EndpointSupportingTokenParameters.ToString().Trim().Replace("\n", "\n  "));
            sb.AppendLine("OptionalEndpointSupportingTokenParameters:");
            sb.AppendLine("  " + this.OptionalEndpointSupportingTokenParameters.ToString().Trim().Replace("\n", "\n  "));
            if (this.operationSupportingTokenParameters.Count == 0)
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "OperationSupportingTokenParameters: none"));
            }
            else
            {
                foreach (string requestAction in this.OperationSupportingTokenParameters.Keys)
                {
                    sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "OperationSupportingTokenParameters[\"{0}\"]:", requestAction));
                    sb.AppendLine("  " + this.OperationSupportingTokenParameters[requestAction].ToString().Trim().Replace("\n", "\n  "));
                }
            }
            if (this.optionalOperationSupportingTokenParameters.Count == 0)
            {
                sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "OptionalOperationSupportingTokenParameters: none"));
            }
            else
            {
                foreach (string requestAction in this.OptionalOperationSupportingTokenParameters.Keys)
                {
                    sb.AppendLine(String.Format(CultureInfo.InvariantCulture, "OptionalOperationSupportingTokenParameters[\"{0}\"]:", requestAction));
                    sb.AppendLine("  " + this.OptionalOperationSupportingTokenParameters[requestAction].ToString().Trim().Replace("\n", "\n  "));
                }
            }
 
            return sb.ToString().Trim();
        }
 
 
        internal static ChannelProtectionRequirements ComputeProtectionRequirements(SecurityBindingElement security, BindingParameterCollection parameterCollection, BindingElementCollection bindingElements, bool isForService)
        {
            if (parameterCollection == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameterCollection");
            if (bindingElements == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bindingElements");
            if (security == null)
            {
                return null;
            }
 
            ChannelProtectionRequirements result = null;
            if ((security is SymmetricSecurityBindingElement) || (security is AsymmetricSecurityBindingElement))
            {
                result = new ChannelProtectionRequirements();
                ChannelProtectionRequirements contractRequirements = parameterCollection.Find<ChannelProtectionRequirements>();
 
                if (contractRequirements != null)
                    result.Add(contractRequirements);
 
                AddBindingProtectionRequirements(result, bindingElements, !isForService);
            }
 
            return result;
        }
 
        static void AddBindingProtectionRequirements(ChannelProtectionRequirements requirements, BindingElementCollection bindingElements, bool isForChannel)
        {
            // Gather custom requirements from bindingElements
            CustomBinding binding = new CustomBinding(bindingElements);
            BindingContext context = new BindingContext(binding, new BindingParameterCollection());
            // In theory, we can just do 
            //     context.GetInnerProperty<ChannelProtectionRequirements>()
            // but that relies on each binding element to correctly union-up its own requirements with
            // those of the rest of the stack.  So instead, we ask each BE individually, and we do the 
            // work of combining the results.  This protects us against this scenario: someone authors "FooBE"
            // with a a GetProperty implementation that always returns null (oops), and puts FooBE on the 
            // top of the stack, and so FooBE "hides" important protection requirements that inner BEs
            // require, resulting in an insecure binding.
            foreach (BindingElement bindingElement in bindingElements)
            {
                if (bindingElement != null)
                {
                    // ask each element individually for its requirements
                    context.RemainingBindingElements.Clear();
                    context.RemainingBindingElements.Add(bindingElement);
                    ChannelProtectionRequirements s = context.GetInnerProperty<ChannelProtectionRequirements>();
                    if (s != null)
                    {
                        //if (isForChannel)
                        //{
                        //    requirements.Add(s.CreateInverse());
                        //}
                        //else
                        //{
                            requirements.Add(s);
                        //}
                    }
                }
            }
        }
 
        internal void ApplyAuditBehaviorSettings(BindingContext context, SecurityProtocolFactory factory)
        {
            ServiceSecurityAuditBehavior auditBehavior = context.BindingParameters.Find<ServiceSecurityAuditBehavior>();
            if (auditBehavior != null)
            {
                factory.AuditLogLocation = auditBehavior.AuditLogLocation;
                factory.SuppressAuditFailure = auditBehavior.SuppressAuditFailure;
                factory.ServiceAuthorizationAuditLevel = auditBehavior.ServiceAuthorizationAuditLevel;
                factory.MessageAuthenticationAuditLevel = auditBehavior.MessageAuthenticationAuditLevel;
            }
            else
            {
                factory.AuditLogLocation = ServiceSecurityAuditBehavior.defaultAuditLogLocation;
                factory.SuppressAuditFailure = ServiceSecurityAuditBehavior.defaultSuppressAuditFailure;
                factory.ServiceAuthorizationAuditLevel = ServiceSecurityAuditBehavior.defaultServiceAuthorizationAuditLevel;
                factory.MessageAuthenticationAuditLevel = ServiceSecurityAuditBehavior.defaultMessageAuthenticationAuditLevel;
            }
        }
 
        internal override bool IsMatch(BindingElement b)
        {
            if (b == null)
                return false;
 
            SecurityBindingElement security = b as SecurityBindingElement;
            if (security == null)
                return false;
            return SecurityElement.AreBindingsMatching(this, security);
        }
 
        static void AddAssertionIfNotNull(PolicyConversionContext policyContext, XmlElement assertion)
        {
            if (policyContext != null && assertion != null)
            {
                policyContext.GetBindingAssertions().Add(assertion);
            }
        }
 
        static void AddAssertionIfNotNull(PolicyConversionContext policyContext, Collection<XmlElement> assertions)
        {
            if (policyContext != null && assertions != null)
            {
                PolicyAssertionCollection existingAssertions = policyContext.GetBindingAssertions();
                for (int i = 0; i < assertions.Count; ++i)
                    existingAssertions.Add(assertions[i]);
            }
        }
 
        static void AddAssertionIfNotNull(PolicyConversionContext policyContext, OperationDescription operation, XmlElement assertion)
        {
            if (policyContext != null && assertion != null)
            {
                policyContext.GetOperationBindingAssertions(operation).Add(assertion);
            }
        }
 
        static void AddAssertionIfNotNull(PolicyConversionContext policyContext, OperationDescription operation, Collection<XmlElement> assertions)
        {
            if (policyContext != null && assertions != null)
            {
                PolicyAssertionCollection existingAssertions = policyContext.GetOperationBindingAssertions(operation);
                for (int i = 0; i < assertions.Count; ++i)
                    existingAssertions.Add(assertions[i]);
            }
        }
 
        static void AddAssertionIfNotNull(PolicyConversionContext policyContext, MessageDescription message, XmlElement assertion)
        {
            if (policyContext != null && assertion != null)
            {
                policyContext.GetMessageBindingAssertions(message).Add(assertion);
            }
        }
 
        static void AddAssertionIfNotNull(PolicyConversionContext policyContext, FaultDescription message, XmlElement assertion)
        {
            if (policyContext != null && assertion != null)
            {
                policyContext.GetFaultBindingAssertions(message).Add(assertion);
            }
        }
 
        internal static void ExportPolicy(MetadataExporter exporter, PolicyConversionContext context)
        {
            if (exporter == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter");
            }
 
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
 
            SecurityTraceRecordHelper.TraceExportChannelBindingEntry();
 
            SecurityBindingElement binding = null;
            ITransportTokenAssertionProvider transportTokenAssertionProvider = null;
            BindingElementCollection bindingElementsBelowSecurity = new BindingElementCollection();
            if ((context != null) && (context.BindingElements != null))
            {
                foreach (BindingElement be in context.BindingElements)
                {
                    if (be is SecurityBindingElement)
                    {
                        binding = (SecurityBindingElement)be;
                    }
                    else
                    {
                        if (binding != null || be is MessageEncodingBindingElement || be is ITransportTokenAssertionProvider)
                        {
                            bindingElementsBelowSecurity.Add(be);
                        }
                        if (be is ITransportTokenAssertionProvider)
                        {
                            transportTokenAssertionProvider = (ITransportTokenAssertionProvider)be;
                        }
                    }
                }
            }
 
            // this is used when exporting bootstrap policy for secure conversation in SecurityPolicy11.CreateWsspBootstrapPolicyAssertion
            exporter.State[SecurityPolicyStrings.SecureConversationBootstrapBindingElementsBelowSecurityKey] = bindingElementsBelowSecurity;
 
            bool hasCompletedSuccessfully = false;
            try
            {
                if (binding is SymmetricSecurityBindingElement)
                {
                    ExportSymmetricSecurityBindingElement((SymmetricSecurityBindingElement)binding, exporter, context);
                    ExportOperationScopeSupportingTokensPolicy(binding, exporter, context);
                    ExportMessageScopeProtectionPolicy(binding, exporter, context);
                }
                else if (binding is AsymmetricSecurityBindingElement)
                {
                    ExportAsymmetricSecurityBindingElement((AsymmetricSecurityBindingElement)binding, exporter, context);
                    ExportOperationScopeSupportingTokensPolicy(binding, exporter, context);
                    ExportMessageScopeProtectionPolicy(binding, exporter, context);
                }
 
                hasCompletedSuccessfully = true;
            }
            finally
            {
                try
                {
                    exporter.State.Remove(SecurityPolicyStrings.SecureConversationBootstrapBindingElementsBelowSecurityKey);
                }
                catch (Exception e)
                {
                    // Always immediately rethrow fatal exceptions.
                    if (hasCompletedSuccessfully || Fx.IsFatal(e)) throw;
                }
            }
        }
 
        internal static void ExportPolicyForTransportTokenAssertionProviders(MetadataExporter exporter, PolicyConversionContext context)
        {
            if (exporter == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("exporter");
            }
 
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
 
            SecurityTraceRecordHelper.TraceExportChannelBindingEntry();
 
            SecurityBindingElement binding = null;
            ITransportTokenAssertionProvider transportTokenAssertionProvider = null;
            BindingElementCollection bindingElementsBelowSecurity = new BindingElementCollection();
            if ((context != null) && (context.BindingElements != null))
            {
                foreach (BindingElement be in context.BindingElements)
                {
                    if (be is SecurityBindingElement)
                    {
                        binding = (SecurityBindingElement)be;
                    }
                    else
                    {
                        if (binding != null || be is MessageEncodingBindingElement || be is ITransportTokenAssertionProvider)
                        {
                            bindingElementsBelowSecurity.Add(be);
                        }
                        if (be is ITransportTokenAssertionProvider)
                        {
                            transportTokenAssertionProvider = (ITransportTokenAssertionProvider)be;
                        }
                    }
                }
            }
 
            // this is used when exporting bootstrap policy for secure conversation in SecurityPolicy11.CreateWsspBootstrapPolicyAssertion
            exporter.State[SecurityPolicyStrings.SecureConversationBootstrapBindingElementsBelowSecurityKey] = bindingElementsBelowSecurity;
 
            bool hasCompletedSuccessfully = false;
            try
            {
                if (binding is TransportSecurityBindingElement)
                {
                    if (transportTokenAssertionProvider == null && !binding.AllowInsecureTransport)
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ExportOfBindingWithTransportSecurityBindingElementAndNoTransportSecurityNotSupported)));
                    }
 
                    ExportTransportSecurityBindingElement((TransportSecurityBindingElement)binding, transportTokenAssertionProvider, exporter, context);
                    ExportOperationScopeSupportingTokensPolicy(binding, exporter, context);
                }
                else if (transportTokenAssertionProvider != null)
                {
                    TransportSecurityBindingElement dummyTransportBindingElement = new TransportSecurityBindingElement();
                    if (binding == null)
                    {
                        dummyTransportBindingElement.IncludeTimestamp = false;
                    }
 
                    // In order to generate the right sp assertion without SBE.
                    // scenario: WSxHttpBinding with SecurityMode.Transport.
                    // See CSD 3105 for detail
                    HttpsTransportBindingElement httpsBinding = transportTokenAssertionProvider as HttpsTransportBindingElement;
                    if (httpsBinding != null && httpsBinding.MessageSecurityVersion != null)
                    {
                        dummyTransportBindingElement.MessageSecurityVersion = httpsBinding.MessageSecurityVersion;
                    }
 
                    ExportTransportSecurityBindingElement(dummyTransportBindingElement, transportTokenAssertionProvider, exporter, context);
                }
 
                hasCompletedSuccessfully = true;
            }
            finally
            {
                try
                {
                    exporter.State.Remove(SecurityPolicyStrings.SecureConversationBootstrapBindingElementsBelowSecurityKey);
                }
                catch (Exception e)
                {
                    // Always immediately rethrow fatal exceptions.
                    if (hasCompletedSuccessfully || Fx.IsFatal(e)) throw;
                }
            }
        }
 
        //
        // We will emit the wssp trust 10 assertion for all the case except for the basic http binding
        // created through the BasicHttpBinding class.  The reason for this exception is to allow better 
        // interop with third party when the third party doesn't understand the trust ----erion
        //
        static bool RequiresWsspTrust(SecurityBindingElement sbe)
        {
            if (sbe == null)
                return false;
 
            return !(sbe.doNotEmitTrust);
        }
 
        static void ExportAsymmetricSecurityBindingElement(AsymmetricSecurityBindingElement binding, MetadataExporter exporter, PolicyConversionContext policyContext)
        {
            WSSecurityPolicy sp = WSSecurityPolicy.GetSecurityPolicyDriver(binding.MessageSecurityVersion);
 
            AddAssertionIfNotNull(policyContext, sp.CreateWsspAsymmetricBindingAssertion(exporter, policyContext, binding));
 
            AddAssertionIfNotNull(policyContext, sp.CreateWsspSupportingTokensAssertion(
                exporter,
                binding.EndpointSupportingTokenParameters.Signed,
                binding.EndpointSupportingTokenParameters.SignedEncrypted,
                binding.EndpointSupportingTokenParameters.Endorsing,
                binding.EndpointSupportingTokenParameters.SignedEndorsing,
                binding.OptionalEndpointSupportingTokenParameters.Signed,
                binding.OptionalEndpointSupportingTokenParameters.SignedEncrypted,
                binding.OptionalEndpointSupportingTokenParameters.Endorsing,
                binding.OptionalEndpointSupportingTokenParameters.SignedEndorsing));
 
            AddAssertionIfNotNull(policyContext, sp.CreateWsspWssAssertion(exporter, binding));
 
            if (RequiresWsspTrust(binding))
            {
                AddAssertionIfNotNull(policyContext, sp.CreateWsspTrustAssertion(exporter, binding.KeyEntropyMode));
            }
        }
 
        static void ExportTransportSecurityBindingElement(TransportSecurityBindingElement binding, ITransportTokenAssertionProvider transportTokenAssertionProvider, MetadataExporter exporter, PolicyConversionContext policyContext)
        {
            WSSecurityPolicy sp = WSSecurityPolicy.GetSecurityPolicyDriver(binding.MessageSecurityVersion);
 
            if (transportTokenAssertionProvider == null && binding.AllowInsecureTransport)
            {
                if ((policyContext != null) && (policyContext.BindingElements != null))
                {
                    foreach (BindingElement be in policyContext.BindingElements)
                    {
                        if (be is HttpTransportBindingElement)
                        {
                            transportTokenAssertionProvider = new HttpsTransportBindingElement();
                            break;
                        }
                        
                        if (be is TcpTransportBindingElement)
                        {
                            transportTokenAssertionProvider = new SslStreamSecurityBindingElement();
                            break;
                        }
                    }
                }
            }
 
            XmlElement transportTokenAssertion = transportTokenAssertionProvider.GetTransportTokenAssertion();
 
            if (transportTokenAssertion == null)
            {
                if (transportTokenAssertionProvider is HttpsTransportBindingElement)
                {
                    transportTokenAssertion = sp.CreateWsspHttpsTokenAssertion(exporter, (HttpsTransportBindingElement)transportTokenAssertionProvider);
                }
 
                if (transportTokenAssertion == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoTransportTokenAssertionProvided, transportTokenAssertionProvider.GetType().ToString())));
            }
 
            AddressingVersion addressingVersion = AddressingVersion.WSAddressing10;
            MessageEncodingBindingElement messageEncoderBindingElement = policyContext.BindingElements.Find<MessageEncodingBindingElement>();
            if (messageEncoderBindingElement != null)
            {
                addressingVersion = messageEncoderBindingElement.MessageVersion.Addressing;
            }
 
            AddAssertionIfNotNull(policyContext, sp.CreateWsspTransportBindingAssertion(exporter, binding, transportTokenAssertion));
 
            Collection<XmlElement> supportingTokenAssertions = sp.CreateWsspSupportingTokensAssertion(
                exporter,
                binding.EndpointSupportingTokenParameters.Signed,
                binding.EndpointSupportingTokenParameters.SignedEncrypted,
                binding.EndpointSupportingTokenParameters.Endorsing,
                binding.EndpointSupportingTokenParameters.SignedEndorsing,
                binding.OptionalEndpointSupportingTokenParameters.Signed,
                binding.OptionalEndpointSupportingTokenParameters.SignedEncrypted,
                binding.OptionalEndpointSupportingTokenParameters.Endorsing,
                binding.OptionalEndpointSupportingTokenParameters.SignedEndorsing,
                addressingVersion);
 
            AddAssertionIfNotNull(policyContext, supportingTokenAssertions);
 
            if (supportingTokenAssertions.Count > 0
                || HasEndorsingSupportingTokensAtOperationScope(binding))
            {
                AddAssertionIfNotNull(policyContext, sp.CreateWsspWssAssertion(exporter, binding));
                if (RequiresWsspTrust(binding))
                {
                    AddAssertionIfNotNull(policyContext, sp.CreateWsspTrustAssertion(exporter, binding.KeyEntropyMode));
                }
            }
        }
 
        static bool HasEndorsingSupportingTokensAtOperationScope(SecurityBindingElement binding)
        {
            foreach (SupportingTokenParameters r in binding.OperationSupportingTokenParameters.Values)
            {
                if (r.Endorsing.Count > 0 || r.SignedEndorsing.Count > 0)
                {
                    return true;
                }
            }
 
            return false;
        }
 
        static void ExportSymmetricSecurityBindingElement(SymmetricSecurityBindingElement binding, MetadataExporter exporter, PolicyConversionContext policyContext)
        {
            WSSecurityPolicy sp = WSSecurityPolicy.GetSecurityPolicyDriver(binding.MessageSecurityVersion);
 
            AddAssertionIfNotNull(policyContext, sp.CreateWsspSymmetricBindingAssertion(exporter, policyContext, binding));
 
            AddAssertionIfNotNull(policyContext, sp.CreateWsspSupportingTokensAssertion(
                exporter,
                binding.EndpointSupportingTokenParameters.Signed,
                binding.EndpointSupportingTokenParameters.SignedEncrypted,
                binding.EndpointSupportingTokenParameters.Endorsing,
                binding.EndpointSupportingTokenParameters.SignedEndorsing,
                binding.OptionalEndpointSupportingTokenParameters.Signed,
                binding.OptionalEndpointSupportingTokenParameters.SignedEncrypted,
                binding.OptionalEndpointSupportingTokenParameters.Endorsing,
                binding.OptionalEndpointSupportingTokenParameters.SignedEndorsing));
 
            AddAssertionIfNotNull(policyContext, sp.CreateWsspWssAssertion(exporter, binding));
 
            if (RequiresWsspTrust(binding))
            {
                AddAssertionIfNotNull(policyContext, sp.CreateWsspTrustAssertion(exporter, binding.KeyEntropyMode));
            }
        }
 
        static void ExportMessageScopeProtectionPolicy(SecurityBindingElement security, MetadataExporter exporter, PolicyConversionContext policyContext)
        {
            BindingParameterCollection bindingParameters = new BindingParameterCollection();
            bindingParameters.Add(ChannelProtectionRequirements.CreateFromContract(policyContext.Contract, policyContext.BindingElements.Find<SecurityBindingElement>().GetIndividualProperty<ISecurityCapabilities>(), false));
            ChannelProtectionRequirements protectionRequirements = SecurityBindingElement.ComputeProtectionRequirements(security, bindingParameters, policyContext.BindingElements, true);
            protectionRequirements.MakeReadOnly();
 
            WSSecurityPolicy sp = WSSecurityPolicy.GetSecurityPolicyDriver(security.MessageSecurityVersion);
 
            foreach (OperationDescription operation in policyContext.Contract.Operations)
            {
                // export policy for application messages
                foreach (MessageDescription message in operation.Messages)
                {
                    MessagePartSpecification parts;
                    ScopedMessagePartSpecification scopedParts;
 
                    // integrity
                    if (message.Direction == MessageDirection.Input)
                    {
                        scopedParts = protectionRequirements.IncomingSignatureParts;
                    }
                    else
                    {
                        scopedParts = protectionRequirements.OutgoingSignatureParts;
                    }
 
                    if (scopedParts.TryGetParts(message.Action, out parts))
                    {
                        AddAssertionIfNotNull(policyContext, message, sp.CreateWsspSignedPartsAssertion(parts));
                    }
 
                    // confidentiality
                    if (message.Direction == MessageDirection.Input)
                    {
                        scopedParts = protectionRequirements.IncomingEncryptionParts;
                    }
                    else
                    {
                        scopedParts = protectionRequirements.OutgoingEncryptionParts;
                    }
 
                    if (scopedParts.TryGetParts(message.Action, out parts))
                    {
                        AddAssertionIfNotNull(policyContext, message, sp.CreateWsspEncryptedPartsAssertion(parts));
                    }
                }
 
                // export policy for faults
                foreach (FaultDescription fault in operation.Faults)
                {
                    MessagePartSpecification parts;
 
                    // integrity
                    if (protectionRequirements.OutgoingSignatureParts.TryGetParts(fault.Action, out parts))
                    {
                        AddAssertionIfNotNull(policyContext, fault, sp.CreateWsspSignedPartsAssertion(parts));
                    }
 
                    // confidentiality
                    if (protectionRequirements.OutgoingEncryptionParts.TryGetParts(fault.Action, out parts))
                    {
                        AddAssertionIfNotNull(policyContext, fault, sp.CreateWsspEncryptedPartsAssertion(parts));
                    }
                }
            }
        }
 
        static void ExportOperationScopeSupportingTokensPolicy(SecurityBindingElement binding, MetadataExporter exporter, PolicyConversionContext policyContext)
        {
            WSSecurityPolicy sp = WSSecurityPolicy.GetSecurityPolicyDriver(binding.MessageSecurityVersion);
 
            if (binding.OperationSupportingTokenParameters.Count == 0 && binding.OptionalOperationSupportingTokenParameters.Count == 0)
            {
                return;
            }
 
            foreach (OperationDescription operation in policyContext.Contract.Operations)
            {
                foreach (MessageDescription message in operation.Messages)
                {
 
                    if (message.Direction == MessageDirection.Input)
                    {
                        SupportingTokenParameters requirements = null;
                        SupportingTokenParameters optionalRequirements = null;
 
                        if (binding.OperationSupportingTokenParameters.ContainsKey(message.Action))
                        {
                            requirements = binding.OperationSupportingTokenParameters[message.Action];
                        }
                        if (binding.OptionalOperationSupportingTokenParameters.ContainsKey(message.Action))
                        {
                            optionalRequirements = binding.OptionalOperationSupportingTokenParameters[message.Action];
                        }
 
                        if (requirements == null && optionalRequirements == null)
                        {
                            continue;
                        }
 
                        AddAssertionIfNotNull(policyContext, operation, sp.CreateWsspSupportingTokensAssertion(
                            exporter,
                            requirements == null ? null : requirements.Signed,
                            requirements == null ? null : requirements.SignedEncrypted,
                            requirements == null ? null : requirements.Endorsing,
                            requirements == null ? null : requirements.SignedEndorsing,
                            optionalRequirements == null ? null : optionalRequirements.Signed,
                            optionalRequirements == null ? null : optionalRequirements.SignedEncrypted,
                            optionalRequirements == null ? null : optionalRequirements.Endorsing,
                            optionalRequirements == null ? null : optionalRequirements.SignedEndorsing));
                    }
                }
            }
        }
    }
}