| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- //----------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Security
- {
- using System.IdentityModel.Tokens;
- using System.Runtime;
- using System.ServiceModel;
- using System.ServiceModel.Diagnostics;
- using System.Xml;
- using ISignatureReaderProvider = System.IdentityModel.ISignatureReaderProvider;
- using ISignatureValueSecurityElement = System.IdentityModel.ISignatureValueSecurityElement;
- using SignedXml = System.IdentityModel.SignedXml;
- using System.Collections.Generic;
- sealed class ReceiveSecurityHeaderElementManager : ISignatureReaderProvider
- {
- const int InitialCapacity = 8;
- readonly ReceiveSecurityHeader securityHeader;
- ReceiveSecurityHeaderEntry[] elements;
- int count;
- readonly string[] headerIds;
- string[] predecryptionHeaderIds;
- string bodyId;
- string bodyContentId;
- bool isPrimaryTokenSigned = false;
- public ReceiveSecurityHeaderElementManager(ReceiveSecurityHeader securityHeader)
- {
- this.securityHeader = securityHeader;
- this.elements = new ReceiveSecurityHeaderEntry[InitialCapacity];
- if (securityHeader.RequireMessageProtection)
- {
- this.headerIds = new string[securityHeader.ProcessedMessage.Headers.Count];
- }
- }
- public int Count
- {
- get { return this.count; }
- }
- public bool IsPrimaryTokenSigned
- {
- get { return this.isPrimaryTokenSigned; }
- set { this.isPrimaryTokenSigned = value; }
- }
- public void AppendElement(
- ReceiveSecurityHeaderElementCategory elementCategory, object element,
- ReceiveSecurityHeaderBindingModes bindingMode, string id, TokenTracker supportingTokenTracker)
- {
- if (id != null)
- {
- VerifyIdUniquenessInSecurityHeader(id);
- }
- EnsureCapacityToAdd();
- this.elements[this.count++].SetElement(elementCategory, element, bindingMode, id, false, null, supportingTokenTracker);
- }
- public void AppendSignature(SignedXml signedXml)
- {
- AppendElement(ReceiveSecurityHeaderElementCategory.Signature, signedXml,
- ReceiveSecurityHeaderBindingModes.Unknown, signedXml.Id, null);
- }
- public void AppendReferenceList(ReferenceList referenceList)
- {
- AppendElement(ReceiveSecurityHeaderElementCategory.ReferenceList, referenceList,
- ReceiveSecurityHeaderBindingModes.Unknown, null, null);
- }
- public void AppendEncryptedData(EncryptedData encryptedData)
- {
- AppendElement(ReceiveSecurityHeaderElementCategory.EncryptedData, encryptedData,
- ReceiveSecurityHeaderBindingModes.Unknown, encryptedData.Id, null);
- }
- public void AppendSignatureConfirmation(ISignatureValueSecurityElement signatureConfirmationElement)
- {
- AppendElement(ReceiveSecurityHeaderElementCategory.SignatureConfirmation, signatureConfirmationElement,
- ReceiveSecurityHeaderBindingModes.Unknown, signatureConfirmationElement.Id, null);
- }
- public void AppendTimestamp(SecurityTimestamp timestamp)
- {
- AppendElement(ReceiveSecurityHeaderElementCategory.Timestamp, timestamp,
- ReceiveSecurityHeaderBindingModes.Unknown, timestamp.Id, null);
- }
- public void AppendSecurityTokenReference(SecurityKeyIdentifierClause strClause, string strId)
- {
- if (!String.IsNullOrEmpty(strId))
- {
- VerifyIdUniquenessInSecurityHeader(strId);
- AppendElement(ReceiveSecurityHeaderElementCategory.SecurityTokenReference, strClause, ReceiveSecurityHeaderBindingModes.Unknown, strId, null);
- }
- }
- public void AppendToken(SecurityToken token, ReceiveSecurityHeaderBindingModes mode, TokenTracker supportingTokenTracker)
- {
- AppendElement(ReceiveSecurityHeaderElementCategory.Token, token,
- mode, token.Id, supportingTokenTracker);
- }
- public void EnsureAllRequiredSecurityHeaderTargetsWereProtected()
- {
- Fx.Assert(this.securityHeader.RequireMessageProtection, "security header protection checks should only be done for message security");
- ReceiveSecurityHeaderEntry entry;
- for (int i = 0; i < this.count; i++)
- {
- GetElementEntry(i, out entry);
- if (!entry.signed)
- {
- switch (entry.elementCategory)
- {
- case ReceiveSecurityHeaderElementCategory.Timestamp:
- case ReceiveSecurityHeaderElementCategory.SignatureConfirmation:
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new MessageSecurityException(SR.GetString(SR.RequiredSecurityHeaderElementNotSigned, entry.elementCategory, entry.id)));
- case ReceiveSecurityHeaderElementCategory.Token:
- switch (entry.bindingMode)
- {
- case ReceiveSecurityHeaderBindingModes.Signed:
- case ReceiveSecurityHeaderBindingModes.SignedEndorsing:
- case ReceiveSecurityHeaderBindingModes.Basic:
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new MessageSecurityException(SR.GetString(SR.RequiredSecurityTokenNotSigned, entry.element, entry.bindingMode)));
- }
- break;
- }
- }
-
- if (!entry.encrypted)
- {
- if (entry.elementCategory == ReceiveSecurityHeaderElementCategory.Token &&
- entry.bindingMode == ReceiveSecurityHeaderBindingModes.Basic)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new MessageSecurityException(SR.GetString(SR.RequiredSecurityTokenNotEncrypted, entry.element, entry.bindingMode)));
- }
- }
- }
- }
- void EnsureCapacityToAdd()
- {
- if (this.count == this.elements.Length)
- {
- ReceiveSecurityHeaderEntry[] newElements = new ReceiveSecurityHeaderEntry[this.elements.Length * 2];
- Array.Copy(this.elements, 0, newElements, 0, this.count);
- this.elements = newElements;
- }
- }
- public object GetElement(int index)
- {
- Fx.Assert(0 <= index && index < this.count, "");
- return this.elements[index].element;
- }
- public T GetElement<T>(int index) where T : class
- {
- Fx.Assert(0 <= index && index < this.count, "");
- return (T) this.elements[index].element;
- }
- public void GetElementEntry(int index, out ReceiveSecurityHeaderEntry element)
- {
- Fx.Assert(0 <= index && index < this.count, "index out of range");
- element = this.elements[index];
- }
- public ReceiveSecurityHeaderElementCategory GetElementCategory(int index)
- {
- Fx.Assert(0 <= index && index < this.count, "index out of range");
- return this.elements[index].elementCategory;
- }
- public void GetPrimarySignature(out XmlDictionaryReader reader, out string id)
- {
- ReceiveSecurityHeaderEntry entry;
- for (int i = 0; i < this.count; i++)
- {
- GetElementEntry(i, out entry);
- if (entry.elementCategory == ReceiveSecurityHeaderElementCategory.Signature &&
- entry.bindingMode == ReceiveSecurityHeaderBindingModes.Primary)
- {
- reader = GetReader(i, false);
- id = entry.id;
- return;
- }
- }
- reader = null;
- id = null;
- return;
- }
- internal XmlDictionaryReader GetReader(int index, bool requiresEncryptedFormReader)
- {
- Fx.Assert(0 <= index && index < this.count, "index out of range");
- if (!requiresEncryptedFormReader)
- {
- byte[] decryptedBuffer = this.elements[index].decryptedBuffer;
- if (decryptedBuffer != null)
- {
- return this.securityHeader.CreateDecryptedReader(decryptedBuffer);
- }
- }
- XmlDictionaryReader securityHeaderReader = this.securityHeader.CreateSecurityHeaderReader();
- securityHeaderReader.ReadStartElement();
- for (int i = 0; securityHeaderReader.IsStartElement() && i < index; i++)
- {
- securityHeaderReader.Skip();
- }
- return securityHeaderReader;
- }
- public XmlDictionaryReader GetSignatureVerificationReader(string id, bool requiresEncryptedFormReaderIfDecrypted)
- {
- ReceiveSecurityHeaderEntry entry;
- for (int i = 0; i < this.count; i++)
- {
- GetElementEntry(i, out entry);
- bool encryptedForm = entry.encrypted && requiresEncryptedFormReaderIfDecrypted;
- bool isSignedToken = (entry.bindingMode == ReceiveSecurityHeaderBindingModes.Signed) || (entry.bindingMode == ReceiveSecurityHeaderBindingModes.SignedEndorsing);
- if (entry.MatchesId(id, encryptedForm))
- {
- SetSigned(i);
- if (!this.IsPrimaryTokenSigned)
- {
- this.IsPrimaryTokenSigned = entry.bindingMode == ReceiveSecurityHeaderBindingModes.Primary && entry.elementCategory == ReceiveSecurityHeaderElementCategory.Token;
- }
- return GetReader(i, encryptedForm);
- }
- else if (entry.MatchesId(id, isSignedToken))
- {
- SetSigned(i);
- if (!this.IsPrimaryTokenSigned)
- {
- this.IsPrimaryTokenSigned = entry.bindingMode == ReceiveSecurityHeaderBindingModes.Primary && entry.elementCategory == ReceiveSecurityHeaderElementCategory.Token;
- }
- return GetReader(i, isSignedToken);
- }
- }
- return null;
- }
- void OnDuplicateId(string id)
- {
- throw TraceUtility.ThrowHelperError(
- new MessageSecurityException(SR.GetString(SR.DuplicateIdInMessageToBeVerified, id)), this.securityHeader.SecurityVerifiedMessage);
- }
- public void SetBindingMode(int index, ReceiveSecurityHeaderBindingModes bindingMode)
- {
- Fx.Assert(0 <= index && index < this.count, "index out of range");
- this.elements[index].bindingMode = bindingMode;
- }
- public void SetElement(int index, object element)
- {
- Fx.Assert(0 <= index && index < this.count, "");
- this.elements[index].element = element;
- }
- public void ReplaceHeaderEntry(int index, ReceiveSecurityHeaderEntry element)
- {
- Fx.Assert(0 <= index && index < this.count, "");
- this.elements[index] = element;
- }
- public void SetElementAfterDecryption(
- int index,
- ReceiveSecurityHeaderElementCategory elementCategory, object element,
- ReceiveSecurityHeaderBindingModes bindingMode, string id, byte[] decryptedBuffer, TokenTracker supportingTokenTracker)
- {
- Fx.Assert(0 <= index && index < this.count, "index out of range");
- Fx.Assert(this.elements[index].elementCategory == ReceiveSecurityHeaderElementCategory.EncryptedData, "Replaced item must be EncryptedData");
- if (id != null)
- {
- VerifyIdUniquenessInSecurityHeader(id);
- }
- this.elements[index].PreserveIdBeforeDecryption();
- this.elements[index].SetElement(elementCategory, element, bindingMode, id, true, decryptedBuffer, supportingTokenTracker);
- }
- public void SetSignatureAfterDecryption(int index, SignedXml signedXml, byte[] decryptedBuffer)
- {
- SetElementAfterDecryption(index, ReceiveSecurityHeaderElementCategory.Signature,
- signedXml, ReceiveSecurityHeaderBindingModes.Unknown, signedXml.Id, decryptedBuffer, null);
- }
- public void SetSignatureConfirmationAfterDecryption(int index, ISignatureValueSecurityElement signatureConfirmationElement, byte[] decryptedBuffer)
- {
- SetElementAfterDecryption(index, ReceiveSecurityHeaderElementCategory.SignatureConfirmation,
- signatureConfirmationElement, ReceiveSecurityHeaderBindingModes.Unknown, signatureConfirmationElement.Id, decryptedBuffer, null);
- }
- internal void SetSigned(int index)
- {
- Fx.Assert(0 <= index && index < this.count, "");
- this.elements[index].signed = true;
- if (this.elements[index].supportingTokenTracker != null)
- {
- this.elements[index].supportingTokenTracker.IsSigned = true;
- }
- }
- public void SetTimestampSigned(string id)
- {
- for (int i = 0; i < this.count; i++)
- {
- if (this.elements[i].elementCategory == ReceiveSecurityHeaderElementCategory.Timestamp &&
- this.elements[i].id == id)
- {
- SetSigned(i);
- }
- }
- }
- public void SetTokenAfterDecryption(int index, SecurityToken token, ReceiveSecurityHeaderBindingModes mode, byte[] decryptedBuffer, TokenTracker supportingTokenTracker)
- {
- SetElementAfterDecryption(index, ReceiveSecurityHeaderElementCategory.Token, token, mode, token.Id, decryptedBuffer, supportingTokenTracker);
- }
- internal bool TryGetTokenElementIndexFromStrId(string strId, out int index)
- {
- index = -1;
- SecurityKeyIdentifierClause strClause = null;
- for (int position = 0; position < this.Count; position++)
- {
- if (this.GetElementCategory(position) == ReceiveSecurityHeaderElementCategory.SecurityTokenReference)
- {
- strClause = this.GetElement(position) as SecurityKeyIdentifierClause;
- if (strClause.Id == strId)
- break;
- }
- }
- if (strClause == null)
- return false;
- for (int position = 0; position < this.Count; position++)
- {
- if (this.GetElementCategory(position) == ReceiveSecurityHeaderElementCategory.Token)
- {
- SecurityToken token = this.GetElement(position) as SecurityToken;
- if (token.MatchesKeyIdentifierClause(strClause))
- {
- index = position;
- return true;
- }
- }
- }
- return false;
- }
- public void VerifyUniquenessAndSetBodyId(string id)
- {
- if (id != null)
- {
- VerifyIdUniquenessInSecurityHeader(id);
- VerifyIdUniquenessInMessageHeadersAndBody(id, this.headerIds.Length);
- this.bodyId = id;
- }
- }
- public void VerifyUniquenessAndSetBodyContentId(string id)
- {
- if (id != null)
- {
- VerifyIdUniquenessInSecurityHeader(id);
- VerifyIdUniquenessInMessageHeadersAndBody(id, this.headerIds.Length);
- this.bodyContentId = id;
- }
- }
- public void VerifyUniquenessAndSetDecryptedHeaderId(string id, int headerIndex)
- {
- if (id != null)
- {
- VerifyIdUniquenessInSecurityHeader(id);
- VerifyIdUniquenessInMessageHeadersAndBody(id, headerIndex);
- if (this.predecryptionHeaderIds == null)
- {
- this.predecryptionHeaderIds = new string[headerIds.Length];
- }
- this.predecryptionHeaderIds[headerIndex] = this.headerIds[headerIndex];
- this.headerIds[headerIndex] = id;
- }
- }
- public void VerifyUniquenessAndSetHeaderId(string id, int headerIndex)
- {
- if (id != null)
- {
- VerifyIdUniquenessInSecurityHeader(id);
- VerifyIdUniquenessInMessageHeadersAndBody(id, headerIndex);
- this.headerIds[headerIndex] = id;
- }
- }
- void VerifyIdUniquenessInHeaderIdTable(string id, int headerCount, string[] headerIdTable)
- {
- for (int i = 0; i < headerCount; i++)
- {
- if (headerIdTable[i] == id)
- {
- OnDuplicateId(id);
- }
- }
- }
- void VerifyIdUniquenessInSecurityHeader(string id)
- {
- Fx.Assert(id != null, "Uniqueness should only be tested for non-empty ids");
- for (int i = 0; i < this.count; i++)
- {
- if (this.elements[i].id == id || this.elements[i].encryptedFormId == id)
- {
- OnDuplicateId(id);
- }
- }
- }
- void VerifyIdUniquenessInMessageHeadersAndBody(string id, int headerCount)
- {
- Fx.Assert(id != null, "Uniqueness should only be tested for non-empty ids");
- VerifyIdUniquenessInHeaderIdTable(id, headerCount, this.headerIds);
- if (this.predecryptionHeaderIds != null)
- {
- VerifyIdUniquenessInHeaderIdTable(id, headerCount, this.predecryptionHeaderIds);
- }
- if (this.bodyId == id || this.bodyContentId == id)
- {
- OnDuplicateId(id);
- }
- }
- XmlDictionaryReader ISignatureReaderProvider.GetReader(object callbackContext)
- {
- int index = (int)callbackContext;
- Fx.Assert(index < this.Count, "Invalid Context provided.");
- return GetReader(index, false);
- }
- public void VerifySignatureConfirmationWasFound()
- {
- ReceiveSecurityHeaderEntry entry;
- for (int i = 0; i < this.count; i++)
- {
- GetElementEntry(i, out entry);
- if (entry.elementCategory == ReceiveSecurityHeaderElementCategory.SignatureConfirmation)
- {
- return;
- }
- }
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SignatureConfirmationWasExpected)));
- }
- }
- }
|