< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.TokenElement
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/SendSecurityHeader.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 11
Coverable lines: 11
Total lines: 1031
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
Equals(...)0%440%
GetHashCode()100%110%
WriteTo(...)100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/SendSecurityHeader.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Threading.Tasks;
 7using System.Xml;
 8using CoreWCF.Channels;
 9using CoreWCF.Description;
 10using CoreWCF.Diagnostics;
 11using CoreWCF.IdentityModel;
 12using CoreWCF.IdentityModel.Tokens;
 13using CoreWCF.Security.Tokens;
 14using DictionaryManager = CoreWCF.IdentityModel.DictionaryManager;
 15using IPrefixGenerator = CoreWCF.IdentityModel.IPrefixGenerator;
 16using ISecurityElement = CoreWCF.IdentityModel.ISecurityElement;
 17using ISignatureValueSecurityElement = CoreWCF.IdentityModel.ISignatureValueSecurityElement;
 18
 19namespace CoreWCF.Security
 20{
 21    internal abstract class SendSecurityHeader : SecurityHeader, IMessageHeaderWithSharedNamespace
 22    {
 23        private bool _basicTokenEncrypted;
 24        private bool _primarySignatureDone;
 25        private bool _encryptSignature;
 26        private SignatureConfirmations _signatureValuesGenerated;
 27        private SignatureConfirmations _signatureConfirmationsToSend;
 28        private int _idCounter;
 29        private string _idPrefix;
 30        private MessagePartSpecification _signatureParts;
 31        private MessagePartSpecification _encryptionParts;
 32        private SecurityTokenParameters _encryptingTokenParameters;
 33        private List<SecurityToken> _basicTokens = null;
 34        private List<SecurityTokenParameters> _basicSupportingTokenParameters = null;
 35        private List<SecurityTokenParameters> _endorsingTokenParameters = null;
 36        private List<SecurityTokenParameters> _signedEndorsingTokenParameters = null;
 37        private List<SecurityTokenParameters> _signedTokenParameters = null;
 38        private SecurityToken _encryptingToken;
 39        private bool _skipKeyInfoForEncryption;
 40        private bool _shouldProtectTokens;
 41        private BufferManager _bufferManager;
 42        private SecurityProtocolCorrelationState _correlationState;
 43        private bool _signThenEncrypt = true;
 44        private static readonly string[] s_ids = new string[] { "_0", "_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8", "_
 45
 46        protected SendSecurityHeader(Message message, string actor, bool mustUnderstand, bool relay,
 47            SecurityStandardsManager standardsManager,
 48            SecurityAlgorithmSuite algorithmSuite,
 49            MessageDirection transferDirection)
 50            : base(message, actor, mustUnderstand, relay, standardsManager, algorithmSuite, transferDirection)
 51        {
 52            ElementContainer = new SendSecurityHeaderElementContainer();
 53        }
 54
 55        public SendSecurityHeaderElementContainer ElementContainer { get; }
 56
 57        public SecurityProtocolCorrelationState CorrelationState
 58        {
 59            get { return _correlationState; }
 60            set
 61            {
 62                ThrowIfProcessingStarted();
 63                _correlationState = value;
 64            }
 65        }
 66
 67        public BufferManager StreamBufferManager
 68        {
 69            get
 70            {
 71                if (_bufferManager == null)
 72                {
 73                    _bufferManager = BufferManager.CreateBufferManager(0, int.MaxValue);
 74                }
 75
 76                return _bufferManager;
 77            }
 78            set
 79            {
 80                _bufferManager = value;
 81            }
 82        }
 83
 84        public MessagePartSpecification EncryptionParts
 85        {
 86            get { return _encryptionParts; }
 87            set
 88            {
 89                ThrowIfProcessingStarted();
 90                if (value == null)
 91                {
 92                    throw TraceUtility.ThrowHelperError(new ArgumentNullException(nameof(value)), Message);
 93                }
 94                if (!value.IsReadOnly)
 95                {
 96                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.MessagePartSpecificationMustBeI
 97                }
 98                _encryptionParts = value;
 99            }
 100        }
 101
 102        public bool EncryptPrimarySignature
 103        {
 104            get { return _encryptSignature; }
 105            set
 106            {
 107                ThrowIfProcessingStarted();
 108                _encryptSignature = value;
 109            }
 110        }
 111
 112        internal byte[] PrimarySignatureValue { get; private set; } = null;
 113
 114        protected internal SecurityTokenParameters SigningTokenParameters { get; private set; }
 115
 116        protected bool ShouldSignToHeader { get; private set; } = false;
 117
 118        public string IdPrefix
 119        {
 120            get { return _idPrefix; }
 121            set
 122            {
 123                ThrowIfProcessingStarted();
 124                _idPrefix = string.IsNullOrEmpty(value) || value == "_" ? null : value;
 125            }
 126        }
 127
 128        public override string Name => StandardsManager.SecurityVersion.HeaderName.Value;
 129
 130        public override string Namespace => StandardsManager.SecurityVersion.HeaderNamespace.Value;
 131
 132        protected SecurityAppliedMessage SecurityAppliedMessage => (SecurityAppliedMessage)Message;
 133
 134        public bool SignThenEncrypt
 135        {
 136            get { return _signThenEncrypt; }
 137            set
 138            {
 139                ThrowIfProcessingStarted();
 140                _signThenEncrypt = value;
 141            }
 142        }
 143
 144        public bool ShouldProtectTokens
 145        {
 146            get { return _shouldProtectTokens; }
 147            set
 148            {
 149                ThrowIfProcessingStarted();
 150                _shouldProtectTokens = value;
 151            }
 152        }
 153
 154        public MessagePartSpecification SignatureParts
 155        {
 156            get { return _signatureParts; }
 157            set
 158            {
 159                ThrowIfProcessingStarted();
 160                if (value == null)
 161                {
 162                    throw TraceUtility.ThrowHelperError(new ArgumentNullException(nameof(value)), Message);
 163                }
 164                if (!value.IsReadOnly)
 165                {
 166                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(
 167                        SR.MessagePartSpecificationMustBeImmutable), Message);
 168                }
 169                _signatureParts = value;
 170            }
 171        }
 172
 173        public SecurityTimestamp Timestamp => ElementContainer.Timestamp;
 174
 175        public bool HasSignedTokens { get; private set; }
 176
 177        public bool HasEncryptedTokens { get; private set; }
 178
 179        public void AddPrerequisiteToken(SecurityToken token)
 180        {
 181            ThrowIfProcessingStarted();
 182            ElementContainer.PrerequisiteToken = token ?? throw TraceUtility.ThrowHelperError(new Exception(nameof(token
 183        }
 184
 185        private void AddParameters(ref List<SecurityTokenParameters> list, SecurityTokenParameters item)
 186        {
 187            if (list == null)
 188            {
 189                list = new List<SecurityTokenParameters>();
 190            }
 191            list.Add(item);
 192        }
 193
 194        public abstract void ApplyBodySecurity(XmlDictionaryWriter writer, IPrefixGenerator prefixGenerator);
 195
 196        public abstract ValueTask ApplyBodySecurityAsync(XmlDictionaryWriter writer, IPrefixGenerator prefixGenerator);
 197
 198        public abstract void ApplySecurityAndWriteHeaders(MessageHeaders headers, XmlDictionaryWriter writer, IPrefixGen
 199
 200        public abstract ValueTask ApplySecurityAndWriteHeadersAsync(MessageHeaders headers, XmlDictionaryWriter writer, 
 201
 202        protected virtual bool HasSignedEncryptedMessagePart => false;
 203
 204        public void SetSigningToken(SecurityToken token, SecurityTokenParameters tokenParameters)
 205        {
 206            ThrowIfProcessingStarted();
 207            if ((token == null && tokenParameters != null) || (token != null && tokenParameters == null))
 208            {
 209                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.TokenMustBe
 210            }
 211            ElementContainer.SourceSigningToken = token;
 212            SigningTokenParameters = tokenParameters;
 213        }
 214
 215        public void SetEncryptionToken(SecurityToken token, SecurityTokenParameters tokenParameters)
 216        {
 217            ThrowIfProcessingStarted();
 218            if ((token == null && tokenParameters != null) || (token != null && tokenParameters == null))
 219            {
 220                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.TokenMustBe
 221            }
 222            ElementContainer.SourceEncryptionToken = token;
 223            _encryptingTokenParameters = tokenParameters;
 224        }
 225
 226        public void AddBasicSupportingToken(SecurityToken token, SecurityTokenParameters parameters)
 227        {
 228            if (token == null)
 229            {
 230                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(token));
 231            }
 232
 233            if (parameters == null)
 234            {
 235                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(parameters));
 236            }
 237
 238            ThrowIfProcessingStarted();
 239            SendSecurityHeaderElement tokenElement = new SendSecurityHeaderElement(token.Id, new TokenElement(token, Sta
 240            {
 241                MarkedForEncryption = true
 242            };
 243            ElementContainer.AddBasicSupportingToken(tokenElement);
 244            HasEncryptedTokens = true;
 245            HasSignedTokens = true;
 246            AddParameters(ref _basicSupportingTokenParameters, parameters);
 247            if (_basicTokens == null)
 248            {
 249                _basicTokens = new List<SecurityToken>();
 250            }
 251            //  We maintain a list of the basic tokens for the SignThenEncrypt case as we will
 252            //  need this token to write STR entry on OnWriteHeaderContents.
 253            _basicTokens.Add(token);
 254        }
 255
 256        public void AddEndorsingSupportingToken(SecurityToken token, SecurityTokenParameters parameters)
 257        {
 258            if (token == null)
 259            {
 260                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(token));
 261            }
 262
 263            if (parameters == null)
 264            {
 265                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(parameters));
 266            }
 267
 268            ThrowIfProcessingStarted();
 269            ElementContainer.AddEndorsingSupportingToken(token);
 270            // The ProviderBackedSecurityToken was added for the ChannelBindingToken (CBT) effort for win7.
 271            // We can assume the key is of type symmetric key.
 272            //
 273            // Asking for the key type from the token will cause the ProviderBackedSecurityToken
 274            // to attempt to resolve the token and the nego will start.
 275            //
 276            // We don't want that.
 277            // We want to defer the nego until after the CBT is available in SecurityAppliedMessage.OnWriteMessage.
 278            //TODO
 279            //if (!(token is ProviderBackedSecurityToken))
 280            //{
 281            //    this.shouldSignToHeader |= (!this.RequireMessageProtection) && (SecurityUtils.GetSecurityKey<Asymmetri
 282            //}
 283            AddParameters(ref _endorsingTokenParameters, parameters);
 284        }
 285
 286        public void AddSignedEndorsingSupportingToken(SecurityToken token, SecurityTokenParameters parameters)
 287        {
 288            if (token == null)
 289            {
 290                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(token));
 291            }
 292
 293            if (parameters == null)
 294            {
 295                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(parameters));
 296            }
 297
 298            ThrowIfProcessingStarted();
 299            ElementContainer.AddSignedEndorsingSupportingToken(token);
 300            HasSignedTokens = true;
 301            ShouldSignToHeader |= (!RequireMessageProtection) && (SecurityUtils.GetSecurityKey<AsymmetricSecurityKey>(to
 302            AddParameters(ref _signedEndorsingTokenParameters, parameters);
 303        }
 304
 305        public void AddSignedSupportingToken(SecurityToken token, SecurityTokenParameters parameters)
 306        {
 307            if (token == null)
 308            {
 309                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(token));
 310            }
 311
 312            if (parameters == null)
 313            {
 314                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(parameters));
 315            }
 316
 317            ThrowIfProcessingStarted();
 318            ElementContainer.AddSignedSupportingToken(token);
 319            HasSignedTokens = true;
 320            AddParameters(ref _signedTokenParameters, parameters);
 321        }
 322
 323        public void AddSignatureConfirmations(SignatureConfirmations confirmations)
 324        {
 325            ThrowIfProcessingStarted();
 326            _signatureConfirmationsToSend = confirmations;
 327        }
 328
 329        public void AddTimestamp(TimeSpan timestampValidityDuration)
 330        {
 331            DateTime now = DateTime.UtcNow;
 332            string id = RequireMessageProtection ? SecurityUtils.GenerateId() : GenerateId();
 333            AddTimestamp(new SecurityTimestamp(now, now + timestampValidityDuration, id));
 334        }
 335
 336        public void AddTimestamp(SecurityTimestamp timestamp)
 337        {
 338            ThrowIfProcessingStarted();
 339            if (ElementContainer.Timestamp != null)
 340            {
 341                throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.TimestampAlreadySetForSecurityHeade
 342            }
 343
 344            ElementContainer.Timestamp = timestamp ?? throw TraceUtility.ThrowHelperArgumentNull(nameof(timestamp), Mess
 345        }
 346
 347        protected virtual ISignatureValueSecurityElement[] CreateSignatureConfirmationElements(SignatureConfirmations si
 348        {
 349            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 350                SR.Format(SR.SignatureConfirmationNotSupported)));
 351        }
 352
 353        private void StartEncryption()
 354        {
 355            if (ElementContainer.SourceEncryptionToken == null)
 356            {
 357                return;
 358            }
 359            // determine the key identifier clause to use for the source
 360            SecurityTokenReferenceStyle sourceEncryptingKeyReferenceStyle = GetTokenReferenceStyle(_encryptingTokenParam
 361            bool encryptionTokenSerialized = sourceEncryptingKeyReferenceStyle == SecurityTokenReferenceStyle.Internal;
 362            SecurityKeyIdentifierClause sourceEncryptingKeyIdentifierClause = _encryptingTokenParameters.CreateKeyIdenti
 363            if (sourceEncryptingKeyIdentifierClause == null)
 364            {
 365                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.TokenManagerCannotCreateTokenReferen
 366            }
 367            SecurityToken sourceToken;
 368            SecurityKeyIdentifierClause sourceTokenIdentifierClause;
 369
 370            // if the source token cannot do symmetric crypto, create a wrapped key
 371            if (!SecurityUtils.HasSymmetricSecurityKey(ElementContainer.SourceEncryptionToken))
 372            {
 373                int keyLength = Math.Max(128, AlgorithmSuite.DefaultSymmetricKeyLength);
 374                CryptoHelper.ValidateSymmetricKeyLength(keyLength, AlgorithmSuite);
 375                byte[] key = new byte[keyLength / 8];
 376                CryptoHelper.FillRandomBytes(key);
 377                AlgorithmSuite.GetKeyWrapAlgorithm(ElementContainer.SourceEncryptionToken, out string keyWrapAlgorithm, 
 378                WrappedKeySecurityToken wrappedKey = new WrappedKeySecurityToken(GenerateId(), key, keyWrapAlgorithm, ke
 379                    ElementContainer.SourceEncryptionToken, new SecurityKeyIdentifier(sourceEncryptingKeyIdentifierClaus
 380                ElementContainer.WrappedEncryptionToken = wrappedKey;
 381                sourceToken = wrappedKey;
 382                sourceTokenIdentifierClause = new LocalIdKeyIdentifierClause(wrappedKey.Id, wrappedKey.GetType());
 383                encryptionTokenSerialized = true;
 384            }
 385            else
 386            {
 387                sourceToken = ElementContainer.SourceEncryptionToken;
 388                sourceTokenIdentifierClause = sourceEncryptingKeyIdentifierClause;
 389            }
 390
 391            // determine if a key needs to be derived
 392            SecurityKeyIdentifierClause encryptingKeyIdentifierClause;
 393            // determine if a token needs to be derived
 394            if (_encryptingTokenParameters.RequireDerivedKeys)
 395            {
 396                string derivationAlgorithm = AlgorithmSuite.GetEncryptionKeyDerivationAlgorithm(sourceToken, StandardsMa
 397                string expectedDerivationAlgorithm = SecurityUtils.GetKeyDerivationAlgorithm(StandardsManager.MessageSec
 398                if (derivationAlgorithm == expectedDerivationAlgorithm)
 399                {
 400                    DerivedKeySecurityToken derivedEncryptingToken = new DerivedKeySecurityToken(-1, 0,
 401                        AlgorithmSuite.GetEncryptionKeyDerivationLength(sourceToken, StandardsManager.MessageSecurityVer
 402                    _encryptingToken = ElementContainer.DerivedEncryptionToken = derivedEncryptingToken;
 403                    encryptingKeyIdentifierClause = new LocalIdKeyIdentifierClause(derivedEncryptingToken.Id, derivedEnc
 404                }
 405                else
 406                {
 407                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.Format(SR.Uns
 408                }
 409            }
 410            else
 411            {
 412                _encryptingToken = sourceToken;
 413                encryptingKeyIdentifierClause = sourceTokenIdentifierClause;
 414            }
 415
 416            _skipKeyInfoForEncryption = encryptionTokenSerialized && EncryptedKeyContainsReferenceList && (_encryptingTo
 417            SecurityKeyIdentifier identifier;
 418            if (_skipKeyInfoForEncryption)
 419            {
 420                identifier = null;
 421            }
 422            else
 423            {
 424                identifier = new SecurityKeyIdentifier(encryptingKeyIdentifierClause);
 425            }
 426
 427            StartEncryptionCore(_encryptingToken, identifier);
 428        }
 429
 430        private void CompleteEncryption()
 431        {
 432            ISecurityElement referenceList = CompleteEncryptionCore(
 433                ElementContainer.PrimarySignature,
 434                ElementContainer.GetBasicSupportingTokens(),
 435                ElementContainer.GetSignatureConfirmations(),
 436                ElementContainer.GetEndorsingSignatures());
 437
 438            if (referenceList == null)
 439            {
 440                // null out all the encryption fields since there is no encryption needed
 441                ElementContainer.SourceEncryptionToken = null;
 442                ElementContainer.WrappedEncryptionToken = null;
 443                ElementContainer.DerivedEncryptionToken = null;
 444                return;
 445            }
 446
 447            if (_skipKeyInfoForEncryption)
 448            {
 449                WrappedKeySecurityToken wrappedKeyToken = _encryptingToken as WrappedKeySecurityToken;
 450                wrappedKeyToken.EnsureEncryptedKeySetUp();
 451                wrappedKeyToken.EncryptedKey.ReferenceList = (ReferenceList)referenceList;
 452            }
 453            else
 454            {
 455                ElementContainer.ReferenceList = referenceList;
 456            }
 457            _basicTokenEncrypted = true;
 458        }
 459
 460        internal void StartSecurityApplication()
 461        {
 462            if (SignThenEncrypt)
 463            {
 464                StartSignature();
 465                StartEncryption();
 466            }
 467            else
 468            {
 469                StartEncryption();
 470                StartSignature();
 471            }
 472        }
 473
 474        internal void CompleteSecurityApplication()
 475        {
 476            if (SignThenEncrypt)
 477            {
 478                CompleteSignature();
 479                SignWithSupportingTokens();
 480                CompleteEncryption();
 481            }
 482            else
 483            {
 484                CompleteEncryption();
 485                CompleteSignature();
 486                SignWithSupportingTokens();
 487            }
 488
 489            if (_correlationState != null)
 490            {
 491                _correlationState.SignatureConfirmations = GetSignatureValues();
 492            }
 493        }
 494
 495        public void RemoveSignatureEncryptionIfAppropriate()
 496        {
 497            if (SignThenEncrypt &&
 498                EncryptPrimarySignature &&
 499                (SecurityAppliedMessage.BodyProtectionMode != MessagePartProtectionMode.SignThenEncrypt) &&
 500                (_basicSupportingTokenParameters == null || _basicSupportingTokenParameters.Count == 0) &&
 501                (_signatureConfirmationsToSend == null || _signatureConfirmationsToSend.Count == 0 || !_signatureConfirm
 502                !HasSignedEncryptedMessagePart)
 503            {
 504                _encryptSignature = false;
 505            }
 506        }
 507
 508        public string GenerateId()
 509        {
 510            int id = _idCounter++;
 511
 512            if (_idPrefix != null)
 513            {
 514                return _idPrefix + id;
 515            }
 516
 517            if (id < s_ids.Length)
 518            {
 519                return s_ids[id];
 520            }
 521            else
 522            {
 523                return "_" + id;
 524            }
 525        }
 526
 527        private SignatureConfirmations GetSignatureValues()
 528        {
 529            return _signatureValuesGenerated;
 530        }
 531
 532        protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
 533        {
 534            StandardsManager.SecurityVersion.WriteStartHeader(writer);
 535            WriteHeaderAttributes(writer, messageVersion);
 536        }
 537
 538        internal static bool ShouldSerializeToken(SecurityTokenParameters parameters, MessageDirection transferDirection
 539        {
 540            switch (parameters.InclusionMode)
 541            {
 542                case SecurityTokenInclusionMode.AlwaysToInitiator:
 543                    return (transferDirection == MessageDirection.Output);
 544                case SecurityTokenInclusionMode.Once:
 545                case SecurityTokenInclusionMode.AlwaysToRecipient:
 546                    return (transferDirection == MessageDirection.Input);
 547                case SecurityTokenInclusionMode.Never:
 548                    return false;
 549                default:
 550                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.Format(SR.Uns
 551            }
 552        }
 553
 554        protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
 555        {
 556            if (_basicSupportingTokenParameters != null && _basicSupportingTokenParameters.Count > 0
 557                && RequireMessageProtection && !_basicTokenEncrypted)
 558            {
 559                throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.BasicTokenCannotBeWrittenWithoutEnc
 560            }
 561
 562            if (ElementContainer.Timestamp != null && Layout != SecurityHeaderLayout.LaxTimestampLast)
 563            {
 564                StandardsManager.WSUtilitySpecificationVersion.WriteTimestamp(writer, ElementContainer.Timestamp);
 565            }
 566            if (ElementContainer.PrerequisiteToken != null)
 567            {
 568                StandardsManager.SecurityTokenSerializer.WriteToken(writer, ElementContainer.PrerequisiteToken);
 569            }
 570            if (ElementContainer.SourceSigningToken != null)
 571            {
 572                if (ShouldSerializeToken(SigningTokenParameters, MessageDirection))
 573                {
 574                    StandardsManager.SecurityTokenSerializer.WriteToken(writer, ElementContainer.SourceSigningToken);
 575
 576                    // Implement Protect token
 577                    // NOTE: The spec says sign the primary token if it is not included in the message. But we currently
 578                    // as we do not support STR-Transform for external references. Hence we can not sign the token which
 579                    // This only affects the messages from service to client where
 580                    // 1. allowSerializedSigningTokenOnReply is false.
 581                    // 2. SymmetricSecurityBindingElement with IssuedTokens binding where the issued token has a symmetr
 582
 583                    if (ShouldProtectTokens)
 584                    {
 585                        WriteSecurityTokenReferencyEntry(writer, ElementContainer.SourceSigningToken, SigningTokenParame
 586                    }
 587                }
 588            }
 589            if (ElementContainer.DerivedSigningToken != null)
 590            {
 591                StandardsManager.SecurityTokenSerializer.WriteToken(writer, ElementContainer.DerivedSigningToken);
 592            }
 593            if (ElementContainer.SourceEncryptionToken != null && ElementContainer.SourceEncryptionToken != ElementConta
 594            {
 595                StandardsManager.SecurityTokenSerializer.WriteToken(writer, ElementContainer.SourceEncryptionToken);
 596            }
 597            if (ElementContainer.WrappedEncryptionToken != null)
 598            {
 599                StandardsManager.SecurityTokenSerializer.WriteToken(writer, ElementContainer.WrappedEncryptionToken);
 600            }
 601            if (ElementContainer.DerivedEncryptionToken != null)
 602            {
 603                StandardsManager.SecurityTokenSerializer.WriteToken(writer, ElementContainer.DerivedEncryptionToken);
 604            }
 605            if (SignThenEncrypt)
 606            {
 607                if (ElementContainer.ReferenceList != null)
 608                {
 609                    ElementContainer.ReferenceList.WriteTo(writer, ServiceModelDictionaryManager.Instance);
 610                }
 611            }
 612
 613            SecurityToken[] signedTokens = ElementContainer.GetSignedSupportingTokens();
 614            if (signedTokens != null)
 615            {
 616                for (int i = 0; i < signedTokens.Length; ++i)
 617                {
 618                    StandardsManager.SecurityTokenSerializer.WriteToken(writer, signedTokens[i]);
 619                    WriteSecurityTokenReferencyEntry(writer, signedTokens[i], _signedTokenParameters[i]);
 620                }
 621            }
 622            SendSecurityHeaderElement[] basicTokensXml = ElementContainer.GetBasicSupportingTokens();
 623            if (basicTokensXml != null)
 624            {
 625                for (int i = 0; i < basicTokensXml.Length; ++i)
 626                {
 627                    basicTokensXml[i].Item.WriteTo(writer, ServiceModelDictionaryManager.Instance);
 628                    if (SignThenEncrypt)
 629                    {
 630                        WriteSecurityTokenReferencyEntry(writer, _basicTokens[i], _basicSupportingTokenParameters[i]);
 631                    }
 632                }
 633            }
 634            SecurityToken[] endorsingTokens = ElementContainer.GetEndorsingSupportingTokens();
 635            if (endorsingTokens != null)
 636            {
 637                for (int i = 0; i < endorsingTokens.Length; ++i)
 638                {
 639                    if (ShouldSerializeToken(_endorsingTokenParameters[i], MessageDirection))
 640                    {
 641                        StandardsManager.SecurityTokenSerializer.WriteToken(writer, endorsingTokens[i]);
 642                    }
 643                }
 644            }
 645            SecurityToken[] endorsingDerivedTokens = ElementContainer.GetEndorsingDerivedSupportingTokens();
 646            if (endorsingDerivedTokens != null)
 647            {
 648                for (int i = 0; i < endorsingDerivedTokens.Length; ++i)
 649                {
 650                    StandardsManager.SecurityTokenSerializer.WriteToken(writer, endorsingDerivedTokens[i]);
 651                }
 652            }
 653            SecurityToken[] signedEndorsingTokens = ElementContainer.GetSignedEndorsingSupportingTokens();
 654            if (signedEndorsingTokens != null)
 655            {
 656                for (int i = 0; i < signedEndorsingTokens.Length; ++i)
 657                {
 658                    StandardsManager.SecurityTokenSerializer.WriteToken(writer, signedEndorsingTokens[i]);
 659                    WriteSecurityTokenReferencyEntry(writer, signedEndorsingTokens[i], _signedEndorsingTokenParameters[i
 660                }
 661            }
 662            SecurityToken[] signedEndorsingDerivedTokens = ElementContainer.GetSignedEndorsingDerivedSupportingTokens();
 663            if (signedEndorsingDerivedTokens != null)
 664            {
 665                for (int i = 0; i < signedEndorsingDerivedTokens.Length; ++i)
 666                {
 667                    StandardsManager.SecurityTokenSerializer.WriteToken(writer, signedEndorsingDerivedTokens[i]);
 668                }
 669            }
 670            SendSecurityHeaderElement[] signatureConfirmations = ElementContainer.GetSignatureConfirmations();
 671            if (signatureConfirmations != null)
 672            {
 673                for (int i = 0; i < signatureConfirmations.Length; ++i)
 674                {
 675                    signatureConfirmations[i].Item.WriteTo(writer, ServiceModelDictionaryManager.Instance);
 676                }
 677            }
 678            if (ElementContainer.PrimarySignature != null && ElementContainer.PrimarySignature.Item != null)
 679            {
 680                ElementContainer.PrimarySignature.Item.WriteTo(writer, ServiceModelDictionaryManager.Instance);
 681            }
 682            SendSecurityHeaderElement[] endorsingSignatures = ElementContainer.GetEndorsingSignatures();
 683            if (endorsingSignatures != null)
 684            {
 685                for (int i = 0; i < endorsingSignatures.Length; ++i)
 686                {
 687                    endorsingSignatures[i].Item.WriteTo(writer, ServiceModelDictionaryManager.Instance);
 688                }
 689            }
 690            if (!SignThenEncrypt)
 691            {
 692                if (ElementContainer.ReferenceList != null)
 693                {
 694                    ElementContainer.ReferenceList.WriteTo(writer, ServiceModelDictionaryManager.Instance);
 695                }
 696            }
 697            if (ElementContainer.Timestamp != null && Layout == SecurityHeaderLayout.LaxTimestampLast)
 698            {
 699                StandardsManager.WSUtilitySpecificationVersion.WriteTimestamp(writer, ElementContainer.Timestamp);
 700            }
 701        }
 702
 703        protected abstract void WriteSecurityTokenReferencyEntry(XmlDictionaryWriter writer, SecurityToken securityToken
 704
 705        public Message SetupExecution()
 706        {
 707            ThrowIfProcessingStarted();
 708            SetProcessingStarted();
 709
 710            bool signBody = false;
 711            if (ElementContainer.SourceSigningToken != null)
 712            {
 713                if (_signatureParts == null)
 714                {
 715                    throw TraceUtility.ThrowHelperError(new ArgumentNullException(nameof(SignatureParts)), Message);
 716                }
 717                signBody = _signatureParts.IsBodyIncluded;
 718            }
 719
 720            bool encryptBody = false;
 721            if (ElementContainer.SourceEncryptionToken != null)
 722            {
 723                if (_encryptionParts == null)
 724                {
 725                    throw TraceUtility.ThrowHelperError(new ArgumentNullException(nameof(EncryptionParts)), Message);
 726                }
 727                encryptBody = _encryptionParts.IsBodyIncluded;
 728            }
 729
 730            SecurityAppliedMessage message = new SecurityAppliedMessage(Message, this, signBody, encryptBody);
 731            Message = message;
 732            return message;
 733        }
 734
 735        protected internal SecurityTokenReferenceStyle GetTokenReferenceStyle(SecurityTokenParameters parameters)
 736        {
 737            return (ShouldSerializeToken(parameters, MessageDirection)) ? SecurityTokenReferenceStyle.Internal : Securit
 738        }
 739
 740        private void StartSignature()
 741        {
 742            if (ElementContainer.SourceSigningToken == null)
 743            {
 744                return;
 745            }
 746
 747            // determine the key identifier clause to use for the source
 748            SecurityTokenReferenceStyle sourceSigningKeyReferenceStyle = GetTokenReferenceStyle(SigningTokenParameters);
 749            SecurityKeyIdentifierClause sourceSigningKeyIdentifierClause = SigningTokenParameters.CreateKeyIdentifierCla
 750            if (sourceSigningKeyIdentifierClause == null)
 751            {
 752                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.TokenManagerCannotCreateTokenReferen
 753            }
 754
 755            SecurityToken signingToken;
 756            SecurityKeyIdentifierClause signingKeyIdentifierClause;
 757
 758            // determine if a token needs to be derived
 759            if (SigningTokenParameters.RequireDerivedKeys && !SigningTokenParameters.HasAsymmetricKey)
 760            {
 761                string derivationAlgorithm = AlgorithmSuite.GetSignatureKeyDerivationAlgorithm(ElementContainer.SourceSi
 762                string expectedDerivationAlgorithm = SecurityUtils.GetKeyDerivationAlgorithm(StandardsManager.MessageSec
 763                if (derivationAlgorithm == expectedDerivationAlgorithm)
 764                {
 765                    DerivedKeySecurityToken derivedSigningToken = new DerivedKeySecurityToken(-1, 0, AlgorithmSuite.GetS
 766                        sourceSigningKeyIdentifierClause, derivationAlgorithm, GenerateId());
 767                    signingToken = ElementContainer.DerivedSigningToken = derivedSigningToken;
 768                    signingKeyIdentifierClause = new LocalIdKeyIdentifierClause(signingToken.Id, signingToken.GetType())
 769                }
 770                else
 771                {
 772                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.Format(SR.Uns
 773                }
 774            }
 775            else
 776            {
 777                signingToken = ElementContainer.SourceSigningToken;
 778                signingKeyIdentifierClause = sourceSigningKeyIdentifierClause;
 779            }
 780
 781            SecurityKeyIdentifier signingKeyIdentifier = new SecurityKeyIdentifier(signingKeyIdentifierClause);
 782
 783            if (_signatureConfirmationsToSend != null && _signatureConfirmationsToSend.Count > 0)
 784            {
 785                ISecurityElement[] signatureConfirmationElements;
 786                signatureConfirmationElements = CreateSignatureConfirmationElements(_signatureConfirmationsToSend);
 787                for (int i = 0; i < signatureConfirmationElements.Length; ++i)
 788                {
 789                    SendSecurityHeaderElement sigConfElement = new SendSecurityHeaderElement(signatureConfirmationElemen
 790                    {
 791                        MarkedForEncryption = _signatureConfirmationsToSend.IsMarkedForEncryption
 792                    };
 793                    ElementContainer.AddSignatureConfirmation(sigConfElement);
 794                }
 795            }
 796
 797            bool generateTargettablePrimarySignature = ((_endorsingTokenParameters != null) || (_signedEndorsingTokenPar
 798            StartPrimarySignatureCore(signingToken, signingKeyIdentifier, _signatureParts, generateTargettablePrimarySig
 799        }
 800
 801        private void CompleteSignature()
 802        {
 803            ISignatureValueSecurityElement signedXml = CompletePrimarySignatureCore(
 804                ElementContainer.GetSignatureConfirmations(), ElementContainer.GetSignedEndorsingSupportingTokens(),
 805                ElementContainer.GetSignedSupportingTokens(), ElementContainer.GetBasicSupportingTokens(), true);
 806            if (signedXml == null)
 807            {
 808                return;
 809            }
 810            ElementContainer.PrimarySignature = new SendSecurityHeaderElement(signedXml.Id, signedXml)
 811            {
 812                MarkedForEncryption = _encryptSignature
 813            };
 814            AddGeneratedSignatureValue(signedXml.GetSignatureValue(), EncryptPrimarySignature);
 815            _primarySignatureDone = true;
 816            PrimarySignatureValue = signedXml.GetSignatureValue();
 817        }
 818
 819        protected abstract void StartPrimarySignatureCore(SecurityToken token, SecurityKeyIdentifier identifier, Message
 820
 821        protected abstract ISignatureValueSecurityElement CompletePrimarySignatureCore(SendSecurityHeaderElement[] signa
 822           SecurityToken[] signedEndorsingTokens, SecurityToken[] signedTokens, SendSecurityHeaderElement[] basicTokens,
 823
 824        protected abstract ISignatureValueSecurityElement CreateSupportingSignature(SecurityToken token, SecurityKeyIden
 825
 826        protected abstract ISignatureValueSecurityElement CreateSupportingSignature(SecurityToken token, SecurityKeyIden
 827
 828        protected abstract void StartEncryptionCore(SecurityToken token, SecurityKeyIdentifier keyIdentifier);
 829
 830        protected abstract ISecurityElement CompleteEncryptionCore(SendSecurityHeaderElement primarySignature,
 831            SendSecurityHeaderElement[] basicTokens, SendSecurityHeaderElement[] signatureConfirmations, SendSecurityHea
 832
 833        private void SignWithSupportingToken(SecurityToken token, SecurityKeyIdentifierClause identifierClause)
 834        {
 835            if (token == null)
 836            {
 837                throw TraceUtility.ThrowHelperArgumentNull(nameof(token), Message);
 838            }
 839            if (identifierClause == null)
 840            {
 841                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.TokenManagerCannotCreateTokenReferen
 842            }
 843            if (!RequireMessageProtection)
 844            {
 845                if (ElementContainer.Timestamp == null)
 846                {
 847                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(
 848                        SR.SigningWithoutPrimarySignatureRequiresTimestamp), Message);
 849                }
 850            }
 851            else
 852            {
 853                if (!_primarySignatureDone)
 854                {
 855                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(
 856                        SR.PrimarySignatureMustBeComputedBeforeSupportingTokenSignatures), Message);
 857                }
 858                if (ElementContainer.PrimarySignature.Item == null)
 859                {
 860                    throw TraceUtility.ThrowHelperError(new InvalidOperationException(
 861                        SR.Format(SR.SupportingTokenSignaturesNotExpected)), Message);
 862                }
 863            }
 864
 865            SecurityKeyIdentifier identifier = new SecurityKeyIdentifier(identifierClause);
 866            ISignatureValueSecurityElement supportingSignature;
 867            if (!RequireMessageProtection)
 868            {
 869                supportingSignature = CreateSupportingSignature(token, identifier);
 870            }
 871            else
 872            {
 873                supportingSignature = CreateSupportingSignature(token, identifier, ElementContainer.PrimarySignature.Ite
 874            }
 875            AddGeneratedSignatureValue(supportingSignature.GetSignatureValue(), _encryptSignature);
 876            SendSecurityHeaderElement supportingSignatureElement = new SendSecurityHeaderElement(supportingSignature.Id,
 877            {
 878                MarkedForEncryption = _encryptSignature
 879            };
 880            ElementContainer.AddEndorsingSignature(supportingSignatureElement);
 881        }
 882
 883        private void SignWithSupportingTokens()
 884        {
 885            SecurityToken[] endorsingTokens = ElementContainer.GetEndorsingSupportingTokens();
 886            if (endorsingTokens != null)
 887            {
 888                for (int i = 0; i < endorsingTokens.Length; ++i)
 889                {
 890                    SecurityToken source = endorsingTokens[i];
 891                    SecurityKeyIdentifierClause sourceKeyClause = _endorsingTokenParameters[i].CreateKeyIdentifierClause
 892                    if (sourceKeyClause == null)
 893                    {
 894                        throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.TokenManagerCannot
 895                    }
 896                    SecurityToken signingToken;
 897                    SecurityKeyIdentifierClause signingKeyClause;
 898                    if (_endorsingTokenParameters[i].RequireDerivedKeys && !_endorsingTokenParameters[i].HasAsymmetricKe
 899                    {
 900                        string derivationAlgorithm = SecurityUtils.GetKeyDerivationAlgorithm(StandardsManager.MessageSec
 901                        DerivedKeySecurityToken dkt = new DerivedKeySecurityToken(-1, 0,
 902                            AlgorithmSuite.GetSignatureKeyDerivationLength(source, StandardsManager.MessageSecurityVersi
 903                            DerivedKeySecurityToken.DefaultNonceLength, source, sourceKeyClause, derivationAlgorithm, Ge
 904                        signingToken = dkt;
 905                        signingKeyClause = new LocalIdKeyIdentifierClause(dkt.Id, dkt.GetType());
 906                        ElementContainer.AddEndorsingDerivedSupportingToken(dkt);
 907                    }
 908                    else
 909                    {
 910                        signingToken = source;
 911                        signingKeyClause = sourceKeyClause;
 912                    }
 913                    SignWithSupportingToken(signingToken, signingKeyClause);
 914                }
 915            }
 916            SecurityToken[] signedEndorsingSupportingTokens = ElementContainer.GetSignedEndorsingSupportingTokens();
 917            if (signedEndorsingSupportingTokens != null)
 918            {
 919                for (int i = 0; i < signedEndorsingSupportingTokens.Length; ++i)
 920                {
 921                    SecurityToken source = signedEndorsingSupportingTokens[i];
 922                    SecurityKeyIdentifierClause sourceKeyClause = _signedEndorsingTokenParameters[i].CreateKeyIdentifier
 923                    if (sourceKeyClause == null)
 924                    {
 925                        throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.TokenManagerCannot
 926                    }
 927                    SecurityToken signingToken;
 928                    SecurityKeyIdentifierClause signingKeyClause;
 929                    if (_signedEndorsingTokenParameters[i].RequireDerivedKeys && !_signedEndorsingTokenParameters[i].Has
 930                    {
 931                        string derivationAlgorithm = SecurityUtils.GetKeyDerivationAlgorithm(StandardsManager.MessageSec
 932                        DerivedKeySecurityToken dkt = new DerivedKeySecurityToken(-1, 0,
 933                            AlgorithmSuite.GetSignatureKeyDerivationLength(source, StandardsManager.MessageSecurityVersi
 934                            DerivedKeySecurityToken.DefaultNonceLength, source, sourceKeyClause, derivationAlgorithm, Ge
 935                        signingToken = dkt;
 936                        signingKeyClause = new LocalIdKeyIdentifierClause(dkt.Id, dkt.GetType());
 937                        ElementContainer.AddSignedEndorsingDerivedSupportingToken(dkt);
 938                    }
 939                    else
 940                    {
 941                        signingToken = source;
 942                        signingKeyClause = sourceKeyClause;
 943                    }
 944                    SignWithSupportingToken(signingToken, signingKeyClause);
 945                }
 946            }
 947        }
 948
 949        protected bool ShouldUseStrTransformForToken(SecurityToken securityToken, int position, SecurityTokenAttachmentM
 950        {
 951            keyIdentifierClause = null;
 952
 953            IssuedSecurityTokenParameters tokenParams;
 954            switch (mode)
 955            {
 956                case SecurityTokenAttachmentMode.SignedEndorsing:
 957                    tokenParams = _signedEndorsingTokenParameters[position] as IssuedSecurityTokenParameters;
 958                    break;
 959                case SecurityTokenAttachmentMode.Signed:
 960                    tokenParams = _signedTokenParameters[position] as IssuedSecurityTokenParameters;
 961                    break;
 962                case SecurityTokenAttachmentMode.SignedEncrypted:
 963                    tokenParams = _basicSupportingTokenParameters[position] as IssuedSecurityTokenParameters;
 964                    break;
 965                default:
 966                    return false;
 967            }
 968
 969            if (tokenParams != null && tokenParams.UseStrTransform)
 970            {
 971                keyIdentifierClause = tokenParams.CreateKeyIdentifierClause(securityToken, GetTokenReferenceStyle(tokenP
 972                if (keyIdentifierClause == null)
 973                {
 974                    throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.Format(SR.TokenManagerCannotCrea
 975                }
 976
 977                return true;
 978            }
 979            return false;
 980        }
 981
 982        XmlDictionaryString IMessageHeaderWithSharedNamespace.SharedNamespace => XD.UtilityDictionary.Namespace;
 983
 984        XmlDictionaryString IMessageHeaderWithSharedNamespace.SharedPrefix => XD.UtilityDictionary.Prefix;
 985
 986        private void AddGeneratedSignatureValue(byte[] signatureValue, bool wasEncrypted)
 987        {
 988            // cache outgoing signatures only on the client side
 989            if (MaintainSignatureConfirmationState && (_signatureConfirmationsToSend == null))
 990            {
 991                if (_signatureValuesGenerated == null)
 992                {
 993                    _signatureValuesGenerated = new SignatureConfirmations();
 994                }
 995                _signatureValuesGenerated.AddConfirmation(signatureValue, wasEncrypted);
 996            }
 997        }
 998    }
 999
 1000    internal class TokenElement : ISecurityElement
 1001    {
 1002        private readonly SecurityStandardsManager _standardsManager;
 1003
 01004        public TokenElement(SecurityToken token, SecurityStandardsManager standardsManager)
 1005        {
 01006            Token = token;
 01007            _standardsManager = standardsManager;
 01008        }
 1009
 1010        public override bool Equals(object item)
 1011        {
 01012            return (item is TokenElement element && Token == element.Token && _standardsManager == element._standardsMan
 1013        }
 1014
 1015        public override int GetHashCode()
 1016        {
 01017            return Token.GetHashCode() ^ _standardsManager.GetHashCode();
 1018        }
 1019
 01020        public bool HasId => true;
 1021
 01022        public string Id => Token.Id;
 1023
 01024        public SecurityToken Token { get; }
 1025
 1026        public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
 1027        {
 01028            _standardsManager.SecurityTokenSerializer.WriteToken(writer, Token);
 01029        }
 1030    }
 1031}