//---------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Security { using System.Collections.Generic; using System.Collections.ObjectModel; using System.IdentityModel.Policy; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.Runtime; using System.Runtime.Diagnostics; using System.Security.Cryptography; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Diagnostics; using System.ServiceModel.Diagnostics.Application; using System.ServiceModel.Security.Tokens; using System.Xml; using Reference = System.IdentityModel.Reference; using SignedInfo = System.IdentityModel.SignedInfo; using SignedXml = System.IdentityModel.SignedXml; using StandardSignedInfo = System.IdentityModel.StandardSignedInfo; class WSSecurityOneDotZeroReceiveSecurityHeader : ReceiveSecurityHeader { WrappedKeySecurityToken pendingDecryptionToken; ReferenceList pendingReferenceList; SignedXml pendingSignature; List earlyDecryptedDataReferences; public WSSecurityOneDotZeroReceiveSecurityHeader(Message message, string actor, bool mustUnderstand, bool relay, SecurityStandardsManager standardsManager, SecurityAlgorithmSuite algorithmSuite, int headerIndex, MessageDirection transferDirection) : base(message, actor, mustUnderstand, relay, standardsManager, algorithmSuite, headerIndex, transferDirection) { } protected static SymmetricAlgorithm CreateDecryptionAlgorithm(SecurityToken token, string encryptionMethod, SecurityAlgorithmSuite suite) { if (encryptionMethod == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException( SR.GetString(SR.EncryptionMethodMissingInEncryptedData))); } suite.EnsureAcceptableEncryptionAlgorithm(encryptionMethod); SymmetricSecurityKey symmetricSecurityKey = SecurityUtils.GetSecurityKey(token); if (symmetricSecurityKey == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException( SR.GetString(SR.TokenCannotCreateSymmetricCrypto, token))); } suite.EnsureAcceptableDecryptionSymmetricKeySize(symmetricSecurityKey, token); SymmetricAlgorithm algorithm = symmetricSecurityKey.GetSymmetricAlgorithm(encryptionMethod); if (algorithm == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException( SR.GetString(SR.UnableToCreateSymmetricAlgorithmFromToken, encryptionMethod))); } return algorithm; } void DecryptBody(XmlDictionaryReader bodyContentReader, SecurityToken token) { EncryptedData bodyXml = new EncryptedData(); bodyXml.ShouldReadXmlReferenceKeyInfoClause = this.MessageDirection == MessageDirection.Output; bodyXml.SecurityTokenSerializer = this.StandardsManager.SecurityTokenSerializer; bodyXml.ReadFrom(bodyContentReader, MaxReceivedMessageSize); if (!bodyContentReader.EOF && bodyContentReader.NodeType != XmlNodeType.EndElement) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.BadEncryptedBody))); } if (token == null) { token = ResolveKeyIdentifier(bodyXml.KeyIdentifier, this.PrimaryTokenResolver, false); } RecordEncryptionToken(token); using (SymmetricAlgorithm algorithm = CreateDecryptionAlgorithm(token, bodyXml.EncryptionMethod, this.AlgorithmSuite)) { bodyXml.SetUpDecryption(algorithm); this.SecurityVerifiedMessage.SetDecryptedBody(bodyXml.GetDecryptedBuffer()); } } protected virtual DecryptedHeader DecryptHeader(XmlDictionaryReader reader, WrappedKeySecurityToken wrappedKeyToken) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new MessageSecurityException(SR.GetString(SR.HeaderDecryptionNotSupportedInWsSecurityJan2004))); } protected override byte[] DecryptSecurityHeaderElement( EncryptedData encryptedData, WrappedKeySecurityToken wrappedKeyToken, out SecurityToken encryptionToken) { if ((encryptedData.KeyIdentifier != null) || (wrappedKeyToken == null)) { // The EncryptedData might have a KeyInfo inside it. Try resolving the SecurityKeyIdentifier. encryptionToken = ResolveKeyIdentifier(encryptedData.KeyIdentifier, this.CombinedPrimaryTokenResolver, false); if (wrappedKeyToken != null && wrappedKeyToken.ReferenceList != null && encryptedData.HasId && wrappedKeyToken.ReferenceList.ContainsReferredId(encryptedData.Id) && (wrappedKeyToken != encryptionToken)) { // We have a EncryptedKey with a ReferenceList inside it. This would mean that // all the EncryptedData pointed by the ReferenceList should be encrypted only // by this key. The individual EncryptedData elements if containing a KeyInfo // clause should point back to the same EncryptedKey token. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.EncryptedKeyWasNotEncryptedWithTheRequiredEncryptingToken, wrappedKeyToken))); } } else { encryptionToken = wrappedKeyToken; } using (SymmetricAlgorithm algorithm = CreateDecryptionAlgorithm(encryptionToken, encryptedData.EncryptionMethod, this.AlgorithmSuite)) { encryptedData.SetUpDecryption(algorithm); return encryptedData.GetDecryptedBuffer(); } } protected override WrappedKeySecurityToken DecryptWrappedKey(XmlDictionaryReader reader) { if (TD.WrappedKeyDecryptionStartIsEnabled()) { TD.WrappedKeyDecryptionStart(this.EventTraceActivity); } WrappedKeySecurityToken token = (WrappedKeySecurityToken)this.StandardsManager.SecurityTokenSerializer.ReadToken( reader, this.PrimaryTokenResolver); this.AlgorithmSuite.EnsureAcceptableKeyWrapAlgorithm(token.WrappingAlgorithm, token.WrappingSecurityKey is AsymmetricSecurityKey); if (TD.WrappedKeyDecryptionSuccessIsEnabled()) { TD.WrappedKeyDecryptionSuccess(this.EventTraceActivity); } return token; } bool EnsureDigestValidityIfIdMatches( SignedInfo signedInfo, string id, XmlDictionaryReader reader, bool doSoapAttributeChecks, MessagePartSpecification signatureParts, MessageHeaderInfo info, bool checkForTokensAtHeaders) { if (signedInfo == null) { return false; } if (doSoapAttributeChecks) { VerifySoapAttributeMatchForHeader(info, signatureParts, reader); } bool signed = false; bool isRecognizedSecurityToken = checkForTokensAtHeaders && this.StandardsManager.SecurityTokenSerializer.CanReadToken(reader); try { signed = signedInfo.EnsureDigestValidityIfIdMatches(id, reader); } catch (CryptographicException exception) { // // Wrap the crypto exception here so that the perf couter can be updated correctly // throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.FailedSignatureVerification), exception)); } if (signed && isRecognizedSecurityToken) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SecurityTokenFoundOutsideSecurityHeader, info.Namespace, info.Name))); } return signed; } protected override void ExecuteMessageProtectionPass(bool hasAtLeastOneSupportingTokenExpectedToBeSigned) { SignatureTargetIdManager idManager = this.StandardsManager.IdManager; MessagePartSpecification encryptionParts = this.RequiredEncryptionParts ?? MessagePartSpecification.NoParts; MessagePartSpecification signatureParts = this.RequiredSignatureParts ?? MessagePartSpecification.NoParts; bool checkForTokensAtHeaders = hasAtLeastOneSupportingTokenExpectedToBeSigned; bool doSoapAttributeChecks = !signatureParts.IsBodyIncluded; bool encryptBeforeSign = this.EncryptBeforeSignMode; SignedInfo signedInfo = this.pendingSignature != null ? this.pendingSignature.Signature.SignedInfo : null; SignatureConfirmations signatureConfirmations = this.GetSentSignatureConfirmations(); if (signatureConfirmations != null && signatureConfirmations.Count > 0 && signatureConfirmations.IsMarkedForEncryption) { // If Signature Confirmations are encrypted then the signature should // be encrypted as well. this.VerifySignatureEncryption(); } MessageHeaders headers = this.SecurityVerifiedMessage.Headers; XmlDictionaryReader reader = this.SecurityVerifiedMessage.GetReaderAtFirstHeader(); bool atLeastOneHeaderOrBodyEncrypted = false; for (int i = 0; i < headers.Count; i++) { if (reader.NodeType != XmlNodeType.Element) { reader.MoveToContent(); } if (i == this.HeaderIndex) { reader.Skip(); continue; } bool isHeaderEncrypted = false; string id = idManager.ExtractId(reader); if (id != null) { isHeaderEncrypted = TryDeleteReferenceListEntry(id); } if (!isHeaderEncrypted && reader.IsStartElement(SecurityXXX2005Strings.EncryptedHeader, SecurityXXX2005Strings.Namespace)) { XmlDictionaryReader localreader = headers.GetReaderAtHeader(i); localreader.ReadStartElement(SecurityXXX2005Strings.EncryptedHeader, SecurityXXX2005Strings.Namespace); if (localreader.IsStartElement(EncryptedData.ElementName, XD.XmlEncryptionDictionary.Namespace)) { string encryptedDataId = localreader.GetAttribute(XD.XmlEncryptionDictionary.Id, null); if (encryptedDataId != null && TryDeleteReferenceListEntry(encryptedDataId)) { isHeaderEncrypted = true; } } } this.ElementManager.VerifyUniquenessAndSetHeaderId(id, i); MessageHeaderInfo info = headers[i]; if (!isHeaderEncrypted && encryptionParts.IsHeaderIncluded(info.Name, info.Namespace)) { this.SecurityVerifiedMessage.OnUnencryptedPart(info.Name, info.Namespace); } bool headerSigned; if ((!isHeaderEncrypted || encryptBeforeSign) && id != null) { headerSigned = EnsureDigestValidityIfIdMatches(signedInfo, id, reader, doSoapAttributeChecks, signatureParts, info, checkForTokensAtHeaders); } else { headerSigned = false; } if (isHeaderEncrypted) { XmlDictionaryReader decryptionReader = headerSigned ? headers.GetReaderAtHeader(i) : reader; DecryptedHeader decryptedHeader = DecryptHeader(decryptionReader, this.pendingDecryptionToken); info = decryptedHeader; id = decryptedHeader.Id; this.ElementManager.VerifyUniquenessAndSetDecryptedHeaderId(id, i); headers.ReplaceAt(i, decryptedHeader); if (!ReferenceEquals(decryptionReader, reader)) { decryptionReader.Close(); } if (!encryptBeforeSign && id != null) { XmlDictionaryReader decryptedHeaderReader = decryptedHeader.GetHeaderReader(); headerSigned = EnsureDigestValidityIfIdMatches(signedInfo, id, decryptedHeaderReader, doSoapAttributeChecks, signatureParts, info, checkForTokensAtHeaders); decryptedHeaderReader.Close(); } } if (!headerSigned && signatureParts.IsHeaderIncluded(info.Name, info.Namespace)) { this.SecurityVerifiedMessage.OnUnsignedPart(info.Name, info.Namespace); } if (headerSigned && isHeaderEncrypted) { // We have a header that is signed and encrypted. So the accompanying primary signature // should be encrypted as well. this.VerifySignatureEncryption(); } if (isHeaderEncrypted && !headerSigned) { // We require all encrypted headers (outside the security header) to be signed. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.EncryptedHeaderNotSigned, info.Name, info.Namespace))); } if (!headerSigned && !isHeaderEncrypted) { reader.Skip(); } atLeastOneHeaderOrBodyEncrypted |= isHeaderEncrypted; } reader.ReadEndElement(); if (reader.NodeType != XmlNodeType.Element) { reader.MoveToContent(); } string bodyId = idManager.ExtractId(reader); this.ElementManager.VerifyUniquenessAndSetBodyId(bodyId); this.SecurityVerifiedMessage.SetBodyPrefixAndAttributes(reader); bool expectBodyEncryption = encryptionParts.IsBodyIncluded || HasPendingDecryptionItem(); bool bodySigned; if ((!expectBodyEncryption || encryptBeforeSign) && bodyId != null) { bodySigned = EnsureDigestValidityIfIdMatches(signedInfo, bodyId, reader, false, null, null, false); } else { bodySigned = false; } bool bodyEncrypted; if (expectBodyEncryption) { XmlDictionaryReader bodyReader = bodySigned ? this.SecurityVerifiedMessage.CreateFullBodyReader() : reader; bodyReader.ReadStartElement(); string bodyContentId = idManager.ExtractId(bodyReader); this.ElementManager.VerifyUniquenessAndSetBodyContentId(bodyContentId); bodyEncrypted = bodyContentId != null && TryDeleteReferenceListEntry(bodyContentId); if (bodyEncrypted) { DecryptBody(bodyReader, this.pendingDecryptionToken); } if (!ReferenceEquals(bodyReader, reader)) { bodyReader.Close(); } if (!encryptBeforeSign && signedInfo != null && signedInfo.HasUnverifiedReference(bodyId)) { bodyReader = this.SecurityVerifiedMessage.CreateFullBodyReader(); bodySigned = EnsureDigestValidityIfIdMatches(signedInfo, bodyId, bodyReader, false, null, null, false); bodyReader.Close(); } } else { bodyEncrypted = false; } if (bodySigned && bodyEncrypted) { this.VerifySignatureEncryption(); } reader.Close(); if (this.pendingSignature != null) { this.pendingSignature.CompleteSignatureVerification(); this.pendingSignature = null; } this.pendingDecryptionToken = null; atLeastOneHeaderOrBodyEncrypted |= bodyEncrypted; if (!bodySigned && signatureParts.IsBodyIncluded) { this.SecurityVerifiedMessage.OnUnsignedPart(XD.MessageDictionary.Body.Value, this.Version.Envelope.Namespace); } if (!bodyEncrypted && encryptionParts.IsBodyIncluded) { this.SecurityVerifiedMessage.OnUnencryptedPart(XD.MessageDictionary.Body.Value, this.Version.Envelope.Namespace); } this.SecurityVerifiedMessage.OnMessageProtectionPassComplete(atLeastOneHeaderOrBodyEncrypted); } protected override bool IsReaderAtEncryptedData(XmlDictionaryReader reader) { bool encrypted = reader.IsStartElement(EncryptedData.ElementName, XD.XmlEncryptionDictionary.Namespace); if (encrypted == true) this.HasAtLeastOneItemInsideSecurityHeaderEncrypted = true; return encrypted; } protected override bool IsReaderAtEncryptedKey(XmlDictionaryReader reader) { return reader.IsStartElement(EncryptedKey.ElementName, XD.XmlEncryptionDictionary.Namespace); } protected override bool IsReaderAtReferenceList(XmlDictionaryReader reader) { return reader.IsStartElement(ReferenceList.ElementName, ReferenceList.NamespaceUri); } protected override bool IsReaderAtSignature(XmlDictionaryReader reader) { return reader.IsStartElement(XD.XmlSignatureDictionary.Signature, XD.XmlSignatureDictionary.Namespace); } protected override bool IsReaderAtSecurityTokenReference(XmlDictionaryReader reader) { return reader.IsStartElement(XD.SecurityJan2004Dictionary.SecurityTokenReference, XD.SecurityJan2004Dictionary.Namespace); } protected override void ProcessReferenceListCore(ReferenceList referenceList, WrappedKeySecurityToken wrappedKeyToken) { this.pendingReferenceList = referenceList; this.pendingDecryptionToken = wrappedKeyToken; } protected override ReferenceList ReadReferenceListCore(XmlDictionaryReader reader) { ReferenceList referenceList = new ReferenceList(); referenceList.ReadFrom(reader); return referenceList; } protected override EncryptedData ReadSecurityHeaderEncryptedItem(XmlDictionaryReader reader, bool readXmlreferenceKeyInfoClause) { EncryptedData encryptedData = new EncryptedData(); encryptedData.ShouldReadXmlReferenceKeyInfoClause = readXmlreferenceKeyInfoClause; encryptedData.SecurityTokenSerializer = this.StandardsManager.SecurityTokenSerializer; encryptedData.ReadFrom(reader); return encryptedData; } protected override SignedXml ReadSignatureCore(XmlDictionaryReader signatureReader) { SignedXml signedXml = new SignedXml(ServiceModelDictionaryManager.Instance, this.StandardsManager.SecurityTokenSerializer); signedXml.Signature.SignedInfo.ResourcePool = this.ResourcePool; signedXml.ReadFrom(signatureReader); return signedXml; } protected static bool TryResolveKeyIdentifier( SecurityKeyIdentifier keyIdentifier, SecurityTokenResolver resolver, bool isFromSignature, out SecurityToken token) { if (keyIdentifier == null) { if (isFromSignature) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.NoKeyInfoInSignatureToFindVerificationToken))); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.NoKeyInfoInEncryptedItemToFindDecryptingToken))); } } return resolver.TryResolveToken(keyIdentifier, out token); } protected static SecurityToken ResolveKeyIdentifier(SecurityKeyIdentifier keyIdentifier, SecurityTokenResolver resolver, bool isFromSignature) { SecurityToken token; if (!TryResolveKeyIdentifier(keyIdentifier, resolver, isFromSignature, out token)) { if (isFromSignature) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException( SR.GetString(SR.UnableToResolveKeyInfoForVerifyingSignature, keyIdentifier, resolver))); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException( SR.GetString(SR.UnableToResolveKeyInfoForDecryption, keyIdentifier, resolver))); } } return token; } SecurityToken ResolveSignatureToken(SecurityKeyIdentifier keyIdentifier, SecurityTokenResolver resolver, bool isPrimarySignature) { SecurityToken token; TryResolveKeyIdentifier(keyIdentifier, resolver, true, out token); if (token == null && !isPrimarySignature) { // check if there is a rsa key token authenticator if (keyIdentifier.Count == 1) { RsaKeyIdentifierClause rsaClause; if (keyIdentifier.TryFind(out rsaClause)) { RsaSecurityTokenAuthenticator rsaAuthenticator = FindAllowedAuthenticator(false); if (rsaAuthenticator != null) { token = new RsaSecurityToken(rsaClause.Rsa); ReadOnlyCollection authorizationPolicies = rsaAuthenticator.ValidateToken(token); SupportingTokenAuthenticatorSpecification spec; TokenTracker rsaTracker = GetSupportingTokenTracker(rsaAuthenticator, out spec); if (rsaTracker == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.UnknownTokenAuthenticatorUsedInTokenProcessing, rsaAuthenticator))); } rsaTracker.RecordToken(token); SecurityTokenAuthorizationPoliciesMapping.Add(token, authorizationPolicies); } } } } if (token == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException( SR.GetString(SR.UnableToResolveKeyInfoForVerifyingSignature, keyIdentifier, resolver))); } return token; } protected override void ReadSecurityTokenReference(XmlDictionaryReader reader) { string strId = reader.GetAttribute(XD.UtilityDictionary.IdAttribute, XD.UtilityDictionary.Namespace); SecurityKeyIdentifierClause strClause = this.StandardsManager.SecurityTokenSerializer.ReadKeyIdentifierClause(reader); if (String.IsNullOrEmpty(strClause.Id)) { strClause.Id = strId; } if (!String.IsNullOrEmpty(strClause.Id)) { this.ElementManager.AppendSecurityTokenReference(strClause, strClause.Id); } } bool HasPendingDecryptionItem() { return this.pendingReferenceList != null && this.pendingReferenceList.DataReferenceCount > 0; } protected override bool TryDeleteReferenceListEntry(string id) { return this.pendingReferenceList != null && this.pendingReferenceList.TryRemoveReferredId(id); } protected override void EnsureDecryptionComplete() { if (this.earlyDecryptedDataReferences != null) { for (int i = 0; i < this.earlyDecryptedDataReferences.Count; i++) { if (!TryDeleteReferenceListEntry(this.earlyDecryptedDataReferences[i])) { throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.UnexpectedEncryptedElementInSecurityHeader)), this.Message); } } } if (HasPendingDecryptionItem()) { throw TraceUtility.ThrowHelperError( new MessageSecurityException(SR.GetString(SR.UnableToResolveDataReference, this.pendingReferenceList.GetReferredId(0))), this.Message); } } protected override void OnDecryptionOfSecurityHeaderItemRequiringReferenceListEntry(string id) { if (!TryDeleteReferenceListEntry(id)) { if (this.earlyDecryptedDataReferences == null) { this.earlyDecryptedDataReferences = new List(4); } this.earlyDecryptedDataReferences.Add(id); } } protected override SecurityToken VerifySignature(SignedXml signedXml, bool isPrimarySignature, SecurityHeaderTokenResolver resolver, object signatureTarget, string id) { if (TD.SignatureVerificationStartIsEnabled()) { TD.SignatureVerificationStart(this.EventTraceActivity); } SecurityToken token = ResolveSignatureToken(signedXml.Signature.KeyIdentifier, resolver, isPrimarySignature); if (isPrimarySignature) { RecordSignatureToken(token); } ReadOnlyCollection keys = token.SecurityKeys; SecurityKey securityKey = (keys != null && keys.Count > 0) ? keys[0] : null; if (securityKey == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException( SR.GetString(SR.UnableToCreateICryptoFromTokenForSignatureVerification, token))); } this.AlgorithmSuite.EnsureAcceptableSignatureKeySize(securityKey, token); this.AlgorithmSuite.EnsureAcceptableSignatureAlgorithm(securityKey, signedXml.Signature.SignedInfo.SignatureMethod); signedXml.StartSignatureVerification(securityKey); StandardSignedInfo signedInfo = (StandardSignedInfo)signedXml.Signature.SignedInfo; ValidateDigestsOfTargetsInSecurityHeader(signedInfo, this.Timestamp, isPrimarySignature, signatureTarget, id); if (!isPrimarySignature) { if ((!this.RequireMessageProtection) && (securityKey is AsymmetricSecurityKey) && (this.Version.Addressing != AddressingVersion.None)) { // For Transport Security using Asymmetric Keys verify that // the 'To' header is signed. int headerIndex = this.Message.Headers.FindHeader(XD.AddressingDictionary.To.Value, this.Message.Version.Addressing.Namespace); if (headerIndex == -1) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.TransportSecuredMessageMissingToHeader))); XmlDictionaryReader toHeaderReader = this.Message.Headers.GetReaderAtHeader(headerIndex); id = toHeaderReader.GetAttribute(XD.UtilityDictionary.IdAttribute, XD.UtilityDictionary.Namespace); // DevDiv:938534 - We added a flag that allow unsigned headers. If this is set, we do not throw an Exception but move on to CompleteSignatureVerification() if (LocalAppContextSwitches.AllowUnsignedToHeader) { // The lack of an id indicates that the sender did not wish to sign the header. We can safely assume that null indicates this header is not signed. // If id is not null, then we need to validate the Digest and ensure signature is valid. The exception is thrown deeper in the System.IdentityModel stack. if (id != null) { signedXml.EnsureDigestValidityIfIdMatches(id, toHeaderReader); } } else { // default behavior for all platforms if (id == null) { // throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.UnsignedToHeaderInTransportSecuredMessage))); } signedXml.EnsureDigestValidity(id, toHeaderReader); } } signedXml.CompleteSignatureVerification(); return token; } this.pendingSignature = signedXml; if (TD.SignatureVerificationSuccessIsEnabled()) { TD.SignatureVerificationSuccess(this.EventTraceActivity); } return token; } void ValidateDigestsOfTargetsInSecurityHeader(StandardSignedInfo signedInfo, SecurityTimestamp timestamp, bool isPrimarySignature, object signatureTarget, string id) { Fx.Assert(!isPrimarySignature || (isPrimarySignature && (signatureTarget == null)), "For primary signature we try to validate all the references."); for (int i = 0; i < signedInfo.ReferenceCount; i++) { Reference reference = signedInfo[i]; this.AlgorithmSuite.EnsureAcceptableDigestAlgorithm(reference.DigestMethod); string referredId = reference.ExtractReferredId(); if (isPrimarySignature || (id == referredId)) { if (timestamp != null && timestamp.Id == referredId && !reference.TransformChain.NeedsInclusiveContext && timestamp.DigestAlgorithm == reference.DigestMethod && timestamp.GetDigest() != null) { reference.EnsureDigestValidity(referredId, timestamp.GetDigest()); this.ElementManager.SetTimestampSigned(referredId); } else { if (signatureTarget != null) reference.EnsureDigestValidity(id, signatureTarget); else { int tokenIndex = -1; XmlDictionaryReader reader = null; if (reference.IsStrTranform()) { if (this.ElementManager.TryGetTokenElementIndexFromStrId(referredId, out tokenIndex)) { ReceiveSecurityHeaderEntry entry; this.ElementManager.GetElementEntry(tokenIndex, out entry); bool isSignedToken = (entry.bindingMode == ReceiveSecurityHeaderBindingModes.Signed) || (entry.bindingMode == ReceiveSecurityHeaderBindingModes.SignedEndorsing); // This means it is a protected(signed)primary token. if (!this.ElementManager.IsPrimaryTokenSigned) { this.ElementManager.IsPrimaryTokenSigned = entry.bindingMode == ReceiveSecurityHeaderBindingModes.Primary && entry.elementCategory == ReceiveSecurityHeaderElementCategory.Token; } this.ElementManager.SetSigned(tokenIndex); // We pass true if it is a signed supporting token, signed primary token or a SignedEndorsing token. We pass false if it is a SignedEncrypted Token. reader = this.ElementManager.GetReader(tokenIndex, isSignedToken); } } else reader = this.ElementManager.GetSignatureVerificationReader(referredId, this.EncryptBeforeSignMode); if (reader != null) { reference.EnsureDigestValidity(referredId, reader); reader.Close(); } } } if (!isPrimarySignature) { // We were given an id to verify and we have verified it. So just break out // of the loop. break; } } } // This check makes sure that if RequireSignedPrimaryToken is true (ProtectTokens is enabled on sbe) then the incoming message // should have the primary signature over the primary(signing)token. if (isPrimarySignature && this.RequireSignedPrimaryToken && !this.ElementManager.IsPrimaryTokenSigned) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SupportingTokenIsNotSigned, new IssuedSecurityTokenParameters()))); } // NOTE: On both client and server side, WCF quietly consumes protected tokens even if protect token is not enabled on sbe. // To change this behaviour add another check below and throw appropriate exception message. } void VerifySoapAttributeMatchForHeader(MessageHeaderInfo info, MessagePartSpecification signatureParts, XmlDictionaryReader reader) { if (!signatureParts.IsHeaderIncluded(info.Name, info.Namespace)) { return; } EnvelopeVersion currentVersion = this.Version.Envelope; EnvelopeVersion otherVersion = currentVersion == EnvelopeVersion.Soap11 ? EnvelopeVersion.Soap12 : EnvelopeVersion.Soap11; bool presentInCurrentVersion; bool presentInOtherVersion; presentInCurrentVersion = null != reader.GetAttribute(XD.MessageDictionary.MustUnderstand, currentVersion.DictionaryNamespace); presentInOtherVersion = null != reader.GetAttribute(XD.MessageDictionary.MustUnderstand, otherVersion.DictionaryNamespace); if (presentInOtherVersion && !presentInCurrentVersion) { throw TraceUtility.ThrowHelperError( new MessageSecurityException(SR.GetString( SR.InvalidAttributeInSignedHeader, info.Name, info.Namespace, XD.MessageDictionary.MustUnderstand, otherVersion.DictionaryNamespace, XD.MessageDictionary.MustUnderstand, currentVersion.DictionaryNamespace)), this.SecurityVerifiedMessage); } presentInCurrentVersion = null != reader.GetAttribute(currentVersion.DictionaryActor, currentVersion.DictionaryNamespace); presentInOtherVersion = null != reader.GetAttribute(otherVersion.DictionaryActor, otherVersion.DictionaryNamespace); if (presentInOtherVersion && !presentInCurrentVersion) { throw TraceUtility.ThrowHelperError( new MessageSecurityException(SR.GetString( SR.InvalidAttributeInSignedHeader, info.Name, info.Namespace, otherVersion.DictionaryActor, otherVersion.DictionaryNamespace, currentVersion.DictionaryActor, currentVersion.DictionaryNamespace)), this.SecurityVerifiedMessage); } } } }