e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
2197 lines
96 KiB
C#
2197 lines
96 KiB
C#
//----------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Security
|
|
{
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.IdentityModel.Policy;
|
|
using System.IdentityModel.Selectors;
|
|
using System.IdentityModel.Tokens;
|
|
using System.Security.Authentication.ExtendedProtection;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.ServiceModel;
|
|
using System.ServiceModel.Channels;
|
|
using System.ServiceModel.Description;
|
|
using System.ServiceModel.Security.Tokens;
|
|
using System.ServiceModel.Diagnostics;
|
|
using System.Runtime;
|
|
using System.Xml;
|
|
using ISignatureValueSecurityElement = System.IdentityModel.ISignatureValueSecurityElement;
|
|
using SignatureResourcePool = System.IdentityModel.SignatureResourcePool;
|
|
using SignedXml = System.IdentityModel.SignedXml;
|
|
using System.Runtime.Diagnostics;
|
|
using System.ServiceModel.Diagnostics.Application;
|
|
|
|
abstract class ReceiveSecurityHeader : SecurityHeader
|
|
{
|
|
// client->server symmetric binding case: only primaryTokenAuthenticator is set
|
|
// server->client symmetric binding case: only primary token is set
|
|
// asymmetric binding case: primaryTokenAuthenticator and wrapping token is set
|
|
|
|
SecurityTokenAuthenticator primaryTokenAuthenticator;
|
|
bool allowFirstTokenMismatch;
|
|
SecurityToken outOfBandPrimaryToken;
|
|
IList<SecurityToken> outOfBandPrimaryTokenCollection;
|
|
SecurityTokenParameters primaryTokenParameters;
|
|
TokenTracker primaryTokenTracker;
|
|
SecurityToken wrappingToken;
|
|
SecurityTokenParameters wrappingTokenParameters;
|
|
SecurityToken expectedEncryptionToken;
|
|
SecurityTokenParameters expectedEncryptionTokenParameters;
|
|
SecurityTokenAuthenticator derivedTokenAuthenticator;
|
|
// assumes that the caller has done the check for uniqueness of types
|
|
IList<SupportingTokenAuthenticatorSpecification> supportingTokenAuthenticators;
|
|
ChannelBinding channelBinding;
|
|
ExtendedProtectionPolicy extendedProtectionPolicy;
|
|
|
|
bool expectEncryption = true;
|
|
// caller should precompute and set expectations
|
|
bool expectBasicTokens;
|
|
bool expectSignedTokens;
|
|
bool expectEndorsingTokens;
|
|
bool expectSignature = true;
|
|
bool requireSignedPrimaryToken;
|
|
bool expectSignatureConfirmation;
|
|
// maps from token to wire form (for basic and signed), and also tracks operations done
|
|
// maps from supporting token parameter to the operations done for that token type
|
|
List<TokenTracker> supportingTokenTrackers;
|
|
|
|
SignatureConfirmations receivedSignatureValues;
|
|
SignatureConfirmations receivedSignatureConfirmations;
|
|
List<SecurityTokenAuthenticator> allowedAuthenticators;
|
|
|
|
SecurityTokenAuthenticator pendingSupportingTokenAuthenticator;
|
|
|
|
WrappedKeySecurityToken wrappedKeyToken;
|
|
Collection<SecurityToken> basicTokens;
|
|
Collection<SecurityToken> signedTokens;
|
|
Collection<SecurityToken> endorsingTokens;
|
|
Collection<SecurityToken> signedEndorsingTokens;
|
|
Dictionary<SecurityToken, ReadOnlyCollection<IAuthorizationPolicy>> tokenPoliciesMapping;
|
|
List<SecurityTokenAuthenticator> wrappedKeyAuthenticator;
|
|
SecurityTimestamp timestamp;
|
|
SecurityHeaderTokenResolver universalTokenResolver;
|
|
SecurityHeaderTokenResolver primaryTokenResolver;
|
|
ReadOnlyCollection<SecurityTokenResolver> outOfBandTokenResolver;
|
|
SecurityTokenResolver combinedUniversalTokenResolver;
|
|
SecurityTokenResolver combinedPrimaryTokenResolver;
|
|
|
|
readonly int headerIndex;
|
|
XmlAttributeHolder[] securityElementAttributes;
|
|
OrderTracker orderTracker = new OrderTracker();
|
|
OperationTracker signatureTracker = new OperationTracker();
|
|
OperationTracker encryptionTracker = new OperationTracker();
|
|
|
|
ReceiveSecurityHeaderElementManager elementManager;
|
|
|
|
int maxDerivedKeys;
|
|
int numDerivedKeys;
|
|
int maxDerivedKeyLength;
|
|
bool enforceDerivedKeyRequirement = true;
|
|
|
|
NonceCache nonceCache;
|
|
TimeSpan replayWindow;
|
|
TimeSpan clockSkew;
|
|
byte[] primarySignatureValue;
|
|
TimeoutHelper timeoutHelper;
|
|
SecurityVerifiedMessage securityVerifiedMessage;
|
|
long maxReceivedMessageSize = TransportDefaults.MaxReceivedMessageSize;
|
|
XmlDictionaryReaderQuotas readerQuotas;
|
|
MessageProtectionOrder protectionOrder;
|
|
bool hasAtLeastOneSupportingTokenExpectedToBeSigned;
|
|
bool hasEndorsingOrSignedEndorsingSupportingTokens;
|
|
SignatureResourcePool resourcePool;
|
|
bool replayDetectionEnabled = false;
|
|
|
|
bool hasAtLeastOneItemInsideSecurityHeaderEncrypted = false;
|
|
|
|
const int AppendPosition = -1;
|
|
|
|
EventTraceActivity eventTraceActivity;
|
|
|
|
protected ReceiveSecurityHeader(Message message, string actor, bool mustUnderstand, bool relay,
|
|
SecurityStandardsManager standardsManager,
|
|
SecurityAlgorithmSuite algorithmSuite,
|
|
int headerIndex,
|
|
MessageDirection direction)
|
|
: base(message, actor, mustUnderstand, relay, standardsManager, algorithmSuite, direction)
|
|
{
|
|
this.headerIndex = headerIndex;
|
|
this.elementManager = new ReceiveSecurityHeaderElementManager(this);
|
|
}
|
|
|
|
public Collection<SecurityToken> BasicSupportingTokens
|
|
{
|
|
get
|
|
{
|
|
return this.basicTokens;
|
|
}
|
|
}
|
|
|
|
public Collection<SecurityToken> SignedSupportingTokens
|
|
{
|
|
get
|
|
{
|
|
return this.signedTokens;
|
|
}
|
|
}
|
|
|
|
public Collection<SecurityToken> EndorsingSupportingTokens
|
|
{
|
|
get
|
|
{
|
|
return this.endorsingTokens;
|
|
}
|
|
}
|
|
|
|
public ReceiveSecurityHeaderElementManager ElementManager
|
|
{
|
|
get
|
|
{
|
|
return this.elementManager;
|
|
}
|
|
}
|
|
|
|
public Collection<SecurityToken> SignedEndorsingSupportingTokens
|
|
{
|
|
get
|
|
{
|
|
return this.signedEndorsingTokens;
|
|
}
|
|
}
|
|
|
|
public SecurityTokenAuthenticator DerivedTokenAuthenticator
|
|
{
|
|
get
|
|
{
|
|
return this.derivedTokenAuthenticator;
|
|
}
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.derivedTokenAuthenticator = value;
|
|
}
|
|
}
|
|
|
|
public List<SecurityTokenAuthenticator> WrappedKeySecurityTokenAuthenticator
|
|
{
|
|
get
|
|
{
|
|
return this.wrappedKeyAuthenticator;
|
|
}
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.wrappedKeyAuthenticator = value;
|
|
}
|
|
}
|
|
|
|
public bool EnforceDerivedKeyRequirement
|
|
{
|
|
get
|
|
{
|
|
return this.enforceDerivedKeyRequirement;
|
|
}
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.enforceDerivedKeyRequirement = value;
|
|
}
|
|
}
|
|
|
|
public byte[] PrimarySignatureValue
|
|
{
|
|
get { return this.primarySignatureValue; }
|
|
}
|
|
|
|
public bool EncryptBeforeSignMode
|
|
{
|
|
get { return this.orderTracker.EncryptBeforeSignMode; }
|
|
}
|
|
|
|
public SecurityToken EncryptionToken
|
|
{
|
|
get { return this.encryptionTracker.Token; }
|
|
}
|
|
|
|
public bool ExpectBasicTokens
|
|
{
|
|
get { return this.expectBasicTokens; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.expectBasicTokens = value;
|
|
}
|
|
}
|
|
|
|
public bool ReplayDetectionEnabled
|
|
{
|
|
get { return this.replayDetectionEnabled; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.replayDetectionEnabled = value;
|
|
}
|
|
}
|
|
|
|
public bool ExpectEncryption
|
|
{
|
|
get { return this.expectEncryption; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.expectEncryption = value;
|
|
}
|
|
}
|
|
|
|
public bool ExpectSignature
|
|
{
|
|
get { return this.expectSignature; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.expectSignature = value;
|
|
}
|
|
}
|
|
|
|
public bool ExpectSignatureConfirmation
|
|
{
|
|
get { return this.expectSignatureConfirmation; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.expectSignatureConfirmation = value;
|
|
}
|
|
}
|
|
|
|
public bool ExpectSignedTokens
|
|
{
|
|
get { return this.expectSignedTokens; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.expectSignedTokens = value;
|
|
}
|
|
}
|
|
|
|
public bool RequireSignedPrimaryToken
|
|
{
|
|
get { return this.requireSignedPrimaryToken; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.requireSignedPrimaryToken = value;
|
|
}
|
|
}
|
|
|
|
public bool ExpectEndorsingTokens
|
|
{
|
|
get { return this.expectEndorsingTokens; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.expectEndorsingTokens = value;
|
|
}
|
|
}
|
|
|
|
public bool HasAtLeastOneItemInsideSecurityHeaderEncrypted
|
|
{
|
|
get { return this.hasAtLeastOneItemInsideSecurityHeaderEncrypted; }
|
|
set { this.hasAtLeastOneItemInsideSecurityHeaderEncrypted = value; }
|
|
}
|
|
|
|
public SecurityHeaderTokenResolver PrimaryTokenResolver
|
|
{
|
|
get
|
|
{
|
|
return this.primaryTokenResolver;
|
|
}
|
|
}
|
|
|
|
public SecurityTokenResolver CombinedUniversalTokenResolver
|
|
{
|
|
get { return this.combinedUniversalTokenResolver; }
|
|
}
|
|
|
|
public SecurityTokenResolver CombinedPrimaryTokenResolver
|
|
{
|
|
get { return this.combinedPrimaryTokenResolver; }
|
|
}
|
|
|
|
protected EventTraceActivity EventTraceActivity
|
|
{
|
|
get
|
|
{
|
|
if (this.eventTraceActivity == null && FxTrace.Trace.IsEnd2EndActivityTracingEnabled)
|
|
{
|
|
this.eventTraceActivity = EventTraceActivityHelper.TryExtractActivity((OperationContext.Current != null) ? OperationContext.Current.IncomingMessage : null);
|
|
}
|
|
|
|
return this.eventTraceActivity;
|
|
}
|
|
}
|
|
|
|
protected void VerifySignatureEncryption()
|
|
{
|
|
if ((this.protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature) &&
|
|
(!this.orderTracker.AllSignaturesEncrypted))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.PrimarySignatureIsRequiredToBeEncrypted)));
|
|
}
|
|
}
|
|
|
|
internal int HeaderIndex
|
|
{
|
|
get { return this.headerIndex; }
|
|
}
|
|
|
|
internal long MaxReceivedMessageSize
|
|
{
|
|
get
|
|
{
|
|
return this.maxReceivedMessageSize;
|
|
}
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.maxReceivedMessageSize = value;
|
|
}
|
|
}
|
|
|
|
internal XmlDictionaryReaderQuotas ReaderQuotas
|
|
{
|
|
get { return this.readerQuotas; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
|
|
if (value == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
|
|
|
|
this.readerQuotas = value;
|
|
}
|
|
}
|
|
|
|
public override string Name
|
|
{
|
|
get { return this.StandardsManager.SecurityVersion.HeaderName.Value; }
|
|
}
|
|
|
|
public override string Namespace
|
|
{
|
|
get { return this.StandardsManager.SecurityVersion.HeaderNamespace.Value; }
|
|
}
|
|
|
|
public Message ProcessedMessage
|
|
{
|
|
get { return this.Message; }
|
|
}
|
|
|
|
public MessagePartSpecification RequiredEncryptionParts
|
|
{
|
|
get { return this.encryptionTracker.Parts; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
if (value == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new ArgumentNullException("value"), this.Message);
|
|
}
|
|
if (!value.IsReadOnly)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new InvalidOperationException(
|
|
SR.GetString(SR.MessagePartSpecificationMustBeImmutable)), this.Message);
|
|
}
|
|
this.encryptionTracker.Parts = value;
|
|
}
|
|
}
|
|
|
|
public MessagePartSpecification RequiredSignatureParts
|
|
{
|
|
get { return this.signatureTracker.Parts; }
|
|
set
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
if (value == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new ArgumentNullException("value"), this.Message);
|
|
}
|
|
if (!value.IsReadOnly)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new InvalidOperationException(
|
|
SR.GetString(SR.MessagePartSpecificationMustBeImmutable)), this.Message);
|
|
}
|
|
this.signatureTracker.Parts = value;
|
|
}
|
|
}
|
|
|
|
protected SignatureResourcePool ResourcePool
|
|
{
|
|
get
|
|
{
|
|
if (this.resourcePool == null)
|
|
{
|
|
this.resourcePool = new SignatureResourcePool();
|
|
}
|
|
return this.resourcePool;
|
|
}
|
|
}
|
|
|
|
internal SecurityVerifiedMessage SecurityVerifiedMessage
|
|
{
|
|
get
|
|
{
|
|
return this.securityVerifiedMessage;
|
|
}
|
|
}
|
|
|
|
public SecurityToken SignatureToken
|
|
{
|
|
get { return this.signatureTracker.Token; }
|
|
}
|
|
|
|
public Dictionary<SecurityToken, ReadOnlyCollection<IAuthorizationPolicy>> SecurityTokenAuthorizationPoliciesMapping
|
|
{
|
|
get
|
|
{
|
|
if (this.tokenPoliciesMapping == null)
|
|
{
|
|
this.tokenPoliciesMapping = new Dictionary<SecurityToken, ReadOnlyCollection<IAuthorizationPolicy>>();
|
|
}
|
|
return this.tokenPoliciesMapping;
|
|
}
|
|
}
|
|
|
|
public SecurityTimestamp Timestamp
|
|
{
|
|
get { return this.timestamp; }
|
|
}
|
|
|
|
public int MaxDerivedKeyLength
|
|
{
|
|
get
|
|
{
|
|
return this.maxDerivedKeyLength;
|
|
}
|
|
}
|
|
|
|
internal XmlDictionaryReader CreateSecurityHeaderReader()
|
|
{
|
|
return this.securityVerifiedMessage.GetReaderAtSecurityHeader();
|
|
}
|
|
|
|
public SignatureConfirmations GetSentSignatureConfirmations()
|
|
{
|
|
return this.receivedSignatureConfirmations;
|
|
}
|
|
|
|
public void ConfigureSymmetricBindingServerReceiveHeader(SecurityTokenAuthenticator primaryTokenAuthenticator, SecurityTokenParameters primaryTokenParameters, IList<SupportingTokenAuthenticatorSpecification> supportingTokenAuthenticators)
|
|
{
|
|
this.primaryTokenAuthenticator = primaryTokenAuthenticator;
|
|
this.primaryTokenParameters = primaryTokenParameters;
|
|
this.supportingTokenAuthenticators = supportingTokenAuthenticators;
|
|
}
|
|
|
|
// encrypted key case
|
|
public void ConfigureSymmetricBindingServerReceiveHeader(SecurityToken wrappingToken, SecurityTokenParameters wrappingTokenParameters, IList<SupportingTokenAuthenticatorSpecification> supportingTokenAuthenticators)
|
|
{
|
|
this.wrappingToken = wrappingToken;
|
|
this.wrappingTokenParameters = wrappingTokenParameters;
|
|
this.supportingTokenAuthenticators = supportingTokenAuthenticators;
|
|
}
|
|
|
|
public void ConfigureAsymmetricBindingServerReceiveHeader(SecurityTokenAuthenticator primaryTokenAuthenticator, SecurityTokenParameters primaryTokenParameters, SecurityToken wrappingToken, SecurityTokenParameters wrappingTokenParameters, IList<SupportingTokenAuthenticatorSpecification> supportingTokenAuthenticators)
|
|
{
|
|
this.primaryTokenAuthenticator = primaryTokenAuthenticator;
|
|
this.primaryTokenParameters = primaryTokenParameters;
|
|
this.wrappingToken = wrappingToken;
|
|
this.wrappingTokenParameters = wrappingTokenParameters;
|
|
this.supportingTokenAuthenticators = supportingTokenAuthenticators;
|
|
}
|
|
|
|
public void ConfigureTransportBindingServerReceiveHeader(IList<SupportingTokenAuthenticatorSpecification> supportingTokenAuthenticators)
|
|
{
|
|
this.supportingTokenAuthenticators = supportingTokenAuthenticators;
|
|
}
|
|
|
|
public void ConfigureAsymmetricBindingClientReceiveHeader(SecurityToken primaryToken, SecurityTokenParameters primaryTokenParameters, SecurityToken encryptionToken, SecurityTokenParameters encryptionTokenParameters, SecurityTokenAuthenticator primaryTokenAuthenticator)
|
|
{
|
|
this.outOfBandPrimaryToken = primaryToken;
|
|
this.primaryTokenParameters = primaryTokenParameters;
|
|
this.primaryTokenAuthenticator = primaryTokenAuthenticator;
|
|
this.allowFirstTokenMismatch = primaryTokenAuthenticator != null;
|
|
if (encryptionToken != null && !SecurityUtils.HasSymmetricSecurityKey(encryptionToken))
|
|
{
|
|
this.wrappingToken = encryptionToken;
|
|
this.wrappingTokenParameters = encryptionTokenParameters;
|
|
}
|
|
else
|
|
{
|
|
this.expectedEncryptionToken = encryptionToken;
|
|
this.expectedEncryptionTokenParameters = encryptionTokenParameters;
|
|
}
|
|
}
|
|
|
|
public void ConfigureSymmetricBindingClientReceiveHeader(SecurityToken primaryToken, SecurityTokenParameters primaryTokenParameters)
|
|
{
|
|
this.outOfBandPrimaryToken = primaryToken;
|
|
this.primaryTokenParameters = primaryTokenParameters;
|
|
}
|
|
|
|
public void ConfigureSymmetricBindingClientReceiveHeader(IList<SecurityToken> primaryTokens, SecurityTokenParameters primaryTokenParameters)
|
|
{
|
|
this.outOfBandPrimaryTokenCollection = primaryTokens;
|
|
this.primaryTokenParameters = primaryTokenParameters;
|
|
}
|
|
|
|
public void ConfigureOutOfBandTokenResolver(ReadOnlyCollection<SecurityTokenResolver> outOfBandResolvers)
|
|
{
|
|
if (outOfBandResolvers == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("outOfBandResolvers");
|
|
if (outOfBandResolvers.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
this.outOfBandTokenResolver = outOfBandResolvers;
|
|
}
|
|
|
|
protected abstract EncryptedData ReadSecurityHeaderEncryptedItem(XmlDictionaryReader reader, bool readXmlreferenceKeyInfoClause);
|
|
|
|
protected abstract byte[] DecryptSecurityHeaderElement(EncryptedData encryptedData, WrappedKeySecurityToken wrappedKeyToken, out SecurityToken encryptionToken);
|
|
|
|
protected abstract WrappedKeySecurityToken DecryptWrappedKey(XmlDictionaryReader reader);
|
|
|
|
public SignatureConfirmations GetSentSignatureValues()
|
|
{
|
|
return this.receivedSignatureValues;
|
|
}
|
|
|
|
protected abstract bool IsReaderAtEncryptedKey(XmlDictionaryReader reader);
|
|
|
|
protected abstract bool IsReaderAtEncryptedData(XmlDictionaryReader reader);
|
|
|
|
protected abstract bool IsReaderAtReferenceList(XmlDictionaryReader reader);
|
|
|
|
protected abstract bool IsReaderAtSignature(XmlDictionaryReader reader);
|
|
|
|
protected abstract bool IsReaderAtSecurityTokenReference(XmlDictionaryReader reader);
|
|
|
|
protected abstract void OnDecryptionOfSecurityHeaderItemRequiringReferenceListEntry(string id);
|
|
|
|
void MarkHeaderAsUnderstood()
|
|
{
|
|
// header decryption does not reorder or delete headers
|
|
MessageHeaderInfo header = this.Message.Headers[this.headerIndex];
|
|
Fx.Assert(header.Name == this.Name && header.Namespace == this.Namespace && header.Actor == this.Actor, "security header index mismatch");
|
|
Message.Headers.UnderstoodHeaders.Add(header);
|
|
}
|
|
|
|
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
|
|
{
|
|
this.StandardsManager.SecurityVersion.WriteStartHeader(writer);
|
|
XmlAttributeHolder[] attributes = this.securityElementAttributes;
|
|
for (int i = 0; i < attributes.Length; ++i)
|
|
{
|
|
writer.WriteAttributeString(attributes[i].Prefix, attributes[i].LocalName, attributes[i].NamespaceUri, attributes[i].Value);
|
|
}
|
|
}
|
|
|
|
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
|
|
{
|
|
XmlDictionaryReader securityHeaderReader = GetReaderAtSecurityHeader();
|
|
securityHeaderReader.ReadStartElement();
|
|
for (int i = 0; i < this.ElementManager.Count; ++i)
|
|
{
|
|
ReceiveSecurityHeaderEntry entry;
|
|
this.ElementManager.GetElementEntry(i, out entry);
|
|
XmlDictionaryReader reader = null;
|
|
if (entry.encrypted)
|
|
{
|
|
reader = this.ElementManager.GetReader(i, false);
|
|
writer.WriteNode(reader, false);
|
|
reader.Close();
|
|
securityHeaderReader.Skip();
|
|
}
|
|
else
|
|
{
|
|
writer.WriteNode(securityHeaderReader, false);
|
|
}
|
|
}
|
|
securityHeaderReader.Close();
|
|
}
|
|
|
|
XmlDictionaryReader GetReaderAtSecurityHeader()
|
|
{
|
|
XmlDictionaryReader reader = this.SecurityVerifiedMessage.GetReaderAtFirstHeader();
|
|
for (int i = 0; i < this.HeaderIndex; ++i)
|
|
{
|
|
reader.Skip();
|
|
}
|
|
|
|
return reader;
|
|
}
|
|
|
|
Collection<SecurityToken> EnsureSupportingTokens(ref Collection<SecurityToken> list)
|
|
{
|
|
if (list == null)
|
|
list = new Collection<SecurityToken>();
|
|
return list;
|
|
}
|
|
|
|
void VerifySupportingToken(TokenTracker tracker)
|
|
{
|
|
if (tracker == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tracker");
|
|
|
|
Fx.Assert(tracker.spec != null, "Supporting token trackers cannot have null specification.");
|
|
|
|
SupportingTokenAuthenticatorSpecification spec = tracker.spec;
|
|
|
|
if (tracker.token == null)
|
|
{
|
|
if (spec.IsTokenOptional)
|
|
return;
|
|
else
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingTokenNotProvided, spec.TokenParameters, spec.SecurityTokenAttachmentMode)));
|
|
}
|
|
switch (spec.SecurityTokenAttachmentMode)
|
|
{
|
|
case SecurityTokenAttachmentMode.Endorsing:
|
|
if (!tracker.IsEndorsing)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingTokenIsNotEndorsing, spec.TokenParameters)));
|
|
}
|
|
if (this.EnforceDerivedKeyRequirement && spec.TokenParameters.RequireDerivedKeys && !spec.TokenParameters.HasAsymmetricKey && !tracker.IsDerivedFrom)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingSignatureIsNotDerivedFrom, spec.TokenParameters)));
|
|
}
|
|
EnsureSupportingTokens(ref endorsingTokens).Add(tracker.token);
|
|
break;
|
|
case SecurityTokenAttachmentMode.Signed:
|
|
if (!tracker.IsSigned && this.RequireMessageProtection)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingTokenIsNotSigned, spec.TokenParameters)));
|
|
}
|
|
EnsureSupportingTokens(ref signedTokens).Add(tracker.token);
|
|
break;
|
|
case SecurityTokenAttachmentMode.SignedEncrypted:
|
|
if (!tracker.IsSigned && this.RequireMessageProtection)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingTokenIsNotSigned, spec.TokenParameters)));
|
|
}
|
|
if (!tracker.IsEncrypted && this.RequireMessageProtection)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingTokenIsNotEncrypted, spec.TokenParameters)));
|
|
}
|
|
EnsureSupportingTokens(ref basicTokens).Add(tracker.token);
|
|
break;
|
|
case SecurityTokenAttachmentMode.SignedEndorsing:
|
|
if (!tracker.IsSigned && this.RequireMessageProtection)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingTokenIsNotSigned, spec.TokenParameters)));
|
|
}
|
|
if (!tracker.IsEndorsing)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingTokenIsNotEndorsing, spec.TokenParameters)));
|
|
}
|
|
if (this.EnforceDerivedKeyRequirement && spec.TokenParameters.RequireDerivedKeys && !spec.TokenParameters.HasAsymmetricKey && !tracker.IsDerivedFrom)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SupportingSignatureIsNotDerivedFrom, spec.TokenParameters)));
|
|
}
|
|
EnsureSupportingTokens(ref signedEndorsingTokens).Add(tracker.token);
|
|
break;
|
|
|
|
default:
|
|
Fx.Assert("Unknown token attachment mode " + spec.SecurityTokenAttachmentMode);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnknownTokenAttachmentMode, spec.SecurityTokenAttachmentMode)));
|
|
}
|
|
}
|
|
|
|
// replay detection done if enableReplayDetection is set to true.
|
|
public void SetTimeParameters(NonceCache nonceCache, TimeSpan replayWindow, TimeSpan clockSkew)
|
|
{
|
|
this.nonceCache = nonceCache;
|
|
this.replayWindow = replayWindow;
|
|
this.clockSkew = clockSkew;
|
|
}
|
|
|
|
public void Process(TimeSpan timeout, ChannelBinding channelBinding, ExtendedProtectionPolicy extendedProtectionPolicy)
|
|
{
|
|
Fx.Assert(this.ReaderQuotas != null, "Reader quotas must be set before processing");
|
|
MessageProtectionOrder actualProtectionOrder = this.protectionOrder;
|
|
bool wasProtectionOrderDowngraded = false;
|
|
if (this.protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature)
|
|
{
|
|
if (this.RequiredEncryptionParts == null || !this.RequiredEncryptionParts.IsBodyIncluded)
|
|
{
|
|
// Let's downgrade for now. If after signature verification we find a header that
|
|
// is signed and encrypted, we will check for signature encryption too.
|
|
actualProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
|
|
wasProtectionOrderDowngraded = true;
|
|
}
|
|
}
|
|
|
|
this.channelBinding = channelBinding;
|
|
this.extendedProtectionPolicy = extendedProtectionPolicy;
|
|
this.orderTracker.SetRequiredProtectionOrder(actualProtectionOrder);
|
|
|
|
SetProcessingStarted();
|
|
this.timeoutHelper = new TimeoutHelper(timeout);
|
|
this.Message = this.securityVerifiedMessage = new SecurityVerifiedMessage(this.Message, this);
|
|
XmlDictionaryReader reader = CreateSecurityHeaderReader();
|
|
reader.MoveToStartElement();
|
|
if (reader.IsEmptyElement)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SecurityHeaderIsEmpty)), this.Message);
|
|
}
|
|
if (this.RequireMessageProtection)
|
|
{
|
|
this.securityElementAttributes = XmlAttributeHolder.ReadAttributes(reader);
|
|
}
|
|
else
|
|
{
|
|
this.securityElementAttributes = XmlAttributeHolder.emptyArray;
|
|
}
|
|
reader.ReadStartElement();
|
|
|
|
if (this.primaryTokenParameters != null)
|
|
{
|
|
this.primaryTokenTracker = new TokenTracker(null, this.outOfBandPrimaryToken, this.allowFirstTokenMismatch);
|
|
}
|
|
// universalTokenResolver is used for resolving tokens
|
|
universalTokenResolver = new SecurityHeaderTokenResolver(this);
|
|
// primary token resolver is used for resolving primary signature and decryption
|
|
primaryTokenResolver = new SecurityHeaderTokenResolver(this);
|
|
if (this.outOfBandPrimaryToken != null)
|
|
{
|
|
universalTokenResolver.Add(this.outOfBandPrimaryToken, SecurityTokenReferenceStyle.External, this.primaryTokenParameters);
|
|
primaryTokenResolver.Add(this.outOfBandPrimaryToken, SecurityTokenReferenceStyle.External, this.primaryTokenParameters);
|
|
}
|
|
else if (this.outOfBandPrimaryTokenCollection != null)
|
|
{
|
|
for (int i = 0; i < this.outOfBandPrimaryTokenCollection.Count; ++i)
|
|
{
|
|
universalTokenResolver.Add(this.outOfBandPrimaryTokenCollection[i], SecurityTokenReferenceStyle.External, this.primaryTokenParameters);
|
|
primaryTokenResolver.Add(this.outOfBandPrimaryTokenCollection[i], SecurityTokenReferenceStyle.External, this.primaryTokenParameters);
|
|
}
|
|
}
|
|
if (this.wrappingToken != null)
|
|
{
|
|
universalTokenResolver.ExpectedWrapper = this.wrappingToken;
|
|
universalTokenResolver.ExpectedWrapperTokenParameters = this.wrappingTokenParameters;
|
|
primaryTokenResolver.ExpectedWrapper = this.wrappingToken;
|
|
primaryTokenResolver.ExpectedWrapperTokenParameters = this.wrappingTokenParameters;
|
|
}
|
|
else if (expectedEncryptionToken != null)
|
|
{
|
|
universalTokenResolver.Add(expectedEncryptionToken, SecurityTokenReferenceStyle.External, expectedEncryptionTokenParameters);
|
|
primaryTokenResolver.Add(expectedEncryptionToken, SecurityTokenReferenceStyle.External, expectedEncryptionTokenParameters);
|
|
}
|
|
|
|
if (this.outOfBandTokenResolver == null)
|
|
{
|
|
this.combinedUniversalTokenResolver = this.universalTokenResolver;
|
|
this.combinedPrimaryTokenResolver = this.primaryTokenResolver;
|
|
}
|
|
else
|
|
{
|
|
this.combinedUniversalTokenResolver = new AggregateSecurityHeaderTokenResolver(this.universalTokenResolver, this.outOfBandTokenResolver);
|
|
this.combinedPrimaryTokenResolver = new AggregateSecurityHeaderTokenResolver(this.primaryTokenResolver, this.outOfBandTokenResolver);
|
|
}
|
|
|
|
allowedAuthenticators = new List<SecurityTokenAuthenticator>();
|
|
if (this.primaryTokenAuthenticator != null)
|
|
{
|
|
allowedAuthenticators.Add(this.primaryTokenAuthenticator);
|
|
}
|
|
if (this.DerivedTokenAuthenticator != null)
|
|
{
|
|
allowedAuthenticators.Add(this.DerivedTokenAuthenticator);
|
|
}
|
|
pendingSupportingTokenAuthenticator = null;
|
|
int numSupportingTokensRequiringDerivation = 0;
|
|
if (this.supportingTokenAuthenticators != null && this.supportingTokenAuthenticators.Count > 0)
|
|
{
|
|
this.supportingTokenTrackers = new List<TokenTracker>(this.supportingTokenAuthenticators.Count);
|
|
for (int i = 0; i < this.supportingTokenAuthenticators.Count; ++i)
|
|
{
|
|
SupportingTokenAuthenticatorSpecification spec = this.supportingTokenAuthenticators[i];
|
|
switch (spec.SecurityTokenAttachmentMode)
|
|
{
|
|
case SecurityTokenAttachmentMode.Endorsing:
|
|
this.hasEndorsingOrSignedEndorsingSupportingTokens = true;
|
|
break;
|
|
case SecurityTokenAttachmentMode.Signed:
|
|
this.hasAtLeastOneSupportingTokenExpectedToBeSigned = true;
|
|
break;
|
|
case SecurityTokenAttachmentMode.SignedEndorsing:
|
|
this.hasEndorsingOrSignedEndorsingSupportingTokens = true;
|
|
this.hasAtLeastOneSupportingTokenExpectedToBeSigned = true;
|
|
break;
|
|
case SecurityTokenAttachmentMode.SignedEncrypted:
|
|
this.hasAtLeastOneSupportingTokenExpectedToBeSigned = true;
|
|
break;
|
|
}
|
|
|
|
if ((this.primaryTokenAuthenticator != null) && (this.primaryTokenAuthenticator.GetType().Equals(spec.TokenAuthenticator.GetType())))
|
|
{
|
|
pendingSupportingTokenAuthenticator = spec.TokenAuthenticator;
|
|
}
|
|
else
|
|
{
|
|
allowedAuthenticators.Add(spec.TokenAuthenticator);
|
|
}
|
|
if (spec.TokenParameters.RequireDerivedKeys && !spec.TokenParameters.HasAsymmetricKey &&
|
|
(spec.SecurityTokenAttachmentMode == SecurityTokenAttachmentMode.Endorsing || spec.SecurityTokenAttachmentMode == SecurityTokenAttachmentMode.SignedEndorsing))
|
|
{
|
|
++numSupportingTokensRequiringDerivation;
|
|
}
|
|
this.supportingTokenTrackers.Add(new TokenTracker(spec));
|
|
}
|
|
}
|
|
|
|
if (this.DerivedTokenAuthenticator != null)
|
|
{
|
|
// we expect key derivation. Compute quotas for derived keys
|
|
int maxKeyDerivationLengthInBits = this.AlgorithmSuite.DefaultEncryptionKeyDerivationLength >= this.AlgorithmSuite.DefaultSignatureKeyDerivationLength ?
|
|
this.AlgorithmSuite.DefaultEncryptionKeyDerivationLength : this.AlgorithmSuite.DefaultSignatureKeyDerivationLength;
|
|
this.maxDerivedKeyLength = maxKeyDerivationLengthInBits / 8;
|
|
// the upper bound of derived keys is (1 for primary signature + 1 for encryption + supporting token signatures requiring derivation)*2
|
|
// the multiplication by 2 is to take care of interop scenarios that may arise that require more derived keys than the lower bound.
|
|
this.maxDerivedKeys = (1 + 1 + numSupportingTokensRequiringDerivation) * 2;
|
|
}
|
|
|
|
SecurityHeaderElementInferenceEngine engine = SecurityHeaderElementInferenceEngine.GetInferenceEngine(this.Layout);
|
|
engine.ExecuteProcessingPasses(this, reader);
|
|
if (this.RequireMessageProtection)
|
|
{
|
|
this.ElementManager.EnsureAllRequiredSecurityHeaderTargetsWereProtected();
|
|
ExecuteMessageProtectionPass(this.hasAtLeastOneSupportingTokenExpectedToBeSigned);
|
|
if (this.RequiredSignatureParts != null && this.SignatureToken == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.RequiredSignatureMissing)), this.Message);
|
|
}
|
|
}
|
|
|
|
EnsureDecryptionComplete();
|
|
|
|
this.signatureTracker.SetDerivationSourceIfRequired();
|
|
this.encryptionTracker.SetDerivationSourceIfRequired();
|
|
if (this.EncryptionToken != null)
|
|
{
|
|
if (wrappingToken != null)
|
|
{
|
|
if (!(this.EncryptionToken is WrappedKeySecurityToken) || ((WrappedKeySecurityToken)this.EncryptionToken).WrappingToken != this.wrappingToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.EncryptedKeyWasNotEncryptedWithTheRequiredEncryptingToken, this.wrappingToken)));
|
|
}
|
|
}
|
|
else if (expectedEncryptionToken != null)
|
|
{
|
|
if (this.EncryptionToken != expectedEncryptionToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MessageWasNotEncryptedWithTheRequiredEncryptingToken)));
|
|
}
|
|
}
|
|
else if (this.SignatureToken != null && this.EncryptionToken != this.SignatureToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SignatureAndEncryptionTokenMismatch, this.SignatureToken, this.EncryptionToken)));
|
|
}
|
|
}
|
|
|
|
// ensure that the primary signature was signed with derived keys if required
|
|
if (this.EnforceDerivedKeyRequirement)
|
|
{
|
|
if (this.SignatureToken != null)
|
|
{
|
|
if (this.primaryTokenParameters != null)
|
|
{
|
|
if (this.primaryTokenParameters.RequireDerivedKeys && !this.primaryTokenParameters.HasAsymmetricKey && !this.primaryTokenTracker.IsDerivedFrom)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.PrimarySignatureWasNotSignedByDerivedKey, this.primaryTokenParameters)));
|
|
}
|
|
}
|
|
else if (this.wrappingTokenParameters != null && this.wrappingTokenParameters.RequireDerivedKeys)
|
|
{
|
|
if (!this.signatureTracker.IsDerivedToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.PrimarySignatureWasNotSignedByDerivedWrappedKey, this.wrappingTokenParameters)));
|
|
}
|
|
}
|
|
}
|
|
|
|
// verify that the encryption is using key derivation
|
|
if (this.EncryptionToken != null)
|
|
{
|
|
if (wrappingTokenParameters != null)
|
|
{
|
|
if (wrappingTokenParameters.RequireDerivedKeys && !this.encryptionTracker.IsDerivedToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MessageWasNotEncryptedByDerivedWrappedKey, this.wrappingTokenParameters)));
|
|
}
|
|
}
|
|
else if (expectedEncryptionTokenParameters != null)
|
|
{
|
|
if (expectedEncryptionTokenParameters.RequireDerivedKeys && !this.encryptionTracker.IsDerivedToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MessageWasNotEncryptedByDerivedEncryptionToken, this.expectedEncryptionTokenParameters)));
|
|
}
|
|
}
|
|
else if (primaryTokenParameters != null && !primaryTokenParameters.HasAsymmetricKey && primaryTokenParameters.RequireDerivedKeys && !this.encryptionTracker.IsDerivedToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.MessageWasNotEncryptedByDerivedEncryptionToken, this.primaryTokenParameters)));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (wasProtectionOrderDowngraded && (this.BasicSupportingTokens != null) && (this.BasicSupportingTokens.Count > 0))
|
|
{
|
|
// Basic tokens are always signed and encrypted. So check if Signatures
|
|
// are encrypted as well.
|
|
this.VerifySignatureEncryption();
|
|
}
|
|
|
|
// verify all supporting token parameters have their requirements met
|
|
if (this.supportingTokenTrackers != null)
|
|
{
|
|
for (int i = 0; i < this.supportingTokenTrackers.Count; ++i)
|
|
{
|
|
VerifySupportingToken(this.supportingTokenTrackers[i]);
|
|
}
|
|
}
|
|
|
|
if (this.replayDetectionEnabled)
|
|
{
|
|
if (this.timestamp == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.NoTimestampAvailableInSecurityHeaderToDoReplayDetection)), this.Message);
|
|
}
|
|
if (this.primarySignatureValue == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.NoSignatureAvailableInSecurityHeaderToDoReplayDetection)), this.Message);
|
|
}
|
|
|
|
AddNonce(this.nonceCache, this.primarySignatureValue);
|
|
|
|
// if replay detection is on, redo creation range checks to ensure full coverage
|
|
this.timestamp.ValidateFreshness(this.replayWindow, this.clockSkew);
|
|
}
|
|
|
|
if (this.ExpectSignatureConfirmation)
|
|
{
|
|
this.ElementManager.VerifySignatureConfirmationWasFound();
|
|
}
|
|
|
|
MarkHeaderAsUnderstood();
|
|
}
|
|
|
|
static void AddNonce(NonceCache cache, byte[] nonce)
|
|
{
|
|
if (!cache.TryAddNonce(nonce))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.InvalidOrReplayedNonce), true));
|
|
}
|
|
}
|
|
|
|
static void CheckNonce(NonceCache cache, byte[] nonce)
|
|
{
|
|
if (cache.CheckNonce(nonce))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.InvalidOrReplayedNonce), true));
|
|
}
|
|
}
|
|
|
|
protected abstract void EnsureDecryptionComplete();
|
|
|
|
protected abstract void ExecuteMessageProtectionPass(bool hasAtLeastOneSupportingTokenExpectedToBeSigned);
|
|
|
|
internal void ExecuteSignatureEncryptionProcessingPass()
|
|
{
|
|
for (int position = 0; position < this.elementManager.Count; position++)
|
|
{
|
|
ReceiveSecurityHeaderEntry entry;
|
|
this.elementManager.GetElementEntry(position, out entry);
|
|
switch (entry.elementCategory)
|
|
{
|
|
case ReceiveSecurityHeaderElementCategory.Signature:
|
|
if (entry.bindingMode == ReceiveSecurityHeaderBindingModes.Primary)
|
|
{
|
|
ProcessPrimarySignature((SignedXml)entry.element, entry.encrypted);
|
|
}
|
|
else
|
|
{
|
|
ProcessSupportingSignature((SignedXml)entry.element, entry.encrypted);
|
|
}
|
|
break;
|
|
case ReceiveSecurityHeaderElementCategory.ReferenceList:
|
|
ProcessReferenceList((ReferenceList)entry.element);
|
|
break;
|
|
case ReceiveSecurityHeaderElementCategory.Token:
|
|
WrappedKeySecurityToken wrappedKeyToken = entry.element as WrappedKeySecurityToken;
|
|
if ((wrappedKeyToken != null) && (wrappedKeyToken.ReferenceList != null))
|
|
{
|
|
Fx.Assert(this.Layout != SecurityHeaderLayout.Strict, "Invalid Calling sequence. This method assumes it will be called only during Lax mode.");
|
|
// ExecuteSignatureEncryptionProcessingPass is called only durng Lax mode. In this
|
|
// case when we have a EncryptedKey with a ReferencList inside it, we would not
|
|
// have processed the ReferenceList during reading pass. Process this here.
|
|
ProcessReferenceList(wrappedKeyToken.ReferenceList, wrappedKeyToken);
|
|
}
|
|
break;
|
|
case ReceiveSecurityHeaderElementCategory.Timestamp:
|
|
case ReceiveSecurityHeaderElementCategory.EncryptedKey:
|
|
case ReceiveSecurityHeaderElementCategory.EncryptedData:
|
|
case ReceiveSecurityHeaderElementCategory.SignatureConfirmation:
|
|
case ReceiveSecurityHeaderElementCategory.SecurityTokenReference:
|
|
// no op
|
|
break;
|
|
default:
|
|
Fx.Assert("invalid element category");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void ExecuteSubheaderDecryptionPass()
|
|
{
|
|
for (int position = 0; position < this.elementManager.Count; position++)
|
|
{
|
|
if (this.elementManager.GetElementCategory(position) == ReceiveSecurityHeaderElementCategory.EncryptedData)
|
|
{
|
|
EncryptedData encryptedData = this.elementManager.GetElement<EncryptedData>(position);
|
|
bool dummy = false;
|
|
ProcessEncryptedData(encryptedData, this.timeoutHelper.RemainingTime(), position, false, ref dummy);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void ExecuteReadingPass(XmlDictionaryReader reader)
|
|
{
|
|
int position = 0;
|
|
while (reader.IsStartElement())
|
|
{
|
|
if (IsReaderAtSignature(reader))
|
|
{
|
|
ReadSignature(reader, AppendPosition, null);
|
|
}
|
|
else if (IsReaderAtReferenceList(reader))
|
|
{
|
|
ReadReferenceList(reader);
|
|
}
|
|
else if (this.StandardsManager.WSUtilitySpecificationVersion.IsReaderAtTimestamp(reader))
|
|
{
|
|
ReadTimestamp(reader);
|
|
}
|
|
else if (IsReaderAtEncryptedKey(reader))
|
|
{
|
|
ReadEncryptedKey(reader, false);
|
|
}
|
|
else if (IsReaderAtEncryptedData(reader))
|
|
{
|
|
ReadEncryptedData(reader);
|
|
}
|
|
else if (this.StandardsManager.SecurityVersion.IsReaderAtSignatureConfirmation(reader))
|
|
{
|
|
ReadSignatureConfirmation(reader, AppendPosition, null);
|
|
}
|
|
else if (IsReaderAtSecurityTokenReference(reader))
|
|
{
|
|
ReadSecurityTokenReference(reader);
|
|
}
|
|
else
|
|
{
|
|
ReadToken(reader, AppendPosition, null, null, null, this.timeoutHelper.RemainingTime());
|
|
}
|
|
position++;
|
|
}
|
|
|
|
reader.ReadEndElement(); // wsse:Security
|
|
reader.Close();
|
|
}
|
|
|
|
internal void ExecuteFullPass(XmlDictionaryReader reader)
|
|
{
|
|
bool primarySignatureFound = !this.RequireMessageProtection;
|
|
int position = 0;
|
|
while (reader.IsStartElement())
|
|
{
|
|
if (IsReaderAtSignature(reader))
|
|
{
|
|
SignedXml signedXml = ReadSignature(reader, AppendPosition, null);
|
|
if (primarySignatureFound)
|
|
{
|
|
this.elementManager.SetBindingMode(position, ReceiveSecurityHeaderBindingModes.Endorsing);
|
|
ProcessSupportingSignature(signedXml, false);
|
|
}
|
|
else
|
|
{
|
|
primarySignatureFound = true;
|
|
this.elementManager.SetBindingMode(position, ReceiveSecurityHeaderBindingModes.Primary);
|
|
ProcessPrimarySignature(signedXml, false);
|
|
}
|
|
}
|
|
else if (IsReaderAtReferenceList(reader))
|
|
{
|
|
ReferenceList referenceList = ReadReferenceList(reader);
|
|
ProcessReferenceList(referenceList);
|
|
}
|
|
else if (this.StandardsManager.WSUtilitySpecificationVersion.IsReaderAtTimestamp(reader))
|
|
{
|
|
ReadTimestamp(reader);
|
|
}
|
|
else if (IsReaderAtEncryptedKey(reader))
|
|
{
|
|
ReadEncryptedKey(reader, true);
|
|
}
|
|
else if (IsReaderAtEncryptedData(reader))
|
|
{
|
|
EncryptedData encryptedData = ReadEncryptedData(reader);
|
|
ProcessEncryptedData(encryptedData, this.timeoutHelper.RemainingTime(), position, true, ref primarySignatureFound);
|
|
}
|
|
else if (this.StandardsManager.SecurityVersion.IsReaderAtSignatureConfirmation(reader))
|
|
{
|
|
ReadSignatureConfirmation(reader, AppendPosition, null);
|
|
}
|
|
else if (IsReaderAtSecurityTokenReference(reader))
|
|
{
|
|
ReadSecurityTokenReference(reader);
|
|
}
|
|
else
|
|
{
|
|
ReadToken(reader, AppendPosition, null, null, null, this.timeoutHelper.RemainingTime());
|
|
}
|
|
position++;
|
|
}
|
|
|
|
reader.ReadEndElement(); // wsse:Security
|
|
reader.Close();
|
|
}
|
|
|
|
internal void EnsureDerivedKeyLimitNotReached()
|
|
{
|
|
++this.numDerivedKeys;
|
|
if (this.numDerivedKeys > this.maxDerivedKeys)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.DerivedKeyLimitExceeded, maxDerivedKeys)));
|
|
}
|
|
}
|
|
|
|
internal void ExecuteDerivedKeyTokenStubPass(bool isFinalPass)
|
|
{
|
|
for (int position = 0; position < this.elementManager.Count; position++)
|
|
{
|
|
if (this.elementManager.GetElementCategory(position) == ReceiveSecurityHeaderElementCategory.Token)
|
|
{
|
|
DerivedKeySecurityTokenStub stub = this.elementManager.GetElement(position) as DerivedKeySecurityTokenStub;
|
|
if (stub != null)
|
|
{
|
|
SecurityToken sourceToken = null;
|
|
this.universalTokenResolver.TryResolveToken(stub.TokenToDeriveIdentifier, out sourceToken);
|
|
if (sourceToken != null)
|
|
{
|
|
EnsureDerivedKeyLimitNotReached();
|
|
DerivedKeySecurityToken derivedKeyToken = stub.CreateToken(sourceToken, this.maxDerivedKeyLength);
|
|
this.elementManager.SetElement(position, derivedKeyToken);
|
|
AddDerivedKeyTokenToResolvers(derivedKeyToken);
|
|
}
|
|
else if (isFinalPass)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.UnableToResolveKeyInfoClauseInDerivedKeyToken, stub.TokenToDeriveIdentifier)), this.Message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SecurityToken GetRootToken(SecurityToken token)
|
|
{
|
|
if (token is DerivedKeySecurityToken)
|
|
{
|
|
return ((DerivedKeySecurityToken)token).TokenToDerive;
|
|
}
|
|
else
|
|
{
|
|
return token;
|
|
}
|
|
}
|
|
|
|
void RecordEncryptionTokenAndRemoveReferenceListEntry(string id, SecurityToken encryptionToken)
|
|
{
|
|
if (id == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.MissingIdInEncryptedElement)), this.Message);
|
|
}
|
|
|
|
OnDecryptionOfSecurityHeaderItemRequiringReferenceListEntry(id);
|
|
RecordEncryptionToken(encryptionToken);
|
|
}
|
|
|
|
EncryptedData ReadEncryptedData(XmlDictionaryReader reader)
|
|
{
|
|
EncryptedData encryptedData = ReadSecurityHeaderEncryptedItem(reader, this.MessageDirection == MessageDirection.Output);
|
|
|
|
this.elementManager.AppendEncryptedData(encryptedData);
|
|
return encryptedData;
|
|
}
|
|
|
|
internal XmlDictionaryReader CreateDecryptedReader(byte[] decryptedBuffer)
|
|
{
|
|
return ContextImportHelper.CreateSplicedReader(
|
|
decryptedBuffer,
|
|
this.SecurityVerifiedMessage.GetEnvelopeAttributes(),
|
|
this.SecurityVerifiedMessage.GetHeaderAttributes(),
|
|
this.securityElementAttributes,
|
|
this.ReaderQuotas
|
|
);
|
|
}
|
|
|
|
void ProcessEncryptedData(EncryptedData encryptedData, TimeSpan timeout, int position, bool eagerMode, ref bool primarySignatureFound)
|
|
{
|
|
if (TD.EncryptedDataProcessingStartIsEnabled())
|
|
{
|
|
TD.EncryptedDataProcessingStart(this.EventTraceActivity);
|
|
}
|
|
|
|
string id = encryptedData.Id;
|
|
|
|
SecurityToken encryptionToken;
|
|
byte[] decryptedBuffer = DecryptSecurityHeaderElement(encryptedData, this.wrappedKeyToken, out encryptionToken);
|
|
|
|
XmlDictionaryReader decryptedReader = CreateDecryptedReader(decryptedBuffer);
|
|
|
|
if (IsReaderAtSignature(decryptedReader))
|
|
{
|
|
RecordEncryptionTokenAndRemoveReferenceListEntry(id, encryptionToken);
|
|
SignedXml signedXml = ReadSignature(decryptedReader, position, decryptedBuffer);
|
|
if (eagerMode)
|
|
{
|
|
if (primarySignatureFound)
|
|
{
|
|
this.elementManager.SetBindingMode(position, ReceiveSecurityHeaderBindingModes.Endorsing);
|
|
ProcessSupportingSignature(signedXml, true);
|
|
}
|
|
else
|
|
{
|
|
primarySignatureFound = true;
|
|
this.elementManager.SetBindingMode(position, ReceiveSecurityHeaderBindingModes.Primary);
|
|
ProcessPrimarySignature(signedXml, true);
|
|
}
|
|
}
|
|
}
|
|
else if (this.StandardsManager.SecurityVersion.IsReaderAtSignatureConfirmation(decryptedReader))
|
|
{
|
|
RecordEncryptionTokenAndRemoveReferenceListEntry(id, encryptionToken);
|
|
ReadSignatureConfirmation(decryptedReader, position, decryptedBuffer);
|
|
}
|
|
else
|
|
{
|
|
if (IsReaderAtEncryptedData(decryptedReader))
|
|
{
|
|
|
|
// The purpose of this code is to process a token that arrived at a client as encryptedData.
|
|
|
|
// This is a common scenario for supporting tokens.
|
|
|
|
// We pass readXmlReferenceKeyIdentifierClause as false here because we do not expect the client
|
|
// to receive an encrypted token for itself from the service. The encrypted token is encrypted for some other service.
|
|
// Hence we assume that the KeyInfoClause entry in it is not an XMLReference entry that the client is supposed to understand.
|
|
|
|
// What if the service sends its authentication token as an EncryptedData to the client?
|
|
|
|
EncryptedData ed = ReadSecurityHeaderEncryptedItem(decryptedReader, false);
|
|
SecurityToken securityToken;
|
|
byte[] db = DecryptSecurityHeaderElement(ed, this.wrappedKeyToken, out securityToken);
|
|
XmlDictionaryReader dr = CreateDecryptedReader(db);
|
|
|
|
|
|
// read the actual token and put it into the system
|
|
ReadToken(dr, position, db, encryptionToken, id, timeout);
|
|
|
|
ReceiveSecurityHeaderEntry rshe;
|
|
this.ElementManager.GetElementEntry(position, out rshe);
|
|
|
|
// In EncryptBeforeSignMode, we have encrypted the outer token, remember the right id.
|
|
// The reason why I have both id's is in that case that one or the other is passed
|
|
// we won't have a problem with which one. SHP accounting should ensure each item has
|
|
// the correct hash.
|
|
if (this.EncryptBeforeSignMode)
|
|
{
|
|
rshe.encryptedFormId = encryptedData.Id;
|
|
rshe.encryptedFormWsuId = encryptedData.WsuId;
|
|
}
|
|
else
|
|
{
|
|
rshe.encryptedFormId = ed.Id;
|
|
rshe.encryptedFormWsuId = ed.WsuId;
|
|
}
|
|
|
|
rshe.decryptedBuffer = decryptedBuffer;
|
|
|
|
// setting this to true, will allow a different id match in ReceiveSecurityHeaderEntry.Match
|
|
// to one of the ids set above as the token id will not match what the signature reference is looking for.
|
|
|
|
rshe.doubleEncrypted = true;
|
|
|
|
this.ElementManager.ReplaceHeaderEntry(position, rshe);
|
|
}
|
|
else
|
|
ReadToken(decryptedReader, position, decryptedBuffer, encryptionToken, id, timeout);
|
|
}
|
|
|
|
if (TD.EncryptedDataProcessingSuccessIsEnabled())
|
|
{
|
|
TD.EncryptedDataProcessingSuccess(this.EventTraceActivity);
|
|
}
|
|
}
|
|
|
|
void ReadEncryptedKey(XmlDictionaryReader reader, bool processReferenceListIfPresent)
|
|
{
|
|
this.orderTracker.OnEncryptedKey();
|
|
|
|
WrappedKeySecurityToken wrappedKeyToken = DecryptWrappedKey(reader);
|
|
if (wrappedKeyToken.WrappingToken != this.wrappingToken)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.EncryptedKeyWasNotEncryptedWithTheRequiredEncryptingToken, this.wrappingToken)));
|
|
}
|
|
this.universalTokenResolver.Add(wrappedKeyToken);
|
|
this.primaryTokenResolver.Add(wrappedKeyToken);
|
|
if (wrappedKeyToken.ReferenceList != null)
|
|
{
|
|
if (!this.EncryptedKeyContainsReferenceList)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.EncryptedKeyWithReferenceListNotAllowed)));
|
|
}
|
|
if (!this.ExpectEncryption)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.EncryptionNotExpected)), this.Message);
|
|
}
|
|
if (processReferenceListIfPresent)
|
|
{
|
|
ProcessReferenceList(wrappedKeyToken.ReferenceList, wrappedKeyToken);
|
|
}
|
|
this.wrappedKeyToken = wrappedKeyToken;
|
|
}
|
|
this.elementManager.AppendToken(wrappedKeyToken, ReceiveSecurityHeaderBindingModes.Primary, null);
|
|
}
|
|
|
|
ReferenceList ReadReferenceList(XmlDictionaryReader reader)
|
|
{
|
|
if (!this.ExpectEncryption)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.EncryptionNotExpected)), this.Message);
|
|
}
|
|
ReferenceList referenceList = ReadReferenceListCore(reader);
|
|
this.elementManager.AppendReferenceList(referenceList);
|
|
return referenceList;
|
|
}
|
|
|
|
protected abstract ReferenceList ReadReferenceListCore(XmlDictionaryReader reader);
|
|
|
|
void ProcessReferenceList(ReferenceList referenceList)
|
|
{
|
|
ProcessReferenceList(referenceList, null);
|
|
}
|
|
|
|
void ProcessReferenceList(ReferenceList referenceList, WrappedKeySecurityToken wrappedKeyToken)
|
|
{
|
|
this.orderTracker.OnProcessReferenceList();
|
|
ProcessReferenceListCore(referenceList, wrappedKeyToken);
|
|
}
|
|
|
|
protected abstract void ProcessReferenceListCore(ReferenceList referenceList, WrappedKeySecurityToken wrappedKeyToken);
|
|
|
|
SignedXml ReadSignature(XmlDictionaryReader reader, int position, byte[] decryptedBuffer)
|
|
{
|
|
Fx.Assert((position == AppendPosition) == (decryptedBuffer == null), "inconsistent position, decryptedBuffer parameters");
|
|
if (!this.ExpectSignature)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SignatureNotExpected)), this.Message);
|
|
}
|
|
SignedXml signedXml = ReadSignatureCore(reader);
|
|
signedXml.Signature.SignedInfo.ReaderProvider = this.ElementManager;
|
|
int readerIndex;
|
|
if (decryptedBuffer == null)
|
|
{
|
|
this.elementManager.AppendSignature(signedXml);
|
|
readerIndex = this.elementManager.Count - 1;
|
|
}
|
|
else
|
|
{
|
|
this.elementManager.SetSignatureAfterDecryption(position, signedXml, decryptedBuffer);
|
|
readerIndex = position;
|
|
}
|
|
signedXml.Signature.SignedInfo.SignatureReaderProviderCallbackContext = (object)(readerIndex);
|
|
return signedXml;
|
|
}
|
|
|
|
protected abstract void ReadSecurityTokenReference(XmlDictionaryReader reader);
|
|
|
|
void ProcessPrimarySignature(SignedXml signedXml, bool isFromDecryptedSource)
|
|
{
|
|
this.orderTracker.OnProcessSignature(isFromDecryptedSource);
|
|
|
|
this.primarySignatureValue = signedXml.GetSignatureValue();
|
|
if (this.replayDetectionEnabled)
|
|
{
|
|
CheckNonce(this.nonceCache, this.primarySignatureValue);
|
|
}
|
|
|
|
SecurityToken signingToken = VerifySignature(signedXml, true, this.primaryTokenResolver, null, null);
|
|
// verify that the signing token is the same as the primary token
|
|
SecurityToken rootSigningToken = GetRootToken(signingToken);
|
|
bool isDerivedKeySignature = signingToken is DerivedKeySecurityToken;
|
|
if (this.primaryTokenTracker != null)
|
|
{
|
|
this.primaryTokenTracker.RecordToken(rootSigningToken);
|
|
this.primaryTokenTracker.IsDerivedFrom = isDerivedKeySignature;
|
|
}
|
|
this.AddIncomingSignatureValue(signedXml.GetSignatureValue(), isFromDecryptedSource);
|
|
}
|
|
|
|
void ReadSignatureConfirmation(XmlDictionaryReader reader, int position, byte[] decryptedBuffer)
|
|
{
|
|
Fx.Assert((position == AppendPosition) == (decryptedBuffer == null), "inconsistent position, decryptedBuffer parameters");
|
|
if (!this.ExpectSignatureConfirmation)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SignatureConfirmationsNotExpected)), this.Message);
|
|
}
|
|
if (this.orderTracker.PrimarySignatureDone)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SignatureConfirmationsOccursAfterPrimarySignature)), this.Message);
|
|
}
|
|
ISignatureValueSecurityElement sigConfElement = this.StandardsManager.SecurityVersion.ReadSignatureConfirmation(reader);
|
|
if (decryptedBuffer == null)
|
|
{
|
|
this.AddIncomingSignatureConfirmation(sigConfElement.GetSignatureValue(), false);
|
|
this.elementManager.AppendSignatureConfirmation(sigConfElement);
|
|
}
|
|
else
|
|
{
|
|
this.AddIncomingSignatureConfirmation(sigConfElement.GetSignatureValue(), true);
|
|
this.elementManager.SetSignatureConfirmationAfterDecryption(position, sigConfElement, decryptedBuffer);
|
|
}
|
|
}
|
|
|
|
TokenTracker GetSupportingTokenTracker(SecurityToken token)
|
|
{
|
|
if (this.supportingTokenTrackers == null)
|
|
return null;
|
|
for (int i = 0; i < this.supportingTokenTrackers.Count; ++i)
|
|
{
|
|
if (supportingTokenTrackers[i].token == token)
|
|
return supportingTokenTrackers[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected TokenTracker GetSupportingTokenTracker(SecurityTokenAuthenticator tokenAuthenticator, out SupportingTokenAuthenticatorSpecification spec)
|
|
{
|
|
spec = null;
|
|
if (this.supportingTokenAuthenticators == null)
|
|
return null;
|
|
for (int i = 0; i < this.supportingTokenAuthenticators.Count; ++i)
|
|
{
|
|
if (supportingTokenAuthenticators[i].TokenAuthenticator == tokenAuthenticator)
|
|
{
|
|
spec = supportingTokenAuthenticators[i];
|
|
return supportingTokenTrackers[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected TAuthenticator FindAllowedAuthenticator<TAuthenticator>(bool removeIfPresent)
|
|
where TAuthenticator : SecurityTokenAuthenticator
|
|
{
|
|
if (this.allowedAuthenticators == null)
|
|
{
|
|
return null;
|
|
}
|
|
for (int i = 0; i < this.allowedAuthenticators.Count; ++i)
|
|
{
|
|
if (allowedAuthenticators[i] is TAuthenticator)
|
|
{
|
|
TAuthenticator result = (TAuthenticator)allowedAuthenticators[i];
|
|
if (removeIfPresent)
|
|
{
|
|
this.allowedAuthenticators.RemoveAt(i);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
void ProcessSupportingSignature(SignedXml signedXml, bool isFromDecryptedSource)
|
|
{
|
|
if (!this.ExpectEndorsingTokens)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SupportingTokenSignaturesNotExpected)), this.Message);
|
|
}
|
|
string id;
|
|
XmlDictionaryReader reader;
|
|
object signatureTarget;
|
|
if (!this.RequireMessageProtection)
|
|
{
|
|
if (this.timestamp == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.SigningWithoutPrimarySignatureRequiresTimestamp)), this.Message);
|
|
}
|
|
reader = null;
|
|
id = this.timestamp.Id;
|
|
// We would have pre-computed the timestamp digest, if the transport reader
|
|
// was capable of canonicalization. If we were not able to compute the digest
|
|
// before hand then the signature verification step will get a new reader
|
|
// and will recompute the digest.
|
|
signatureTarget = null;
|
|
}
|
|
else
|
|
{
|
|
this.elementManager.GetPrimarySignature(out reader, out id);
|
|
if (reader == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.NoPrimarySignatureAvailableForSupportingTokenSignatureVerification)), this.Message);
|
|
}
|
|
signatureTarget = reader;
|
|
}
|
|
SecurityToken signingToken = VerifySignature(signedXml, false, this.universalTokenResolver, signatureTarget, id);
|
|
if (reader != null)
|
|
{
|
|
reader.Close();
|
|
}
|
|
if (signingToken == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.SignatureVerificationFailed)), this.Message);
|
|
}
|
|
SecurityToken rootSigningToken = GetRootToken(signingToken);
|
|
TokenTracker tracker = GetSupportingTokenTracker(rootSigningToken);
|
|
if (tracker == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.UnknownSupportingToken, signingToken)));
|
|
}
|
|
|
|
if (tracker.AlreadyReadEndorsingSignature)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.MoreThanOneSupportingSignature, signingToken)));
|
|
|
|
tracker.IsEndorsing = true;
|
|
tracker.AlreadyReadEndorsingSignature = true;
|
|
tracker.IsDerivedFrom = (signingToken is DerivedKeySecurityToken);
|
|
AddIncomingSignatureValue(signedXml.GetSignatureValue(), isFromDecryptedSource);
|
|
}
|
|
|
|
void ReadTimestamp(XmlDictionaryReader reader)
|
|
{
|
|
if (this.timestamp != null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.DuplicateTimestampInSecurityHeader)), this.Message);
|
|
}
|
|
bool expectTimestampToBeSigned = this.RequireMessageProtection || this.hasEndorsingOrSignedEndorsingSupportingTokens;
|
|
string expectedDigestAlgorithm = expectTimestampToBeSigned ? this.AlgorithmSuite.DefaultDigestAlgorithm : null;
|
|
SignatureResourcePool resourcePool = expectTimestampToBeSigned ? this.ResourcePool : null;
|
|
this.timestamp = this.StandardsManager.WSUtilitySpecificationVersion.ReadTimestamp(reader, expectedDigestAlgorithm, resourcePool);
|
|
this.timestamp.ValidateRangeAndFreshness(this.replayWindow, this.clockSkew);
|
|
this.elementManager.AppendTimestamp(this.timestamp);
|
|
}
|
|
|
|
bool IsPrimaryToken(SecurityToken token)
|
|
{
|
|
bool result = (token == outOfBandPrimaryToken
|
|
|| (primaryTokenTracker != null && token == primaryTokenTracker.token)
|
|
|| (token == expectedEncryptionToken)
|
|
|| ((token is WrappedKeySecurityToken) && ((WrappedKeySecurityToken)token).WrappingToken == this.wrappingToken));
|
|
if (!result && this.outOfBandPrimaryTokenCollection != null)
|
|
{
|
|
for (int i = 0; i < this.outOfBandPrimaryTokenCollection.Count; ++i)
|
|
{
|
|
if (this.outOfBandPrimaryTokenCollection[i] == token)
|
|
{
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void ReadToken(XmlDictionaryReader reader, int position, byte[] decryptedBuffer,
|
|
SecurityToken encryptionToken, string idInEncryptedForm, TimeSpan timeout)
|
|
{
|
|
Fx.Assert((position == AppendPosition) == (decryptedBuffer == null), "inconsistent position, decryptedBuffer parameters");
|
|
Fx.Assert((position == AppendPosition) == (encryptionToken == null), "inconsistent position, encryptionToken parameters");
|
|
string localName = reader.LocalName;
|
|
string namespaceUri = reader.NamespaceURI;
|
|
string valueType = reader.GetAttribute(XD.SecurityJan2004Dictionary.ValueType, null);
|
|
|
|
SecurityTokenAuthenticator usedTokenAuthenticator;
|
|
SecurityToken token = ReadToken(reader, this.CombinedUniversalTokenResolver, allowedAuthenticators, out usedTokenAuthenticator);
|
|
if (token == null)
|
|
{
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.TokenManagerCouldNotReadToken, localName, namespaceUri, valueType)), this.Message);
|
|
}
|
|
DerivedKeySecurityToken derivedKeyToken = token as DerivedKeySecurityToken;
|
|
if (derivedKeyToken != null)
|
|
{
|
|
EnsureDerivedKeyLimitNotReached();
|
|
derivedKeyToken.InitializeDerivedKey(this.maxDerivedKeyLength);
|
|
}
|
|
|
|
if ((usedTokenAuthenticator is SspiNegotiationTokenAuthenticator) ||
|
|
(usedTokenAuthenticator == this.primaryTokenAuthenticator))
|
|
{
|
|
this.allowedAuthenticators.Remove(usedTokenAuthenticator);
|
|
}
|
|
|
|
ReceiveSecurityHeaderBindingModes mode;
|
|
TokenTracker supportingTokenTracker = null;
|
|
if (usedTokenAuthenticator == this.primaryTokenAuthenticator)
|
|
{
|
|
// this is the primary token. Add to resolver as such
|
|
this.universalTokenResolver.Add(token, SecurityTokenReferenceStyle.Internal, this.primaryTokenParameters);
|
|
this.primaryTokenResolver.Add(token, SecurityTokenReferenceStyle.Internal, this.primaryTokenParameters);
|
|
if (this.pendingSupportingTokenAuthenticator != null)
|
|
{
|
|
this.allowedAuthenticators.Add(this.pendingSupportingTokenAuthenticator);
|
|
this.pendingSupportingTokenAuthenticator = null;
|
|
}
|
|
this.primaryTokenTracker.RecordToken(token);
|
|
mode = ReceiveSecurityHeaderBindingModes.Primary;
|
|
}
|
|
else if (usedTokenAuthenticator == this.DerivedTokenAuthenticator)
|
|
{
|
|
if (token is DerivedKeySecurityTokenStub)
|
|
{
|
|
if (this.Layout == SecurityHeaderLayout.Strict)
|
|
{
|
|
DerivedKeySecurityTokenStub tmpToken = (DerivedKeySecurityTokenStub)token;
|
|
throw TraceUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.UnableToResolveKeyInfoClauseInDerivedKeyToken, tmpToken.TokenToDeriveIdentifier)), this.Message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddDerivedKeyTokenToResolvers(token);
|
|
}
|
|
mode = ReceiveSecurityHeaderBindingModes.Unknown;
|
|
}
|
|
else
|
|
{
|
|
SupportingTokenAuthenticatorSpecification supportingTokenSpec;
|
|
supportingTokenTracker = GetSupportingTokenTracker(usedTokenAuthenticator, out supportingTokenSpec);
|
|
if (supportingTokenTracker == null)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.UnknownTokenAuthenticatorUsedInTokenProcessing, usedTokenAuthenticator)));
|
|
}
|
|
if (supportingTokenTracker.token != null)
|
|
{
|
|
supportingTokenTracker = new TokenTracker(supportingTokenSpec);
|
|
this.supportingTokenTrackers.Add(supportingTokenTracker);
|
|
}
|
|
|
|
supportingTokenTracker.RecordToken(token);
|
|
if (encryptionToken != null)
|
|
{
|
|
supportingTokenTracker.IsEncrypted = true;
|
|
}
|
|
|
|
bool isBasic;
|
|
bool isSignedButNotBasic;
|
|
SecurityTokenAttachmentModeHelper.Categorize(supportingTokenSpec.SecurityTokenAttachmentMode,
|
|
out isBasic, out isSignedButNotBasic, out mode);
|
|
if (isBasic)
|
|
{
|
|
if (!this.ExpectBasicTokens)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.BasicTokenNotExpected)));
|
|
}
|
|
|
|
// only basic tokens have to be part of the reference list. Encrypted Saml tokens dont for example
|
|
if (this.RequireMessageProtection && encryptionToken != null)
|
|
{
|
|
RecordEncryptionTokenAndRemoveReferenceListEntry(idInEncryptedForm, encryptionToken);
|
|
}
|
|
}
|
|
if (isSignedButNotBasic && !this.ExpectSignedTokens)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.SignedSupportingTokenNotExpected)));
|
|
}
|
|
this.universalTokenResolver.Add(token, SecurityTokenReferenceStyle.Internal, supportingTokenSpec.TokenParameters);
|
|
}
|
|
if (position == AppendPosition)
|
|
{
|
|
this.elementManager.AppendToken(token, mode, supportingTokenTracker);
|
|
}
|
|
else
|
|
{
|
|
this.elementManager.SetTokenAfterDecryption(position, token, mode, decryptedBuffer, supportingTokenTracker);
|
|
}
|
|
}
|
|
|
|
SecurityToken ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver, IList<SecurityTokenAuthenticator> allowedTokenAuthenticators, out SecurityTokenAuthenticator usedTokenAuthenticator)
|
|
{
|
|
SecurityToken token = this.StandardsManager.SecurityTokenSerializer.ReadToken(reader, tokenResolver);
|
|
if (token is DerivedKeySecurityTokenStub)
|
|
{
|
|
if (this.DerivedTokenAuthenticator == null)
|
|
{
|
|
// No Authenticator registered for DerivedKeySecurityToken
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.UnableToFindTokenAuthenticator, typeof(DerivedKeySecurityToken))));
|
|
}
|
|
|
|
// This is just the stub. Nothing to Validate. Set the usedTokenAuthenticator to
|
|
// DerivedKeySecurityTokenAuthenticator.
|
|
usedTokenAuthenticator = this.DerivedTokenAuthenticator;
|
|
return token;
|
|
}
|
|
|
|
for (int i = 0; i < allowedTokenAuthenticators.Count; ++i)
|
|
{
|
|
SecurityTokenAuthenticator tokenAuthenticator = allowedTokenAuthenticators[i];
|
|
if (tokenAuthenticator.CanValidateToken(token))
|
|
{
|
|
ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies;
|
|
ServiceCredentialsSecurityTokenManager.KerberosSecurityTokenAuthenticatorWrapper kerbTokenAuthenticator =
|
|
tokenAuthenticator as ServiceCredentialsSecurityTokenManager.KerberosSecurityTokenAuthenticatorWrapper;
|
|
if (kerbTokenAuthenticator != null)
|
|
{
|
|
authorizationPolicies = kerbTokenAuthenticator.ValidateToken(token, this.channelBinding, this.extendedProtectionPolicy);
|
|
}
|
|
else
|
|
{
|
|
authorizationPolicies = tokenAuthenticator.ValidateToken(token);
|
|
}
|
|
SecurityTokenAuthorizationPoliciesMapping.Add(token, authorizationPolicies);
|
|
usedTokenAuthenticator = tokenAuthenticator;
|
|
return token;
|
|
}
|
|
}
|
|
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.UnableToFindTokenAuthenticator, token.GetType())));
|
|
}
|
|
|
|
|
|
void AddDerivedKeyTokenToResolvers(SecurityToken token)
|
|
{
|
|
this.universalTokenResolver.Add(token);
|
|
// add it to the primary token resolver only if its root is primary
|
|
SecurityToken rootToken = GetRootToken(token);
|
|
if (IsPrimaryToken(rootToken))
|
|
{
|
|
primaryTokenResolver.Add(token);
|
|
}
|
|
}
|
|
|
|
void AddIncomingSignatureConfirmation(byte[] signatureValue, bool isFromDecryptedSource)
|
|
{
|
|
if (this.MaintainSignatureConfirmationState)
|
|
{
|
|
if (this.receivedSignatureConfirmations == null)
|
|
{
|
|
this.receivedSignatureConfirmations = new SignatureConfirmations();
|
|
}
|
|
this.receivedSignatureConfirmations.AddConfirmation(signatureValue, isFromDecryptedSource);
|
|
}
|
|
}
|
|
|
|
void AddIncomingSignatureValue(byte[] signatureValue, bool isFromDecryptedSource)
|
|
{
|
|
// cache incoming signatures only on the server side
|
|
if (this.MaintainSignatureConfirmationState && !this.ExpectSignatureConfirmation)
|
|
{
|
|
if (this.receivedSignatureValues == null)
|
|
{
|
|
this.receivedSignatureValues = new SignatureConfirmations();
|
|
}
|
|
this.receivedSignatureValues.AddConfirmation(signatureValue, isFromDecryptedSource);
|
|
}
|
|
}
|
|
|
|
protected void RecordEncryptionToken(SecurityToken token)
|
|
{
|
|
this.encryptionTracker.RecordToken(token);
|
|
}
|
|
|
|
protected void RecordSignatureToken(SecurityToken token)
|
|
{
|
|
this.signatureTracker.RecordToken(token);
|
|
}
|
|
|
|
public void SetRequiredProtectionOrder(MessageProtectionOrder protectionOrder)
|
|
{
|
|
ThrowIfProcessingStarted();
|
|
this.protectionOrder = protectionOrder;
|
|
}
|
|
|
|
protected abstract SignedXml ReadSignatureCore(XmlDictionaryReader signatureReader);
|
|
|
|
protected abstract SecurityToken VerifySignature(SignedXml signedXml, bool isPrimarySignature,
|
|
SecurityHeaderTokenResolver resolver, object signatureTarget, string id);
|
|
|
|
protected abstract bool TryDeleteReferenceListEntry(string id);
|
|
|
|
struct OrderTracker
|
|
{
|
|
static readonly ReceiverProcessingOrder[] stateTransitionTableOnDecrypt = new ReceiverProcessingOrder[]
|
|
{
|
|
ReceiverProcessingOrder.Decrypt, ReceiverProcessingOrder.VerifyDecrypt, ReceiverProcessingOrder.Decrypt,
|
|
ReceiverProcessingOrder.Mixed, ReceiverProcessingOrder.VerifyDecrypt, ReceiverProcessingOrder.Mixed
|
|
};
|
|
static readonly ReceiverProcessingOrder[] stateTransitionTableOnVerify = new ReceiverProcessingOrder[]
|
|
{
|
|
ReceiverProcessingOrder.Verify, ReceiverProcessingOrder.Verify, ReceiverProcessingOrder.DecryptVerify,
|
|
ReceiverProcessingOrder.DecryptVerify, ReceiverProcessingOrder.Mixed, ReceiverProcessingOrder.Mixed
|
|
};
|
|
|
|
const int MaxAllowedWrappedKeys = 1;
|
|
|
|
int referenceListCount;
|
|
ReceiverProcessingOrder state;
|
|
int signatureCount;
|
|
int unencryptedSignatureCount;
|
|
int numWrappedKeys;
|
|
MessageProtectionOrder protectionOrder;
|
|
bool enforce;
|
|
|
|
public bool AllSignaturesEncrypted
|
|
{
|
|
get { return this.unencryptedSignatureCount == 0; }
|
|
}
|
|
|
|
public bool EncryptBeforeSignMode
|
|
{
|
|
get { return this.enforce && this.protectionOrder == MessageProtectionOrder.EncryptBeforeSign; }
|
|
}
|
|
|
|
public bool EncryptBeforeSignOrderRequirementMet
|
|
{
|
|
get { return this.state != ReceiverProcessingOrder.DecryptVerify && this.state != ReceiverProcessingOrder.Mixed; }
|
|
}
|
|
|
|
public bool PrimarySignatureDone
|
|
{
|
|
get { return this.signatureCount > 0; }
|
|
}
|
|
|
|
public bool SignBeforeEncryptOrderRequirementMet
|
|
{
|
|
get { return this.state != ReceiverProcessingOrder.VerifyDecrypt && this.state != ReceiverProcessingOrder.Mixed; }
|
|
}
|
|
|
|
void EnforceProtectionOrder()
|
|
{
|
|
switch (this.protectionOrder)
|
|
{
|
|
case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:
|
|
if (!this.AllSignaturesEncrypted)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.PrimarySignatureIsRequiredToBeEncrypted)));
|
|
}
|
|
goto case MessageProtectionOrder.SignBeforeEncrypt;
|
|
case MessageProtectionOrder.SignBeforeEncrypt:
|
|
if (!this.SignBeforeEncryptOrderRequirementMet)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.MessageProtectionOrderMismatch, this.protectionOrder)));
|
|
}
|
|
break;
|
|
case MessageProtectionOrder.EncryptBeforeSign:
|
|
if (!this.EncryptBeforeSignOrderRequirementMet)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.MessageProtectionOrderMismatch, this.protectionOrder)));
|
|
}
|
|
break;
|
|
default:
|
|
Fx.Assert("");
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void OnProcessReferenceList()
|
|
{
|
|
Fx.Assert(this.enforce, "OrderTracker should have 'enforce' set to true.");
|
|
if (this.referenceListCount > 0)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(
|
|
SR.GetString(SR.AtMostOneReferenceListIsSupportedWithDefaultPolicyCheck)));
|
|
}
|
|
this.referenceListCount++;
|
|
this.state = stateTransitionTableOnDecrypt[(int)this.state];
|
|
if (this.enforce)
|
|
{
|
|
EnforceProtectionOrder();
|
|
}
|
|
}
|
|
|
|
public void OnProcessSignature(bool isEncrypted)
|
|
{
|
|
Fx.Assert(this.enforce, "OrderTracker should have 'enforce' set to true.");
|
|
if (this.signatureCount > 0)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.AtMostOneSignatureIsSupportedWithDefaultPolicyCheck)));
|
|
}
|
|
this.signatureCount++;
|
|
if (!isEncrypted)
|
|
{
|
|
this.unencryptedSignatureCount++;
|
|
}
|
|
this.state = stateTransitionTableOnVerify[(int)this.state];
|
|
if (this.enforce)
|
|
{
|
|
EnforceProtectionOrder();
|
|
}
|
|
}
|
|
|
|
public void OnEncryptedKey()
|
|
{
|
|
Fx.Assert(this.enforce, "OrderTracker should have 'enforce' set to true.");
|
|
|
|
if (this.numWrappedKeys == MaxAllowedWrappedKeys)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.WrappedKeyLimitExceeded, this.numWrappedKeys)));
|
|
|
|
this.numWrappedKeys++;
|
|
}
|
|
|
|
public void SetRequiredProtectionOrder(MessageProtectionOrder protectionOrder)
|
|
{
|
|
this.protectionOrder = protectionOrder;
|
|
this.enforce = true;
|
|
}
|
|
|
|
enum ReceiverProcessingOrder : int
|
|
{
|
|
None = 0,
|
|
Verify = 1,
|
|
Decrypt = 2,
|
|
DecryptVerify = 3,
|
|
VerifyDecrypt = 4,
|
|
Mixed = 5
|
|
}
|
|
}
|
|
|
|
struct OperationTracker
|
|
{
|
|
MessagePartSpecification parts;
|
|
SecurityToken token;
|
|
bool isDerivedToken;
|
|
|
|
public MessagePartSpecification Parts
|
|
{
|
|
get { return this.parts; }
|
|
set { this.parts = value; }
|
|
}
|
|
|
|
public SecurityToken Token
|
|
{
|
|
get { return this.token; }
|
|
}
|
|
|
|
public bool IsDerivedToken
|
|
{
|
|
get { return this.isDerivedToken; }
|
|
}
|
|
|
|
public void RecordToken(SecurityToken token)
|
|
{
|
|
if (this.token == null)
|
|
{
|
|
this.token = token;
|
|
}
|
|
else if (!ReferenceEquals(this.token, token))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.MismatchInSecurityOperationToken)));
|
|
}
|
|
}
|
|
|
|
public void SetDerivationSourceIfRequired()
|
|
{
|
|
DerivedKeySecurityToken derivedKeyToken = this.token as DerivedKeySecurityToken;
|
|
if (derivedKeyToken != null)
|
|
{
|
|
this.token = derivedKeyToken.TokenToDerive;
|
|
this.isDerivedToken = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class TokenTracker
|
|
{
|
|
public SecurityToken token;
|
|
public bool IsDerivedFrom;
|
|
public bool IsSigned;
|
|
public bool IsEncrypted;
|
|
public bool IsEndorsing;
|
|
public bool AlreadyReadEndorsingSignature;
|
|
bool allowFirstTokenMismatch;
|
|
public SupportingTokenAuthenticatorSpecification spec;
|
|
|
|
public TokenTracker(SupportingTokenAuthenticatorSpecification spec)
|
|
: this(spec, null, false)
|
|
{
|
|
}
|
|
|
|
public TokenTracker(SupportingTokenAuthenticatorSpecification spec, SecurityToken token, bool allowFirstTokenMismatch)
|
|
{
|
|
this.spec = spec;
|
|
this.token = token;
|
|
this.allowFirstTokenMismatch = allowFirstTokenMismatch;
|
|
}
|
|
|
|
public void RecordToken(SecurityToken token)
|
|
{
|
|
if (this.token == null)
|
|
{
|
|
this.token = token;
|
|
}
|
|
else if (this.allowFirstTokenMismatch)
|
|
{
|
|
if (!AreTokensEqual(this.token, token))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.MismatchInSecurityOperationToken)));
|
|
}
|
|
this.token = token;
|
|
this.allowFirstTokenMismatch = false;
|
|
}
|
|
else if (!object.ReferenceEquals(this.token, token))
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.MismatchInSecurityOperationToken)));
|
|
}
|
|
}
|
|
|
|
static bool AreTokensEqual(SecurityToken outOfBandToken, SecurityToken replyToken)
|
|
{
|
|
// we support the serialized reply token legacy feature only for X509 certificates.
|
|
// in this case the thumbprint of the reply certificate must match the outofband certificate's thumbprint
|
|
if ((outOfBandToken is X509SecurityToken) && (replyToken is X509SecurityToken))
|
|
{
|
|
byte[] outOfBandCertificateThumbprint = ((X509SecurityToken)outOfBandToken).Certificate.GetCertHash();
|
|
byte[] replyCertificateThumbprint = ((X509SecurityToken)replyToken).Certificate.GetCertHash();
|
|
return (CryptoHelper.IsEqual(outOfBandCertificateThumbprint, replyCertificateThumbprint));
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
class AggregateSecurityHeaderTokenResolver : System.IdentityModel.Tokens.AggregateTokenResolver
|
|
{
|
|
SecurityHeaderTokenResolver tokenResolver;
|
|
|
|
public AggregateSecurityHeaderTokenResolver(SecurityHeaderTokenResolver tokenResolver, ReadOnlyCollection<SecurityTokenResolver> outOfBandTokenResolvers) :
|
|
base(outOfBandTokenResolvers)
|
|
{
|
|
if (tokenResolver == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenResolver");
|
|
|
|
this.tokenResolver = tokenResolver;
|
|
}
|
|
|
|
protected override bool TryResolveSecurityKeyCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityKey key)
|
|
{
|
|
bool resolved = false;
|
|
key = null;
|
|
|
|
resolved = this.tokenResolver.TryResolveSecurityKey(keyIdentifierClause, false, out key);
|
|
|
|
if (!resolved)
|
|
{
|
|
resolved = base.TryResolveSecurityKeyCore(keyIdentifierClause, out key);
|
|
}
|
|
|
|
if (!resolved)
|
|
{
|
|
resolved = SecurityUtils.TryCreateKeyFromIntrinsicKeyClause(keyIdentifierClause, this, out key);
|
|
}
|
|
|
|
return resolved;
|
|
}
|
|
|
|
protected override bool TryResolveTokenCore(SecurityKeyIdentifier keyIdentifier, out SecurityToken token)
|
|
{
|
|
bool resolved = false;
|
|
token = null;
|
|
|
|
resolved = this.tokenResolver.TryResolveToken(keyIdentifier, false, false, out token);
|
|
|
|
if (!resolved)
|
|
{
|
|
resolved = base.TryResolveTokenCore(keyIdentifier, out token);
|
|
}
|
|
|
|
if (!resolved)
|
|
{
|
|
for (int i = 0; i < keyIdentifier.Count; ++i)
|
|
{
|
|
if (this.TryResolveTokenFromIntrinsicKeyClause(keyIdentifier[i], out token))
|
|
{
|
|
resolved = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return resolved;
|
|
}
|
|
|
|
bool TryResolveTokenFromIntrinsicKeyClause(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityToken token)
|
|
{
|
|
token = null;
|
|
if (keyIdentifierClause is RsaKeyIdentifierClause)
|
|
{
|
|
token = new RsaSecurityToken(((RsaKeyIdentifierClause)keyIdentifierClause).Rsa);
|
|
return true;
|
|
}
|
|
else if (keyIdentifierClause is X509RawDataKeyIdentifierClause)
|
|
{
|
|
token = new X509SecurityToken(new X509Certificate2(((X509RawDataKeyIdentifierClause)keyIdentifierClause).GetX509RawData()), false);
|
|
return true;
|
|
}
|
|
else if (keyIdentifierClause is EncryptedKeyIdentifierClause)
|
|
{
|
|
EncryptedKeyIdentifierClause keyClause = (EncryptedKeyIdentifierClause)keyIdentifierClause;
|
|
SecurityKeyIdentifier wrappingTokenReference = keyClause.EncryptingKeyIdentifier;
|
|
SecurityToken unwrappingToken;
|
|
if (this.TryResolveToken(wrappingTokenReference, out unwrappingToken))
|
|
{
|
|
token = SecurityUtils.CreateTokenFromEncryptedKeyClause(keyClause, unwrappingToken);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected override bool TryResolveTokenCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityToken token)
|
|
{
|
|
bool resolved = false;
|
|
token = null;
|
|
|
|
resolved = this.tokenResolver.TryResolveToken(keyIdentifierClause, false, false, out token);
|
|
|
|
if (!resolved)
|
|
{
|
|
resolved = base.TryResolveTokenCore(keyIdentifierClause, out token);
|
|
}
|
|
|
|
if (!resolved)
|
|
{
|
|
resolved = TryResolveTokenFromIntrinsicKeyClause(keyIdentifierClause, out token);
|
|
}
|
|
|
|
return resolved;
|
|
}
|
|
}
|
|
}
|