< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.WrappedXmlDictionaryWriter
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/WSSecurityOneDotZeroSendSecurityHeader.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 66
Coverable lines: 66
Total lines: 1011
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 16
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%
WriteStartAttribute(...)0%660%
WriteStartElement(...)0%10100%
Close()100%110%
Flush()100%110%
LookupPrefix(...)100%110%
WriteBase64(...)100%110%
WriteCData(...)100%110%
WriteCharEntity(...)100%110%
WriteChars(...)100%110%
WriteComment(...)100%110%
WriteDocType(...)100%110%
WriteEndAttribute()100%110%
WriteEndDocument()100%110%
WriteEndElement()100%110%
WriteEntityRef(...)100%110%
WriteFullEndElement()100%110%
WriteProcessingInstruction(...)100%110%
WriteRaw(...)100%110%
WriteRaw(...)100%110%
WriteStartDocument(...)100%110%
WriteStartDocument()100%110%
WriteString(...)100%110%
WriteSurrogateCharEntity(...)100%110%
WriteWhitespace(...)100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/WSSecurityOneDotZeroSendSecurityHeader.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.IO;
 6using System.Security.Cryptography;
 7using System.Security.Cryptography.Xml;
 8using System.Text;
 9using System.Threading.Tasks;
 10using System.Xml;
 11using CoreWCF.Channels;
 12using CoreWCF.Description;
 13using CoreWCF.Diagnostics;
 14using CoreWCF.IdentityModel;
 15using CoreWCF.IdentityModel.Tokens;
 16using CoreWCF.Runtime;
 17using CoreWCF.Security.Tokens;
 18using IPrefixGenerator = CoreWCF.IdentityModel.IPrefixGenerator;
 19using ISecurityElement = CoreWCF.IdentityModel.ISecurityElement;
 20using ISignatureValueSecurityElement = CoreWCF.IdentityModel.ISignatureValueSecurityElement;
 21using KeyInfo = System.Security.Cryptography.Xml.KeyInfo;
 22
 23namespace CoreWCF.Security
 24{
 25    internal class WSSecurityOneDotZeroSendSecurityHeader : SendSecurityHeader
 26    {
 27        private HashStream _hashStream;
 28        private SignedXml _signedXml;
 29        private KeyedHashAlgorithm _signingKey;
 30        private MessagePartSpecification _effectiveSignatureParts;
 31
 32        // For Transport Security we have to sign the 'To' header with the
 33        // supporting tokens.
 34        private Stream _toHeaderStream = null;
 35        private string _toHeaderId = null;
 36
 37        public WSSecurityOneDotZeroSendSecurityHeader(Message message, string actor, bool mustUnderstand, bool relay,
 38            SecurityStandardsManager standardsManager,
 39            SecurityAlgorithmSuite algorithmSuite,
 40            MessageDirection direction)
 41            : base(message, actor, mustUnderstand, relay, standardsManager, algorithmSuite, direction)
 42        {
 43        }
 44
 45        protected string EncryptionAlgorithm
 46        {
 47            get { return AlgorithmSuite.DefaultEncryptionAlgorithm; }
 48        }
 49
 50        protected XmlDictionaryString EncryptionAlgorithmDictionaryString
 51        {
 52            get { return AlgorithmSuite.DefaultEncryptionAlgorithmDictionaryString; }
 53        }
 54
 55        private void AddEncryptionReference(MessageHeader header, string headerId, IPrefixGenerator prefixGenerator, boo
 56            out MemoryStream plainTextStream, out string encryptedDataId)
 57        {
 58            throw new PlatformNotSupportedException();
 59        }
 60
 61        private void AddSignatureReference(SecurityToken token, int position, SecurityTokenAttachmentMode mode)
 62        {
 63            bool strTransformEnabled = ShouldUseStrTransformForToken(token, position, mode, out SecurityKeyIdentifierCla
 64            AddTokenSignatureReference(token, keyIdentifierClause, strTransformEnabled);
 65        }
 66
 67        private void AddPrimaryTokenSignatureReference(SecurityToken token, SecurityTokenParameters securityTokenParamet
 68        {
 69            return;
 70        }
 71
 72        // Given a token and useStarTransform value this method adds apporopriate reference accordingly.
 73        // 1. If strTransform is disabled, it adds a reference to the token's id.
 74        // 2. Else if strtransform is enabled it adds a reference the security token's keyIdentifier's id.
 75        private void AddTokenSignatureReference(SecurityToken token, SecurityKeyIdentifierClause keyIdentifierClause, bo
 76        {
 77            if (strTransformEnabled)
 78            {
 79                throw new PlatformNotSupportedException();
 80            }
 81        }
 82
 83        private void AddSignatureReference(SendSecurityHeaderElement[] elements)
 84        {
 85            if (elements != null)
 86            {
 87                for (int i = 0; i < elements.Length; ++i)
 88                {
 89                    // signedEncryptedTokenElement can either be a TokenElement ( in SignThenEncrypt case) or EncryptedD
 90                    // STR-Transform does not make sense in !SignThenEncrypt case .
 91                    // note: signedEncryptedTokenElement can also be SignatureConfirmation but we do not care about it h
 92                    bool useStrTransform = elements[i].Item is TokenElement signedEncryptedTokenElement
 93                                           && SignThenEncrypt
 94                                           && ShouldUseStrTransformForToken(signedEncryptedTokenElement.Token,
 95                                                                                 i,
 96                                                                                 SecurityTokenAttachmentMode.SignedEncry
 97                                                                                 out SecurityKeyIdentifierClause keyIden
 98
 99                    if (!useStrTransform && elements[i].Id == null)
 100                    {
 101                        throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.ElementToSignMustHaveId), Me
 102                    }
 103
 104                    MemoryStream stream = new MemoryStream();
 105                    XmlDictionaryWriter utf8Writer = TakeUtf8Writer();
 106                    utf8Writer.StartCanonicalization(stream, false, null);
 107                    elements[i].Item.WriteTo(utf8Writer, ServiceModelDictionaryManager.Instance);
 108                    utf8Writer.EndCanonicalization();
 109                    stream.Position = 0;
 110                    if (useStrTransform)
 111                    {
 112                        throw new PlatformNotSupportedException("StrTransform not supported yet");
 113                    }
 114                    else
 115                    {
 116                        AddReference("#" + elements[i].Id, stream);
 117                    }
 118                }
 119            }
 120        }
 121
 122        private string GetSignatureHash(MessageHeader header, string headerId, IPrefixGenerator prefixGenerator, XmlDict
 123        {
 124            HashStream hashStream = TakeHashStream();
 125            XmlDictionaryWriter effectiveWriter;
 126            XmlBuffer canonicalBuffer = null;
 127
 128            if (writer.CanCanonicalize)
 129            {
 130                effectiveWriter = writer;
 131            }
 132            else
 133            {
 134                canonicalBuffer = new XmlBuffer(int.MaxValue);
 135                effectiveWriter = canonicalBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 136            }
 137
 138            effectiveWriter.StartCanonicalization(hashStream, false, null);
 139
 140            header.WriteStartHeader(effectiveWriter, Version);
 141            if (headerId == null)
 142            {
 143                headerId = GenerateId();
 144                StandardsManager.IdManager.WriteIdAttribute(effectiveWriter, headerId);
 145            }
 146            header.WriteHeaderContents(effectiveWriter, Version);
 147            effectiveWriter.WriteEndElement();
 148            effectiveWriter.EndCanonicalization();
 149            effectiveWriter.Flush();
 150
 151            if (!ReferenceEquals(effectiveWriter, writer))
 152            {
 153                Fx.Assert(canonicalBuffer != null, "Canonical buffer cannot be null.");
 154                canonicalBuffer.CloseSection();
 155                canonicalBuffer.Close();
 156                XmlDictionaryReader dicReader = canonicalBuffer.GetReader(0);
 157                writer.WriteNode(dicReader, false);
 158                dicReader.Close();
 159            }
 160
 161            hash = hashStream.FlushHashAndGetValue();
 162
 163            return headerId;
 164        }
 165
 166        private async ValueTask<(string, byte[])> GetSignatureHashAsync(MessageHeader header, string headerId, IPrefixGe
 167        {
 168            HashStream hashStream = TakeHashStream();
 169            XmlDictionaryWriter effectiveWriter;
 170            XmlBuffer canonicalBuffer = null;
 171
 172            if (writer.CanCanonicalize)
 173            {
 174                effectiveWriter = writer;
 175            }
 176            else
 177            {
 178                canonicalBuffer = new XmlBuffer(int.MaxValue);
 179                effectiveWriter = canonicalBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 180            }
 181
 182            effectiveWriter.StartCanonicalization(hashStream, false, null);
 183
 184            header.WriteStartHeader(effectiveWriter, Version);
 185            if (headerId == null)
 186            {
 187                headerId = GenerateId();
 188                StandardsManager.IdManager.WriteIdAttribute(effectiveWriter, headerId);
 189            }
 190            header.WriteHeaderContents(effectiveWriter, Version);
 191            await effectiveWriter.WriteEndElementAsync();
 192            effectiveWriter.EndCanonicalization();
 193            await effectiveWriter.FlushAsync();
 194
 195            if (!ReferenceEquals(effectiveWriter, writer))
 196            {
 197                Fx.Assert(canonicalBuffer != null, "Canonical buffer cannot be null.");
 198                canonicalBuffer.CloseSection();
 199                canonicalBuffer.Close();
 200                XmlDictionaryReader dicReader = canonicalBuffer.GetReader(0);
 201                await writer.WriteNodeAsync(dicReader, false);
 202                dicReader.Close();
 203            }
 204
 205            var hash = hashStream.FlushHashAndGetValue();
 206
 207            return (headerId, hash);
 208        }
 209
 210        private string GetSignatureStream(MessageHeader header, string headerId, IPrefixGenerator prefixGenerator, XmlDi
 211        {
 212            stream = new MemoryStream();
 213            XmlDictionaryWriter effectiveWriter;
 214            XmlBuffer canonicalBuffer = null;
 215
 216            if (writer.CanCanonicalize)
 217            {
 218                effectiveWriter = writer;
 219            }
 220            else
 221            {
 222                canonicalBuffer = new XmlBuffer(int.MaxValue);
 223                effectiveWriter = canonicalBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 224            }
 225
 226            effectiveWriter.StartCanonicalization(stream, false, null);
 227
 228            header.WriteStartHeader(effectiveWriter, Version);
 229            if (headerId == null)
 230            {
 231                headerId = GenerateId();
 232                StandardsManager.IdManager.WriteIdAttribute(effectiveWriter, headerId);
 233            }
 234            header.WriteHeaderContents(effectiveWriter, Version);
 235            effectiveWriter.WriteEndElement();
 236            effectiveWriter.EndCanonicalization();
 237            effectiveWriter.Flush();
 238
 239            if (!ReferenceEquals(effectiveWriter, writer))
 240            {
 241                Fx.Assert(canonicalBuffer != null, "Canonical buffer cannot be null.");
 242                canonicalBuffer.CloseSection();
 243                canonicalBuffer.Close();
 244                XmlDictionaryReader dicReader = canonicalBuffer.GetReader(0);
 245                writer.WriteNode(dicReader, false);
 246                dicReader.Close();
 247            }
 248
 249            stream.Position = 0;
 250
 251            return headerId;
 252        }
 253
 254        private async ValueTask<(string, Stream)> GetSignatureStreamAsync(MessageHeader header, string headerId, IPrefix
 255        {
 256            Stream stream = new MemoryStream();
 257            XmlDictionaryWriter effectiveWriter;
 258            XmlBuffer canonicalBuffer = null;
 259
 260            if (writer.CanCanonicalize)
 261            {
 262                effectiveWriter = writer;
 263            }
 264            else
 265            {
 266                canonicalBuffer = new XmlBuffer(int.MaxValue);
 267                effectiveWriter = canonicalBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
 268            }
 269
 270            effectiveWriter.StartCanonicalization(stream, false, null);
 271
 272            header.WriteStartHeader(effectiveWriter, Version);
 273            if (headerId == null)
 274            {
 275                headerId = GenerateId();
 276                StandardsManager.IdManager.WriteIdAttribute(effectiveWriter, headerId);
 277            }
 278            header.WriteHeaderContents(effectiveWriter, Version);
 279            await effectiveWriter.WriteEndElementAsync();
 280            effectiveWriter.EndCanonicalization();
 281            await effectiveWriter.FlushAsync();
 282
 283            if (!ReferenceEquals(effectiveWriter, writer))
 284            {
 285                Fx.Assert(canonicalBuffer != null, "Canonical buffer cannot be null.");
 286                canonicalBuffer.CloseSection();
 287                canonicalBuffer.Close();
 288                XmlDictionaryReader dicReader = canonicalBuffer.GetReader(0);
 289                await writer.WriteNodeAsync(dicReader, false);
 290                dicReader.Close();
 291            }
 292
 293            stream.Position = 0;
 294
 295            return (headerId, stream);
 296        }
 297
 298        private void AddReference(string id, Stream contents)
 299        {
 300            var reference = new System.Security.Cryptography.Xml.Reference(contents)
 301            {
 302                Uri = id,
 303                DigestMethod = AlgorithmSuite.DefaultDigestAlgorithm
 304            };
 305            reference.AddTransform(new XmlDsigExcC14NTransform());
 306            _signedXml.AddReference(reference);
 307        }
 308
 309        private void AddSignatureReference(MessageHeader header, string headerId, IPrefixGenerator prefixGenerator, XmlD
 310        {
 311            // No transforms added to Reference as the digest value has already been calculated
 312            headerId = GetSignatureHash(header, headerId, prefixGenerator, writer, out byte[] hashValue);
 313            var reference = new Reference
 314            {
 315                DigestMethod = AlgorithmSuite.DefaultDigestAlgorithm,
 316                DigestValue = hashValue,
 317                Id = headerId
 318            };
 319            _signedXml.AddReference(reference);
 320        }
 321
 322        private async ValueTask AddSignatureReferenceAsync(MessageHeader header, string headerId, IPrefixGenerator prefi
 323        {
 324            // No transforms added to Reference as the digest value has already been calculated
 325            var (generatedHeaderId, hashValue) = await GetSignatureHashAsync(header, headerId, prefixGenerator, writer);
 326            headerId = generatedHeaderId;
 327
 328            var reference = new Reference
 329            {
 330                DigestMethod = AlgorithmSuite.DefaultDigestAlgorithm,
 331                DigestValue = hashValue,
 332                Id = headerId
 333            };
 334            _signedXml.AddReference(reference);
 335        }
 336
 337        private void ApplySecurityAndWriteHeader(MessageHeader header, string headerId, XmlDictionaryWriter writer, IPre
 338        {
 339            if (!RequireMessageProtection && ShouldSignToHeader)
 340            {
 341                if ((header.Name == XD.AddressingDictionary.To.Value) &&
 342                    (header.Namespace == Message.Version.Addressing.Namespace))
 343                {
 344                    if (_toHeaderStream == null)
 345                    {
 346                        headerId = GetSignatureStream(header, headerId, prefixGenerator, writer, out Stream headerStream
 347                        _toHeaderStream = headerStream;
 348                        _toHeaderId = headerId;
 349                    }
 350                    else
 351                    {
 352                        // More than one 'To' header is specified in the message.
 353                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.Transp
 354                    }
 355
 356                    return;
 357                }
 358            }
 359
 360            MessagePartProtectionMode protectionMode = GetProtectionMode(header);
 361            switch (protectionMode)
 362            {
 363                case MessagePartProtectionMode.None:
 364                    header.WriteHeader(writer, Version);
 365                    return;
 366                case MessagePartProtectionMode.Sign:
 367                    AddSignatureReference(header, headerId, prefixGenerator, writer);
 368                    return;
 369                case MessagePartProtectionMode.SignThenEncrypt:
 370                case MessagePartProtectionMode.Encrypt:
 371                case MessagePartProtectionMode.EncryptThenSign:
 372                    throw new PlatformNotSupportedException();
 373                default:
 374                    Fx.Assert("Invalid MessagePartProtectionMode");
 375                    return;
 376            }
 377        }
 378
 379        private async ValueTask ApplySecurityAndWriteHeaderAsync(MessageHeader header, string headerId, XmlDictionaryWri
 380        {
 381            if (!RequireMessageProtection && ShouldSignToHeader)
 382            {
 383                if ((header.Name == XD.AddressingDictionary.To.Value) &&
 384                    (header.Namespace == Message.Version.Addressing.Namespace))
 385                {
 386                    if (_toHeaderStream == null)
 387                    {
 388                        var (generatedHeaderId, stream) = await GetSignatureStreamAsync(header, headerId, prefixGenerato
 389                        headerId = generatedHeaderId;
 390
 391                        _toHeaderStream = stream;
 392                        _toHeaderId = headerId;
 393                    }
 394                    else
 395                    {
 396                        // More than one 'To' header is specified in the message.
 397                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.Transp
 398                    }
 399
 400                    return;
 401                }
 402            }
 403
 404            MessagePartProtectionMode protectionMode = GetProtectionMode(header);
 405            switch (protectionMode)
 406            {
 407                case MessagePartProtectionMode.None:
 408                    header.WriteHeader(writer, Version);
 409                    return;
 410                case MessagePartProtectionMode.Sign:
 411                    await AddSignatureReferenceAsync(header, headerId, prefixGenerator, writer);
 412                    return;
 413                case MessagePartProtectionMode.SignThenEncrypt:
 414                case MessagePartProtectionMode.Encrypt:
 415                case MessagePartProtectionMode.EncryptThenSign:
 416                    throw new PlatformNotSupportedException();
 417                default:
 418                    Fx.Assert("Invalid MessagePartProtectionMode");
 419                    return;
 420            }
 421        }
 422
 423        public override void ApplySecurityAndWriteHeaders(MessageHeaders headers, XmlDictionaryWriter writer, IPrefixGen
 424        {
 425            string[] headerIds;
 426            if (RequireMessageProtection || ShouldSignToHeader)
 427            {
 428                headerIds = headers.GetHeaderAttributes(UtilityStrings.IdAttribute,
 429                    StandardsManager.IdManager.DefaultIdNamespaceUri);
 430            }
 431            else
 432            {
 433                headerIds = null;
 434            }
 435            for (int i = 0; i < headers.Count; i++)
 436            {
 437                MessageHeader header = headers.GetMessageHeader(i);
 438                if (Version.Addressing == AddressingVersion.None && header.Namespace == AddressingVersion.None.Namespace
 439                {
 440                    continue;
 441                }
 442
 443                if (header != this)
 444                {
 445                    ApplySecurityAndWriteHeader(header, headerIds?[i], writer, prefixGenerator);
 446                }
 447            }
 448        }
 449
 450        public override async ValueTask ApplySecurityAndWriteHeadersAsync(MessageHeaders headers, XmlDictionaryWriter wr
 451        {
 452            string[] headerIds;
 453            if (RequireMessageProtection || ShouldSignToHeader)
 454            {
 455                headerIds = headers.GetHeaderAttributes(UtilityStrings.IdAttribute,
 456                    StandardsManager.IdManager.DefaultIdNamespaceUri);
 457            }
 458            else
 459            {
 460                headerIds = null;
 461            }
 462            for (int i = 0; i < headers.Count; i++)
 463            {
 464                MessageHeader header = headers.GetMessageHeader(i);
 465                if (Version.Addressing == AddressingVersion.None && header.Namespace == AddressingVersion.None.Namespace
 466                {
 467                    continue;
 468                }
 469
 470                if (header != this)
 471                {
 472                    await ApplySecurityAndWriteHeaderAsync(header, headerIds?[i], writer, prefixGenerator);
 473                }
 474            }
 475        }
 476
 477        private static bool CanCanonicalizeAndFragment(XmlDictionaryWriter writer)
 478        {
 479            if (!writer.CanCanonicalize)
 480            {
 481                return false;
 482            }
 483            return writer is IFragmentCapableXmlDictionaryWriter fragmentingWriter && fragmentingWriter.CanFragment;
 484        }
 485
 486        public override void ApplyBodySecurity(XmlDictionaryWriter writer, IPrefixGenerator prefixGenerator)
 487        {
 488            SecurityAppliedMessage message = SecurityAppliedMessage;
 489            switch (message.BodyProtectionMode)
 490            {
 491                case MessagePartProtectionMode.None:
 492                    return;
 493                case MessagePartProtectionMode.Sign:
 494                    var ms = new MemoryStream();
 495                    if (CanCanonicalizeAndFragment(writer))
 496                    {
 497                        message.WriteBodyToSignWithFragments(ms, false, null, writer);
 498                    }
 499                    else
 500                    {
 501                        message.WriteBodyToSign(ms);
 502                    }
 503
 504                    ms.Position = 0;
 505                    AddReference("#" + message.BodyId, ms);
 506                    return;
 507                case MessagePartProtectionMode.SignThenEncrypt:
 508                    throw new PlatformNotSupportedException();
 509                case MessagePartProtectionMode.Encrypt:
 510                    throw new PlatformNotSupportedException();
 511                case MessagePartProtectionMode.EncryptThenSign:
 512                    throw new PlatformNotSupportedException();
 513                default:
 514                    Fx.Assert("Invalid MessagePartProtectionMode");
 515                    return;
 516            }
 517        }
 518
 519        public override async ValueTask ApplyBodySecurityAsync(XmlDictionaryWriter writer, IPrefixGenerator prefixGenera
 520        {
 521            SecurityAppliedMessage message = SecurityAppliedMessage;
 522            switch (message.BodyProtectionMode)
 523            {
 524                case MessagePartProtectionMode.None:
 525                    return;
 526                case MessagePartProtectionMode.Sign:
 527                    var ms = new MemoryStream();
 528                    if (CanCanonicalizeAndFragment(writer))
 529                    {
 530                        await message.WriteBodyToSignWithFragmentsAsync(ms, false, null, writer);
 531                    }
 532                    else
 533                    {
 534                        await message.WriteBodyToSignAsync(ms);
 535                    }
 536
 537                    ms.Position = 0;
 538                    AddReference("#" + message.BodyId, ms);
 539                    return;
 540                case MessagePartProtectionMode.SignThenEncrypt:
 541                    throw new PlatformNotSupportedException();
 542                case MessagePartProtectionMode.Encrypt:
 543                    throw new PlatformNotSupportedException();
 544                case MessagePartProtectionMode.EncryptThenSign:
 545                    throw new PlatformNotSupportedException();
 546                default:
 547                    Fx.Assert("Invalid MessagePartProtectionMode");
 548                    return;
 549            }
 550        }
 551
 552        protected override ISignatureValueSecurityElement CompletePrimarySignatureCore(
 553            SendSecurityHeaderElement[] signatureConfirmations,
 554            SecurityToken[] signedEndorsingTokens,
 555            SecurityToken[] signedTokens,
 556            SendSecurityHeaderElement[] basicTokens, bool isPrimarySignature)
 557        {
 558            if (_signedXml == null)
 559            {
 560                return null;
 561            }
 562
 563            SecurityTimestamp timestamp = Timestamp;
 564            if (timestamp != null)
 565            {
 566                if (timestamp.Id == null)
 567                {
 568                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Timestamp
 569                }
 570
 571                byte[] buffer = new byte[64];
 572                var ms = new MemoryStream();
 573                StandardsManager.WSUtilitySpecificationVersion.WriteTimestampCanonicalForm(
 574                    ms, timestamp, buffer);
 575                ms.Position = 0;
 576                AddReference("#" + timestamp.Id, ms);
 577                var reference = new System.Security.Cryptography.Xml.Reference(ms);
 578            }
 579
 580            if ((ShouldSignToHeader) && (_signingKey != null || _signedXml.SigningKey != null) && (Version.Addressing !=
 581            {
 582                if (_toHeaderStream != null)
 583                {
 584                    AddReference("#" + _toHeaderId, _toHeaderStream);
 585                }
 586                else
 587                {
 588                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Transport
 589                }
 590            }
 591
 592            AddSignatureReference(signatureConfirmations);
 593            if (isPrimarySignature && ShouldProtectTokens)
 594            {
 595                AddPrimaryTokenSignatureReference(ElementContainer.SourceSigningToken, SigningTokenParameters);
 596            }
 597
 598            if (RequireMessageProtection)
 599            {
 600                throw new PlatformNotSupportedException(nameof(RequireMessageProtection));
 601            }
 602
 603            if (_signedXml.SignedInfo.References.Count == 0)
 604            {
 605                throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.NoPartsOfMessageMatchedPartsToSign),
 606            }
 607            try
 608            {
 609                if (_signingKey != null)
 610                {
 611                    _signedXml.ComputeSignature(_signingKey);
 612                }
 613                else
 614                {
 615                    _signedXml.ComputeSignature();
 616                }
 617
 618                return new SignatureValue(_signedXml.Signature);
 619            }
 620            finally
 621            {
 622                _hashStream = null;
 623                _signingKey = null;
 624                _signedXml = null;
 625                _effectiveSignatureParts = null;
 626            }
 627        }
 628
 629        internal class SignatureValue : ISignatureValueSecurityElement
 630        {
 631            private readonly Signature _signature;
 632
 633            public SignatureValue(Signature signature)
 634            {
 635                _signature = signature;
 636            }
 637
 638            public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
 639            {
 640                _signature.GetXml().WriteTo(writer);
 641            }
 642
 643            public bool HasId
 644            {
 645                get { return true; }
 646            }
 647
 648            public string Id
 649            {
 650                get { return _signature.Id; }
 651            }
 652
 653            public byte[] GetSignatureValue()
 654            {
 655                return _signature.SignatureValue;
 656            }
 657        }
 658
 659        private HashStream TakeHashStream()
 660        {
 661            HashStream hashStream;
 662            if (_hashStream == null)
 663            {
 664                _hashStream = hashStream = new HashStream(CryptoHelper.CreateHashAlgorithm(AlgorithmSuite.DefaultDigestA
 665            }
 666            else
 667            {
 668                hashStream = _hashStream;
 669                ;
 670                hashStream.Reset();
 671            }
 672            return hashStream;
 673        }
 674
 675        private XmlDictionaryWriter TakeUtf8Writer()
 676        {
 677            throw new PlatformNotSupportedException();
 678        }
 679
 680        private MessagePartProtectionMode GetProtectionMode(MessageHeader header)
 681        {
 682            if (!RequireMessageProtection)
 683            {
 684                return MessagePartProtectionMode.None;
 685            }
 686            bool sign = _signedXml != null && _effectiveSignatureParts.IsHeaderIncluded(header);
 687            bool encrypt = false;
 688            return MessagePartProtectionModeHelper.GetProtectionMode(sign, encrypt, SignThenEncrypt);
 689        }
 690
 691        protected override void StartPrimarySignatureCore(SecurityToken token,
 692            SecurityKeyIdentifier keyIdentifier,
 693            MessagePartSpecification signatureParts,
 694            bool generateTargettableSignature)
 695        {
 696            SecurityAlgorithmSuite suite = AlgorithmSuite;
 697            string canonicalizationAlgorithm = suite.DefaultCanonicalizationAlgorithm;
 698            if (canonicalizationAlgorithm != SecurityAlgorithms.ExclusiveC14n)
 699            {
 700                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 701                    new MessageSecurityException(SR.Format(SR.UnsupportedCanonicalizationAlgorithm, suite.DefaultCanonic
 702            }
 703            suite.GetSignatureAlgorithmAndKey(token, out string signatureAlgorithm, out SecurityKey signatureKey, out Xm
 704            GetSigningAlgorithm(signatureKey, signatureAlgorithm, out _signingKey, out AsymmetricAlgorithm asymmetricAlg
 705
 706            _signedXml = new SignedXml();
 707            _signedXml.SignedInfo.CanonicalizationMethod = canonicalizationAlgorithm;
 708            _signedXml.SignedInfo.SignatureMethod = signatureAlgorithm;
 709            _signedXml.SigningKey = asymmetricAlgorithm;
 710            if (keyIdentifier != null)
 711            {
 712                var stream = new MemoryStream();
 713                using (var xmlWriter = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false))
 714                {
 715                    StandardsManager.SecurityTokenSerializer.WriteKeyIdentifier(xmlWriter, keyIdentifier);
 716                }
 717
 718                stream.Position = 0;
 719                XmlDocument doc = new XmlDocument();
 720                doc.Load(stream);
 721                var keyInfo = new KeyInfo();
 722                keyInfo.LoadXml(doc.DocumentElement);
 723                _signedXml.KeyInfo = keyInfo;
 724            }
 725
 726            if (generateTargettableSignature)
 727            {
 728                _signedXml.Signature.Id = GenerateId();
 729            }
 730            _effectiveSignatureParts = signatureParts;
 731        }
 732
 733        private void GetSigningAlgorithm(SecurityKey signatureKey, string algorithmName, out KeyedHashAlgorithm symmetri
 734        {
 735            symmetricAlgorithm = null;
 736            asymmetricAlgorithm = null;
 737            if (signatureKey is SymmetricSecurityKey symmetricKey)
 738            {
 739                _signingKey = symmetricKey.GetKeyedHashAlgorithm(algorithmName);
 740                if (_signingKey == null)
 741                {
 742                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 743                        SR.Format("UnableToCreateKeyedHashAlgorithm", symmetricKey, algorithmName)));
 744                }
 745            }
 746            else
 747            {
 748                if (!(signatureKey is AsymmetricSecurityKey asymmetricKey))
 749                {
 750                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 751                        SR.Format(SR.UnknownICryptoType, _signingKey)));
 752                }
 753
 754                asymmetricAlgorithm = asymmetricKey.GetAsymmetricAlgorithm(algorithmName, privateKey: true);
 755                if (asymmetricAlgorithm == null)
 756                {
 757                    //TODO MUST before checkin search and replace SR.Format("
 758                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 759                        SR.Format("UnableToCreateHashAlgorithmFromAsymmetricCrypto", algorithmName,
 760                            asymmetricKey)));
 761                }
 762            }
 763        }
 764
 765        protected override ISignatureValueSecurityElement CreateSupportingSignature(SecurityToken token, SecurityKeyIden
 766        {
 767            StartPrimarySignatureCore(token, identifier, MessagePartSpecification.NoParts, false);
 768            return CompletePrimarySignatureCore(null, null, null, null, false);
 769        }
 770
 771        protected override ISignatureValueSecurityElement CreateSupportingSignature(SecurityToken token, SecurityKeyIden
 772        {
 773            AlgorithmSuite.GetSignatureAlgorithmAndKey(token, out string signatureAlgorithm, out SecurityKey signatureKe
 774
 775            SignedXml signedXml = new SignedXml();
 776            SignedInfo signedInfo = signedXml.SignedInfo;
 777            signedInfo.CanonicalizationMethod = AlgorithmSuite.DefaultCanonicalizationAlgorithm;
 778            signedInfo.SignatureMethod = signatureAlgorithm;
 779
 780            if (elementToSign.Id == null)
 781            {
 782                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.ElementToSign
 783            }
 784
 785            MemoryStream stream = new MemoryStream();
 786            XmlDictionaryWriter utf8Writer = TakeUtf8Writer();
 787            utf8Writer.StartCanonicalization(stream, false, null);
 788            elementToSign.WriteTo(utf8Writer, ServiceModelDictionaryManager.Instance);
 789            utf8Writer.EndCanonicalization();
 790            stream.Position = 0;
 791            AddReference("#" + elementToSign.Id, stream);
 792
 793            GetSigningAlgorithm(signatureKey, signatureAlgorithm, out KeyedHashAlgorithm keyedHashAlgorithm, out Asymmet
 794            if (keyedHashAlgorithm != null)
 795            {
 796                signedXml.ComputeSignature(keyedHashAlgorithm);
 797            }
 798            else
 799            {
 800                signedXml.SigningKey = asymmetricAlgorithm;
 801                signedXml.ComputeSignature();
 802            }
 803
 804            SetKeyInfo(signedXml, identifier);
 805            return new SignatureValue(signedXml.Signature);
 806        }
 807
 808        private void SetKeyInfo(SignedXml signedXml, SecurityKeyIdentifier identifier)
 809        {
 810            if (identifier != null)
 811            {
 812                var stream = new MemoryStream();
 813                using (var xmlWriter = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false))
 814                {
 815                    StandardsManager.SecurityTokenSerializer.WriteKeyIdentifier(xmlWriter, identifier);
 816                }
 817
 818                stream.Position = 0;
 819                XmlDocument doc = new XmlDocument();
 820                doc.Load(stream);
 821                var keyInfo = new KeyInfo();
 822                keyInfo.LoadXml(doc.DocumentElement);
 823                signedXml.KeyInfo = keyInfo;
 824            }
 825        }
 826
 827        protected override void WriteSecurityTokenReferencyEntry(XmlDictionaryWriter writer, SecurityToken securityToken
 828        {
 829            return;
 830        }
 831
 832        protected override void StartEncryptionCore(SecurityToken token, SecurityKeyIdentifier keyIdentifier)
 833        {
 834            throw new NotImplementedException();
 835        }
 836
 837        protected override ISecurityElement CompleteEncryptionCore(SendSecurityHeaderElement primarySignature, SendSecur
 838        {
 839            return null;
 840        }
 841    }
 842
 843    internal class WrappedXmlDictionaryWriter : XmlDictionaryWriter
 844    {
 845        private readonly XmlDictionaryWriter _innerWriter;
 846        private int _index;
 847        private bool _insertId;
 848        private bool _isStrReferenceElement;
 849        private readonly string _id;
 850
 0851        public WrappedXmlDictionaryWriter(XmlDictionaryWriter writer, string id)
 852        {
 0853            _innerWriter = writer;
 0854            _index = 0;
 0855            _insertId = false;
 0856            _isStrReferenceElement = false;
 0857            _id = id;
 0858        }
 859
 860        public override void WriteStartAttribute(string prefix, string localName, string namespaceUri)
 861        {
 0862            if (_isStrReferenceElement && _insertId && localName == XD.UtilityDictionary.IdAttribute.Value)
 863            {
 864                // This means the serializer is already writing the Id out, so we don't write it again.
 0865                _insertId = false;
 866            }
 0867            _innerWriter.WriteStartAttribute(prefix, localName, namespaceUri);
 0868        }
 869
 870        public override void WriteStartElement(string prefix, string localName, string namespaceUri)
 871        {
 0872            if (_isStrReferenceElement && _insertId)
 873            {
 0874                if (_id != null)
 875                {
 0876                    _innerWriter.WriteAttributeString(XD.UtilityDictionary.Prefix.Value, XD.UtilityDictionary.IdAttribut
 877                }
 878
 0879                _isStrReferenceElement = false;
 0880                _insertId = false;
 881            }
 882
 0883            _index++;
 884
 0885            if (_index == 1 && localName == XD.SecurityJan2004Dictionary.SecurityTokenReference.Value)
 886            {
 0887                _insertId = true;
 0888                _isStrReferenceElement = true;
 889            }
 890
 0891            _innerWriter.WriteStartElement(prefix, localName, namespaceUri);
 0892        }
 893
 894        // Below methods simply call into innerWritter
 895        public override void Close()
 896        {
 0897            _innerWriter.Close();
 0898        }
 899
 900        public override void Flush()
 901        {
 0902            _innerWriter.Flush();
 0903        }
 904
 905        public override string LookupPrefix(string ns)
 906        {
 0907            return _innerWriter.LookupPrefix(ns);
 908        }
 909
 910        public override void WriteBase64(byte[] buffer, int index, int count)
 911        {
 0912            _innerWriter.WriteBase64(buffer, index, count);
 0913        }
 914
 915        public override void WriteCData(string text)
 916        {
 0917            _innerWriter.WriteCData(text);
 0918        }
 919
 920        public override void WriteCharEntity(char ch)
 921        {
 0922            _innerWriter.WriteCharEntity(ch);
 0923        }
 924
 925        public override void WriteChars(char[] buffer, int index, int count)
 926        {
 0927            _innerWriter.WriteChars(buffer, index, count);
 0928        }
 929
 930        public override void WriteComment(string text)
 931        {
 0932            _innerWriter.WriteComment(text);
 0933        }
 934
 935        public override void WriteDocType(string name, string pubid, string sysid, string subset)
 936        {
 0937            _innerWriter.WriteDocType(name, pubid, sysid, subset);
 0938        }
 939
 940        public override void WriteEndAttribute()
 941        {
 0942            _innerWriter.WriteEndAttribute();
 0943        }
 944
 945        public override void WriteEndDocument()
 946        {
 0947            _innerWriter.WriteEndDocument();
 0948        }
 949
 950        public override void WriteEndElement()
 951        {
 0952            _innerWriter.WriteEndElement();
 0953        }
 954
 955        public override void WriteEntityRef(string name)
 956        {
 0957            _innerWriter.WriteEntityRef(name);
 0958        }
 959
 960        public override void WriteFullEndElement()
 961        {
 0962            _innerWriter.WriteFullEndElement();
 0963        }
 964
 965        public override void WriteProcessingInstruction(string name, string text)
 966        {
 0967            _innerWriter.WriteProcessingInstruction(name, text);
 0968        }
 969
 970        public override void WriteRaw(string data)
 971        {
 0972            _innerWriter.WriteRaw(data);
 0973        }
 974
 975        public override void WriteRaw(char[] buffer, int index, int count)
 976        {
 0977            _innerWriter.WriteRaw(buffer, index, count);
 0978        }
 979
 980        public override void WriteStartDocument(bool standalone)
 981        {
 0982            _innerWriter.WriteStartDocument(standalone);
 0983        }
 984
 985        public override void WriteStartDocument()
 986        {
 0987            _innerWriter.WriteStartDocument();
 0988        }
 989
 990        public override WriteState WriteState
 991        {
 0992            get { return _innerWriter.WriteState; }
 993        }
 994
 995        public override void WriteString(string text)
 996        {
 0997            _innerWriter.WriteString(text);
 0998        }
 999
 1000        public override void WriteSurrogateCharEntity(char lowChar, char highChar)
 1001        {
 01002            _innerWriter.WriteSurrogateCharEntity(lowChar, highChar);
 01003        }
 1004
 1005        public override void WriteWhitespace(string ws)
 1006        {
 01007            _innerWriter.WriteWhitespace(ws);
 01008        }
 1009    }
 1010}
 1011