| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- //----------------------------------------------------------
- // 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.ServiceModel;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Description;
- using System.ServiceModel.Diagnostics;
- using System.ServiceModel.Security.Tokens;
- sealed class SymmetricSecurityProtocol : MessageSecurityProtocol
- {
- SecurityTokenProvider initiatorSymmetricTokenProvider;
- SecurityTokenProvider initiatorAsymmetricTokenProvider;
- SecurityTokenAuthenticator initiatorTokenAuthenticator;
- public SymmetricSecurityProtocol(SymmetricSecurityProtocolFactory factory,
- EndpointAddress target, Uri via)
- : base(factory, target, via)
- {
- }
- SymmetricSecurityProtocolFactory Factory
- {
- get { return (SymmetricSecurityProtocolFactory)base.MessageSecurityProtocolFactory; }
- }
- public SecurityTokenProvider InitiatorSymmetricTokenProvider
- {
- get
- {
- this.CommunicationObject.ThrowIfNotOpened();
- return this.initiatorSymmetricTokenProvider;
- }
- }
- public SecurityTokenProvider InitiatorAsymmetricTokenProvider
- {
- get
- {
- this.CommunicationObject.ThrowIfNotOpened();
- return this.initiatorAsymmetricTokenProvider;
- }
- }
- public SecurityTokenAuthenticator InitiatorTokenAuthenticator
- {
- get
- {
- this.CommunicationObject.ThrowIfNotOpened();
- return this.initiatorTokenAuthenticator;
- }
- }
- InitiatorServiceModelSecurityTokenRequirement CreateInitiatorTokenRequirement()
- {
- InitiatorServiceModelSecurityTokenRequirement tokenRequirement = CreateInitiatorSecurityTokenRequirement();
- this.Factory.SecurityTokenParameters.InitializeSecurityTokenRequirement(tokenRequirement);
- tokenRequirement.KeyUsage = this.Factory.SecurityTokenParameters.HasAsymmetricKey ? SecurityKeyUsage.Exchange : SecurityKeyUsage.Signature;
- tokenRequirement.Properties[ServiceModelSecurityTokenRequirement.MessageDirectionProperty] = MessageDirection.Output;
- if (this.Factory.SecurityTokenParameters.HasAsymmetricKey)
- {
- tokenRequirement.IsOutOfBandToken = true;
- }
- return tokenRequirement;
- }
- public override void OnOpen(TimeSpan timeout)
- {
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- base.OnOpen(timeoutHelper.RemainingTime());
- if (this.Factory.ActAsInitiator)
- {
- // 1. Create a token requirement for the provider
- InitiatorServiceModelSecurityTokenRequirement tokenProviderRequirement = CreateInitiatorTokenRequirement();
- // 2. Create a provider
- SecurityTokenProvider tokenProvider = this.Factory.SecurityTokenManager.CreateSecurityTokenProvider(tokenProviderRequirement);
- SecurityUtils.OpenTokenProviderIfRequired(tokenProvider, timeoutHelper.RemainingTime());
- if (this.Factory.SecurityTokenParameters.HasAsymmetricKey)
- {
- this.initiatorAsymmetricTokenProvider = tokenProvider;
- }
- else
- {
- this.initiatorSymmetricTokenProvider = tokenProvider;
- }
- // 3. Create a token requirement for authenticator
- InitiatorServiceModelSecurityTokenRequirement tokenAuthenticatorRequirement = CreateInitiatorTokenRequirement();
- // 4. Create authenticator (we dont support out of band resolvers on the client side
- SecurityTokenResolver outOfBandTokenResolver;
- this.initiatorTokenAuthenticator = this.Factory.SecurityTokenManager.CreateSecurityTokenAuthenticator(tokenAuthenticatorRequirement, out outOfBandTokenResolver);
- SecurityUtils.OpenTokenAuthenticatorIfRequired(this.initiatorTokenAuthenticator, timeoutHelper.RemainingTime());
- }
- }
- public override void OnAbort()
- {
- if (this.Factory.ActAsInitiator)
- {
- SecurityTokenProvider provider = this.initiatorSymmetricTokenProvider ?? this.initiatorAsymmetricTokenProvider;
- if (provider != null)
- {
- SecurityUtils.AbortTokenProviderIfRequired(provider);
- }
- if (this.initiatorTokenAuthenticator != null)
- {
- SecurityUtils.AbortTokenAuthenticatorIfRequired(this.initiatorTokenAuthenticator);
- }
- }
- base.OnAbort();
- }
- public override void OnClose(TimeSpan timeout)
- {
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- if (this.Factory.ActAsInitiator)
- {
- SecurityTokenProvider provider = this.initiatorSymmetricTokenProvider ?? this.initiatorAsymmetricTokenProvider;
- if (provider != null)
- {
- SecurityUtils.CloseTokenProviderIfRequired(provider, timeoutHelper.RemainingTime());
- }
- if (this.initiatorTokenAuthenticator != null)
- {
- SecurityUtils.CloseTokenAuthenticatorIfRequired(this.initiatorTokenAuthenticator, timeoutHelper.RemainingTime());
- }
- }
- base.OnClose(timeoutHelper.RemainingTime());
- }
- SecurityTokenProvider GetTokenProvider()
- {
- if (this.Factory.ActAsInitiator)
- {
- return (this.initiatorSymmetricTokenProvider ?? this.initiatorAsymmetricTokenProvider);
- }
- else
- {
- return this.Factory.RecipientAsymmetricTokenProvider;
- }
- }
- protected override IAsyncResult BeginSecureOutgoingMessageCore(Message message, TimeSpan timeout, SecurityProtocolCorrelationState correlationState, AsyncCallback callback, object state)
- {
- SecurityToken token;
- SecurityTokenParameters tokenParameters;
- IList<SupportingTokenSpecification> supportingTokens;
- SecurityToken prerequisiteWrappingToken;
- SecurityProtocolCorrelationState newCorrelationState;
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- if (TryGetTokenSynchronouslyForOutgoingSecurity(message, correlationState, false, timeoutHelper.RemainingTime(), out token, out tokenParameters, out prerequisiteWrappingToken, out supportingTokens, out newCorrelationState))
- {
- SetUpDelayedSecurityExecution(ref message, prerequisiteWrappingToken, token, tokenParameters, supportingTokens, GetSignatureConfirmationCorrelationState(correlationState, newCorrelationState));
- return new CompletedAsyncResult<Message, SecurityProtocolCorrelationState>(message, newCorrelationState, callback, state);
- }
- else
- {
- if (this.Factory.ActAsInitiator != true)
- {
- Fx.Assert("Unexpected code path for server security application");
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ProtocolMustBeInitiator, this.GetType().ToString())));
- }
- SecurityTokenProvider provider = GetTokenProvider();
- return new SecureOutgoingMessageAsyncResult(message, this, provider, this.Factory.ApplyConfidentiality, this.initiatorTokenAuthenticator, correlationState, timeoutHelper.RemainingTime(), callback, state);
- }
- }
- protected override SecurityProtocolCorrelationState SecureOutgoingMessageCore(ref Message message, TimeSpan timeout, SecurityProtocolCorrelationState correlationState)
- {
- SecurityToken token;
- SecurityTokenParameters tokenParameters;
- IList<SupportingTokenSpecification> supportingTokens;
- SecurityToken prerequisiteWrappingToken;
- SecurityProtocolCorrelationState newCorrelationState;
- TryGetTokenSynchronouslyForOutgoingSecurity(message, correlationState, true, timeout, out token, out tokenParameters, out prerequisiteWrappingToken, out supportingTokens, out newCorrelationState);
- SetUpDelayedSecurityExecution(ref message, prerequisiteWrappingToken, token, tokenParameters, supportingTokens, GetSignatureConfirmationCorrelationState(correlationState, newCorrelationState));
- return newCorrelationState;
- }
- void SetUpDelayedSecurityExecution(ref Message message,
- SecurityToken prerequisiteToken,
- SecurityToken primaryToken,
- SecurityTokenParameters primaryTokenParameters,
- IList<SupportingTokenSpecification> supportingTokens,
- SecurityProtocolCorrelationState correlationState
- )
- {
- string actor = string.Empty;
- SendSecurityHeader securityHeader = ConfigureSendSecurityHeader(message, actor, supportingTokens, correlationState);
- if (prerequisiteToken != null)
- {
- securityHeader.AddPrerequisiteToken(prerequisiteToken);
- }
- if (this.Factory.ApplyIntegrity || securityHeader.HasSignedTokens)
- {
- if (!this.Factory.ApplyIntegrity)
- {
- securityHeader.SignatureParts = MessagePartSpecification.NoParts;
- }
- securityHeader.SetSigningToken(primaryToken, primaryTokenParameters);
- }
- if (Factory.ApplyConfidentiality || securityHeader.HasEncryptedTokens)
- {
- if (!this.Factory.ApplyConfidentiality)
- {
- securityHeader.EncryptionParts = MessagePartSpecification.NoParts;
- }
- securityHeader.SetEncryptionToken(primaryToken, primaryTokenParameters);
- }
- message = securityHeader.SetupExecution();
- }
- protected override void EndSecureOutgoingMessageCore(IAsyncResult result, out Message message, out SecurityProtocolCorrelationState newCorrelationState)
- {
- if (result is CompletedAsyncResult<Message, SecurityProtocolCorrelationState>)
- {
- message = CompletedAsyncResult<Message, SecurityProtocolCorrelationState>.End(result, out newCorrelationState);
- }
- else
- {
- message = SecureOutgoingMessageAsyncResult.End(result, out newCorrelationState);
- }
- }
- WrappedKeySecurityToken CreateWrappedKeyToken(SecurityToken wrappingToken, SecurityTokenParameters wrappingTokenParameters, SecurityTokenReferenceStyle wrappingTokenReferenceStyle)
- {
- int keyLength = Math.Max(128, this.Factory.OutgoingAlgorithmSuite.DefaultSymmetricKeyLength);
- CryptoHelper.ValidateSymmetricKeyLength(keyLength, this.Factory.OutgoingAlgorithmSuite);
- byte[] key = new byte[keyLength / 8];
- CryptoHelper.FillRandomBytes(key);
- string tokenId = SecurityUtils.GenerateId();
- string wrappingAlgorithm = this.Factory.OutgoingAlgorithmSuite.DefaultAsymmetricKeyWrapAlgorithm;
- SecurityKeyIdentifierClause clause = wrappingTokenParameters.CreateKeyIdentifierClause(wrappingToken, wrappingTokenReferenceStyle);
- SecurityKeyIdentifier identifier = new SecurityKeyIdentifier();
- identifier.Add(clause);
- return new WrappedKeySecurityToken(tokenId, key, wrappingAlgorithm, wrappingToken, identifier);
- }
- SecurityToken GetInitiatorToken(SecurityToken providerToken,
- Message message,
- TimeSpan timeout,
- out SecurityTokenParameters tokenParameters,
- out SecurityToken prerequisiteWrappingToken)
- {
- tokenParameters = null;
- prerequisiteWrappingToken = null;
- SecurityToken token;
- if (this.Factory.SecurityTokenParameters.HasAsymmetricKey)
- {
- SecurityToken asymmetricToken = providerToken;
- // non-Indigo server implementations might require the wrapping token to be included in the message
- bool isAsymmetricTokenInMessage = SendSecurityHeader.ShouldSerializeToken(this.Factory.SecurityTokenParameters, MessageDirection.Input);
- if (isAsymmetricTokenInMessage)
- {
- prerequisiteWrappingToken = asymmetricToken;
- }
- token = CreateWrappedKeyToken(asymmetricToken, this.Factory.SecurityTokenParameters, (isAsymmetricTokenInMessage) ? SecurityTokenReferenceStyle.Internal : SecurityTokenReferenceStyle.External);
- }
- else
- {
- token = providerToken;
- }
- tokenParameters = this.Factory.GetProtectionTokenParameters();
- return token;
- }
- // try to get the token if it can be obtained within the
- // synchronous requirements of the call; return true iff a
- // token not required OR a token is required AND has been
- // obtained within the specified synchronous requirements.
- bool TryGetTokenSynchronouslyForOutgoingSecurity(Message message, SecurityProtocolCorrelationState correlationState, bool isBlockingCall, TimeSpan timeout, out SecurityToken token, out SecurityTokenParameters tokenParameters, out SecurityToken prerequisiteWrappingToken, out IList<SupportingTokenSpecification> supportingTokens, out SecurityProtocolCorrelationState newCorrelationState)
- {
- SymmetricSecurityProtocolFactory factory = this.Factory;
- supportingTokens = null;
- prerequisiteWrappingToken = null;
- token = null;
- tokenParameters = null;
- newCorrelationState = null;
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- if (factory.ApplyIntegrity || factory.ApplyConfidentiality)
- {
- if (factory.ActAsInitiator)
- {
- if (!isBlockingCall || !TryGetSupportingTokens(factory, this.Target, this.Via, message, timeoutHelper.RemainingTime(), isBlockingCall, out supportingTokens))
- {
- return false;
- }
- SecurityTokenProvider provider = GetTokenProvider();
- SecurityToken providerToken = GetTokenAndEnsureOutgoingIdentity(provider, factory.ApplyConfidentiality, timeoutHelper.RemainingTime(), this.initiatorTokenAuthenticator);
- token = GetInitiatorToken(providerToken, message, timeoutHelper.RemainingTime(), out tokenParameters, out prerequisiteWrappingToken);
- newCorrelationState = GetCorrelationState(token);
- }
- else
- {
- token = GetCorrelationToken(correlationState);
- tokenParameters = this.Factory.GetProtectionTokenParameters();
- }
- }
- return true;
- }
- SecurityToken GetCorrelationToken(SecurityProtocolCorrelationState[] correlationStates, out SecurityTokenParameters correlationTokenParameters)
- {
- SecurityToken token = GetCorrelationToken(correlationStates);
- correlationTokenParameters = this.Factory.GetProtectionTokenParameters();
- return token;
- }
- void EnsureWrappedToken(SecurityToken token, Message message)
- {
- if (!(token is WrappedKeySecurityToken))
- {
- throw TraceUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.IncomingSigningTokenMustBeAnEncryptedKey)), message);
- }
- }
- protected override SecurityProtocolCorrelationState VerifyIncomingMessageCore(ref Message message, string actor, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
- {
- SymmetricSecurityProtocolFactory factory = this.Factory;
- IList<SupportingTokenAuthenticatorSpecification> supportingAuthenticators;
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- ReceiveSecurityHeader securityHeader = ConfigureReceiveSecurityHeader(message, string.Empty, correlationStates, out supportingAuthenticators);
- SecurityToken requiredReplySigningToken = null;
- if (this.Factory.ActAsInitiator)
- {
- // set the outofband protection token
- SecurityTokenParameters outOfBandTokenParameters;
- SecurityToken outOfBandToken = GetCorrelationToken(correlationStates, out outOfBandTokenParameters);
- securityHeader.ConfigureSymmetricBindingClientReceiveHeader(outOfBandToken, outOfBandTokenParameters);
- requiredReplySigningToken = outOfBandToken;
- }
- else
- {
- if (factory.RecipientSymmetricTokenAuthenticator != null)
- {
- securityHeader.ConfigureSymmetricBindingServerReceiveHeader(this.Factory.RecipientSymmetricTokenAuthenticator, this.Factory.SecurityTokenParameters, supportingAuthenticators);
- }
- else
- {
- securityHeader.ConfigureSymmetricBindingServerReceiveHeader(this.Factory.RecipientAsymmetricTokenProvider.GetToken(timeoutHelper.RemainingTime()), this.Factory.SecurityTokenParameters, supportingAuthenticators);
- securityHeader.WrappedKeySecurityTokenAuthenticator = this.Factory.WrappedKeySecurityTokenAuthenticator;
- }
- securityHeader.ConfigureOutOfBandTokenResolver(MergeOutOfBandResolvers(supportingAuthenticators, this.Factory.RecipientOutOfBandTokenResolverList));
- }
- ProcessSecurityHeader(securityHeader, ref message, requiredReplySigningToken, timeoutHelper.RemainingTime(), correlationStates);
- SecurityToken signingToken = securityHeader.SignatureToken;
- if (factory.RequireIntegrity)
- {
- if (factory.SecurityTokenParameters.HasAsymmetricKey)
- {
- // enforce that the signing token is a wrapped key token
- EnsureWrappedToken(signingToken, message);
- }
- else
- {
- EnsureNonWrappedToken(signingToken, message);
- }
- if (factory.ActAsInitiator)
- {
- if (!factory.SecurityTokenParameters.HasAsymmetricKey)
- {
- ReadOnlyCollection<IAuthorizationPolicy> signingTokenPolicies = this.initiatorTokenAuthenticator.ValidateToken(signingToken);
- DoIdentityCheckAndAttachInitiatorSecurityProperty(message, signingToken, signingTokenPolicies);
- }
- else
- {
- SecurityToken wrappingToken = (signingToken as WrappedKeySecurityToken).WrappingToken;
- ReadOnlyCollection<IAuthorizationPolicy> wrappingTokenPolicies = this.initiatorTokenAuthenticator.ValidateToken(wrappingToken);
- DoIdentityCheckAndAttachInitiatorSecurityProperty(message, signingToken, wrappingTokenPolicies);
- }
- }
- else
- {
- AttachRecipientSecurityProperty(message, signingToken, this.Factory.SecurityTokenParameters.HasAsymmetricKey, securityHeader.BasicSupportingTokens, securityHeader.EndorsingSupportingTokens, securityHeader.SignedEndorsingSupportingTokens,
- securityHeader.SignedSupportingTokens, securityHeader.SecurityTokenAuthorizationPoliciesMapping);
- }
- }
- return GetCorrelationState(signingToken, securityHeader);
- }
- sealed class SecureOutgoingMessageAsyncResult : GetOneTokenAndSetUpSecurityAsyncResult
- {
- SymmetricSecurityProtocol symmetricBinding;
- public SecureOutgoingMessageAsyncResult(Message m, SymmetricSecurityProtocol binding, SecurityTokenProvider provider,
- bool doIdentityChecks, SecurityTokenAuthenticator identityCheckAuthenticator, SecurityProtocolCorrelationState correlationState, TimeSpan timeout, AsyncCallback callback, object state)
- : base(m, binding, provider, doIdentityChecks, identityCheckAuthenticator, correlationState, timeout, callback, state)
- {
- symmetricBinding = binding;
- Start();
- }
- protected override void OnGetTokenDone(ref Message message, SecurityToken providerToken, TimeSpan timeout)
- {
- SecurityTokenParameters tokenParameters;
- SecurityToken prerequisiteWrappingToken;
- SecurityToken token = symmetricBinding.GetInitiatorToken(providerToken, message, timeout, out tokenParameters, out prerequisiteWrappingToken);
- this.SetCorrelationToken(token);
- symmetricBinding.SetUpDelayedSecurityExecution(ref message, prerequisiteWrappingToken, token, tokenParameters, this.SupportingTokens, Binding.GetSignatureConfirmationCorrelationState(OldCorrelationState, NewCorrelationState));
- }
- }
- }
- }
|