public override void MarkElements(ReceiveSecurityHeaderElementManager elementManager, bool messageSecurityMode) { bool primarySignatureFound = false; for (int position = 0; position < elementManager.Count; position++) { ReceiveSecurityHeaderEntry entry; elementManager.GetElementEntry(position, out entry); if (entry.elementCategory == ReceiveSecurityHeaderElementCategory.Signature) { if (!messageSecurityMode) { elementManager.SetBindingMode(position, ReceiveSecurityHeaderBindingModes.Endorsing); continue; } SignedXml signedXml = (SignedXml)entry.element; StandardSignedInfo signedInfo = (StandardSignedInfo)signedXml.Signature.SignedInfo; bool targetsSignature = false; if (signedInfo.ReferenceCount == 1) { string uri = signedInfo[0].Uri; string id; if (uri != null && uri.Length > 1 && uri[0] == '#') { id = uri.Substring(1); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new MessageSecurityException(SR.GetString(SR.UnableToResolveReferenceUriForSignature, uri))); } for (int j = 0; j < elementManager.Count; j++) { ReceiveSecurityHeaderEntry inner; elementManager.GetElementEntry(j, out inner); if (j != position && inner.elementCategory == ReceiveSecurityHeaderElementCategory.Signature && inner.id == id) { targetsSignature = true; break; } } } if (targetsSignature) { elementManager.SetBindingMode(position, ReceiveSecurityHeaderBindingModes.Endorsing); continue; } else { if (primarySignatureFound) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.AtMostOnePrimarySignatureInReceiveSecurityHeader))); } primarySignatureFound = true; elementManager.SetBindingMode(position, ReceiveSecurityHeaderBindingModes.Primary); continue; } } } }
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 <SecurityKey> 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); 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 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. }
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 <SecurityKey> 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); }