2015-04-07 09:35:12 +01:00
//----------------------------------------------------------
// 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 < string > 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 < SymmetricSecurityKey > ( 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 ) )
2016-02-22 11:00:01 -05:00
{
2015-04-07 09:35:12 +01:00
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 ;
}
2016-02-22 11:00:01 -05:00
}
2015-04-07 09:35:12 +01:00
}
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 < RsaKeyIdentifierClause > ( out rsaClause ) )
{
RsaSecurityTokenAuthenticator rsaAuthenticator = FindAllowedAuthenticator < RsaSecurityTokenAuthenticator > ( false ) ;
if ( rsaAuthenticator ! = null )
{
token = new RsaSecurityToken ( rsaClause . Rsa ) ;
ReadOnlyCollection < IAuthorizationPolicy > 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 < string > ( 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 < 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 ) ;
2016-02-22 11:00:01 -05:00
// 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 ) ;
}
2015-04-07 09:35:12 +01:00
}
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 ;
}
}
}
2016-02-22 11:00:01 -05:00
// This check makes sure that if RequireSignedPrimaryToken is true (ProtectTokens is enabled on sbe) then the incoming message
2015-04-07 09:35:12 +01:00
// 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 ) ;
}
}
}
}