AsymmetricSecurityProtocol.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. //----------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Security
  5. {
  6. using System.Collections.Generic;
  7. using System.Collections.ObjectModel;
  8. using System.IdentityModel.Policy;
  9. using System.IdentityModel.Selectors;
  10. using System.IdentityModel.Tokens;
  11. using System.Runtime;
  12. using System.ServiceModel;
  13. using System.ServiceModel.Channels;
  14. using System.ServiceModel.Description;
  15. using System.ServiceModel.Security.Tokens;
  16. sealed class AsymmetricSecurityProtocol : MessageSecurityProtocol
  17. {
  18. SecurityTokenAuthenticator initiatorAsymmetricTokenAuthenticator;
  19. SecurityTokenProvider initiatorAsymmetricTokenProvider;
  20. SecurityTokenProvider initiatorCryptoTokenProvider;
  21. public AsymmetricSecurityProtocol(AsymmetricSecurityProtocolFactory factory,
  22. EndpointAddress target, Uri via)
  23. : base(factory, target, via)
  24. {
  25. }
  26. protected override bool DoAutomaticEncryptionMatch
  27. {
  28. get { return false; }
  29. }
  30. AsymmetricSecurityProtocolFactory Factory
  31. {
  32. get { return (AsymmetricSecurityProtocolFactory)base.MessageSecurityProtocolFactory; }
  33. }
  34. public SecurityTokenProvider InitiatorCryptoTokenProvider
  35. {
  36. get
  37. {
  38. this.CommunicationObject.ThrowIfNotOpened();
  39. return this.initiatorCryptoTokenProvider;
  40. }
  41. }
  42. public SecurityTokenAuthenticator InitiatorAsymmetricTokenAuthenticator
  43. {
  44. get
  45. {
  46. this.CommunicationObject.ThrowIfNotOpened();
  47. return this.initiatorAsymmetricTokenAuthenticator;
  48. }
  49. }
  50. public SecurityTokenProvider InitiatorAsymmetricTokenProvider
  51. {
  52. get
  53. {
  54. this.CommunicationObject.ThrowIfNotOpened();
  55. return this.initiatorAsymmetricTokenProvider;
  56. }
  57. }
  58. public override void OnOpen(TimeSpan timeout)
  59. {
  60. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  61. base.OnOpen(timeoutHelper.RemainingTime());
  62. if (this.Factory.ActAsInitiator)
  63. {
  64. if (this.Factory.ApplyIntegrity)
  65. {
  66. InitiatorServiceModelSecurityTokenRequirement requirement = CreateInitiatorSecurityTokenRequirement();
  67. this.Factory.CryptoTokenParameters.InitializeSecurityTokenRequirement(requirement);
  68. requirement.KeyUsage = SecurityKeyUsage.Signature;
  69. requirement.Properties[ServiceModelSecurityTokenRequirement.MessageDirectionProperty] = MessageDirection.Output;
  70. this.initiatorCryptoTokenProvider = this.Factory.SecurityTokenManager.CreateSecurityTokenProvider(requirement);
  71. SecurityUtils.OpenTokenProviderIfRequired(this.initiatorCryptoTokenProvider, timeoutHelper.RemainingTime());
  72. }
  73. if (this.Factory.RequireIntegrity || this.Factory.ApplyConfidentiality)
  74. {
  75. InitiatorServiceModelSecurityTokenRequirement providerRequirement = CreateInitiatorSecurityTokenRequirement();
  76. this.Factory.AsymmetricTokenParameters.InitializeSecurityTokenRequirement(providerRequirement);
  77. providerRequirement.KeyUsage = SecurityKeyUsage.Exchange;
  78. providerRequirement.Properties[ServiceModelSecurityTokenRequirement.MessageDirectionProperty] = (this.Factory.ApplyConfidentiality) ? MessageDirection.Output : MessageDirection.Input;
  79. this.initiatorAsymmetricTokenProvider = this.Factory.SecurityTokenManager.CreateSecurityTokenProvider(providerRequirement);
  80. SecurityUtils.OpenTokenProviderIfRequired(this.initiatorAsymmetricTokenProvider, timeoutHelper.RemainingTime());
  81. InitiatorServiceModelSecurityTokenRequirement authenticatorRequirement = CreateInitiatorSecurityTokenRequirement();
  82. this.Factory.AsymmetricTokenParameters.InitializeSecurityTokenRequirement(authenticatorRequirement);
  83. authenticatorRequirement.IsOutOfBandToken = !this.Factory.AllowSerializedSigningTokenOnReply;
  84. authenticatorRequirement.KeyUsage = SecurityKeyUsage.Exchange;
  85. authenticatorRequirement.Properties[ServiceModelSecurityTokenRequirement.MessageDirectionProperty] = (this.Factory.ApplyConfidentiality) ? MessageDirection.Output : MessageDirection.Input;
  86. // Create authenticator (we dont support out of band resolvers on the client side
  87. SecurityTokenResolver outOfBandTokenResolver;
  88. this.initiatorAsymmetricTokenAuthenticator = this.Factory.SecurityTokenManager.CreateSecurityTokenAuthenticator(authenticatorRequirement, out outOfBandTokenResolver);
  89. SecurityUtils.OpenTokenAuthenticatorIfRequired(this.initiatorAsymmetricTokenAuthenticator, timeoutHelper.RemainingTime());
  90. }
  91. }
  92. }
  93. public override void OnAbort()
  94. {
  95. if (this.Factory.ActAsInitiator)
  96. {
  97. if (this.initiatorCryptoTokenProvider != null)
  98. {
  99. SecurityUtils.AbortTokenProviderIfRequired(this.initiatorCryptoTokenProvider);
  100. }
  101. if (this.initiatorAsymmetricTokenProvider != null)
  102. {
  103. SecurityUtils.AbortTokenProviderIfRequired(this.initiatorAsymmetricTokenProvider);
  104. }
  105. if (this.initiatorAsymmetricTokenAuthenticator != null)
  106. {
  107. SecurityUtils.AbortTokenAuthenticatorIfRequired(this.initiatorAsymmetricTokenAuthenticator);
  108. }
  109. }
  110. base.OnAbort();
  111. }
  112. public override void OnClose(TimeSpan timeout)
  113. {
  114. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  115. if (this.Factory.ActAsInitiator)
  116. {
  117. if (this.initiatorCryptoTokenProvider != null)
  118. {
  119. SecurityUtils.CloseTokenProviderIfRequired(this.initiatorCryptoTokenProvider, timeoutHelper.RemainingTime());
  120. }
  121. if (this.initiatorAsymmetricTokenProvider != null)
  122. {
  123. SecurityUtils.CloseTokenProviderIfRequired(this.initiatorAsymmetricTokenProvider, timeoutHelper.RemainingTime());
  124. }
  125. if (this.initiatorAsymmetricTokenAuthenticator != null)
  126. {
  127. SecurityUtils.CloseTokenAuthenticatorIfRequired(this.initiatorAsymmetricTokenAuthenticator, timeoutHelper.RemainingTime());
  128. }
  129. }
  130. base.OnClose(timeoutHelper.RemainingTime());
  131. }
  132. protected override IAsyncResult BeginSecureOutgoingMessageCore(Message message, TimeSpan timeout, SecurityProtocolCorrelationState correlationState, AsyncCallback callback, object state)
  133. {
  134. SecurityToken encryptingToken;
  135. SecurityToken signingToken;
  136. SecurityProtocolCorrelationState newCorrelationState;
  137. IList<SupportingTokenSpecification> supportingTokens;
  138. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  139. if (TryGetTokenSynchronouslyForOutgoingSecurity(message, correlationState, false, timeoutHelper.RemainingTime(), out encryptingToken, out signingToken, out supportingTokens, out newCorrelationState))
  140. {
  141. SetUpDelayedSecurityExecution(ref message, encryptingToken, signingToken, supportingTokens, GetSignatureConfirmationCorrelationState(correlationState, newCorrelationState));
  142. return new CompletedAsyncResult<Message, SecurityProtocolCorrelationState>(message, newCorrelationState, callback, state);
  143. }
  144. else
  145. {
  146. if (this.Factory.ActAsInitiator == false)
  147. {
  148. Fx.Assert("Unexpected code path for server security application");
  149. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SendingOutgoingmessageOnRecipient)));
  150. }
  151. AsymmetricSecurityProtocolFactory factory = this.Factory;
  152. SecurityTokenProvider encProvider = factory.ApplyConfidentiality ? this.initiatorAsymmetricTokenProvider : null;
  153. SecurityTokenProvider sigProvider = factory.ApplyIntegrity ? this.initiatorCryptoTokenProvider : null;
  154. return new SecureOutgoingMessageAsyncResult(message, this,
  155. encProvider, sigProvider, factory.ApplyConfidentiality, this.initiatorAsymmetricTokenAuthenticator, correlationState, timeoutHelper.RemainingTime(), callback, state);
  156. }
  157. }
  158. protected override void EndSecureOutgoingMessageCore(IAsyncResult result, out Message message, out SecurityProtocolCorrelationState newCorrelationState)
  159. {
  160. if (result is CompletedAsyncResult<Message, SecurityProtocolCorrelationState>)
  161. {
  162. message = CompletedAsyncResult<Message, SecurityProtocolCorrelationState>.End(result, out newCorrelationState);
  163. }
  164. else
  165. {
  166. message = SecureOutgoingMessageAsyncResult.End(result, out newCorrelationState);
  167. }
  168. }
  169. protected override SecurityProtocolCorrelationState SecureOutgoingMessageCore(ref Message message, TimeSpan timeout, SecurityProtocolCorrelationState correlationState)
  170. {
  171. SecurityToken encryptingToken;
  172. SecurityToken signingToken;
  173. SecurityProtocolCorrelationState newCorrelationState;
  174. IList<SupportingTokenSpecification> supportingTokens;
  175. TryGetTokenSynchronouslyForOutgoingSecurity(message, correlationState, true, timeout, out encryptingToken, out signingToken, out supportingTokens, out newCorrelationState);
  176. SetUpDelayedSecurityExecution(ref message, encryptingToken, signingToken, supportingTokens, GetSignatureConfirmationCorrelationState(correlationState, newCorrelationState));
  177. return newCorrelationState;
  178. }
  179. void SetUpDelayedSecurityExecution(ref Message message, SecurityToken encryptingToken, SecurityToken signingToken,
  180. IList<SupportingTokenSpecification> supportingTokens, SecurityProtocolCorrelationState correlationState)
  181. {
  182. AsymmetricSecurityProtocolFactory factory = this.Factory;
  183. string actor = string.Empty;
  184. SendSecurityHeader securityHeader = ConfigureSendSecurityHeader(message, actor, supportingTokens, correlationState);
  185. SecurityTokenParameters signingTokenParameters = (this.Factory.ActAsInitiator) ? this.Factory.CryptoTokenParameters : this.Factory.AsymmetricTokenParameters;
  186. SecurityTokenParameters encryptionTokenParameters = (this.Factory.ActAsInitiator) ? this.Factory.AsymmetricTokenParameters : this.Factory.CryptoTokenParameters;
  187. if (this.Factory.ApplyIntegrity || securityHeader.HasSignedTokens)
  188. {
  189. if (!this.Factory.ApplyIntegrity)
  190. {
  191. securityHeader.SignatureParts = MessagePartSpecification.NoParts;
  192. }
  193. securityHeader.SetSigningToken(signingToken, signingTokenParameters);
  194. }
  195. if (Factory.ApplyConfidentiality || securityHeader.HasEncryptedTokens)
  196. {
  197. if (!this.Factory.ApplyConfidentiality)
  198. {
  199. securityHeader.EncryptionParts = MessagePartSpecification.NoParts;
  200. }
  201. securityHeader.SetEncryptionToken(encryptingToken, encryptionTokenParameters);
  202. }
  203. message = securityHeader.SetupExecution();
  204. }
  205. void AttachRecipientSecurityProperty(Message message, SecurityToken initiatorToken, SecurityToken recipientToken, IList<SecurityToken> basicTokens, IList<SecurityToken> endorsingTokens,
  206. IList<SecurityToken> signedEndorsingTokens, IList<SecurityToken> signedTokens, Dictionary<SecurityToken, ReadOnlyCollection<IAuthorizationPolicy>> tokenPoliciesMapping)
  207. {
  208. SecurityMessageProperty security = SecurityMessageProperty.GetOrCreate(message);
  209. security.InitiatorToken = (initiatorToken != null) ? new SecurityTokenSpecification(initiatorToken, tokenPoliciesMapping[initiatorToken]) : null;
  210. security.RecipientToken = (recipientToken != null) ? new SecurityTokenSpecification(recipientToken, EmptyReadOnlyCollection<IAuthorizationPolicy>.Instance) : null;
  211. AddSupportingTokenSpecification(security, basicTokens, endorsingTokens, signedEndorsingTokens, signedTokens, tokenPoliciesMapping);
  212. security.ServiceSecurityContext = new ServiceSecurityContext(security.GetInitiatorTokenAuthorizationPolicies());
  213. }
  214. void DoIdentityCheckAndAttachInitiatorSecurityProperty(Message message, SecurityToken initiatorToken, SecurityToken recipientToken, ReadOnlyCollection<IAuthorizationPolicy> recipientTokenPolicies)
  215. {
  216. AuthorizationContext recipientAuthorizationContext = base.EnsureIncomingIdentity(message, recipientToken, recipientTokenPolicies);
  217. SecurityMessageProperty security = SecurityMessageProperty.GetOrCreate(message);
  218. security.InitiatorToken = (initiatorToken != null) ? new SecurityTokenSpecification(initiatorToken, EmptyReadOnlyCollection<IAuthorizationPolicy>.Instance) : null;
  219. security.RecipientToken = new SecurityTokenSpecification(recipientToken, recipientTokenPolicies);
  220. security.ServiceSecurityContext = new ServiceSecurityContext(recipientAuthorizationContext, recipientTokenPolicies ?? EmptyReadOnlyCollection<IAuthorizationPolicy>.Instance);
  221. }
  222. protected override SecurityProtocolCorrelationState VerifyIncomingMessageCore(ref Message message, string actor, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
  223. {
  224. AsymmetricSecurityProtocolFactory factory = this.Factory;
  225. IList<SupportingTokenAuthenticatorSpecification> supportingAuthenticators;
  226. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  227. ReceiveSecurityHeader securityHeader = ConfigureReceiveSecurityHeader(message, string.Empty, correlationStates, out supportingAuthenticators);
  228. SecurityToken requiredReplySigningToken = null;
  229. if (factory.ActAsInitiator)
  230. {
  231. SecurityToken encryptionToken = null;
  232. SecurityToken receiverToken = null;
  233. if (factory.RequireIntegrity)
  234. {
  235. receiverToken = GetToken(this.initiatorAsymmetricTokenProvider, null, timeoutHelper.RemainingTime());
  236. requiredReplySigningToken = receiverToken;
  237. }
  238. if (factory.RequireConfidentiality)
  239. {
  240. encryptionToken = GetCorrelationToken(correlationStates);
  241. if (!SecurityUtils.HasSymmetricSecurityKey(encryptionToken))
  242. {
  243. securityHeader.WrappedKeySecurityTokenAuthenticator = this.Factory.WrappedKeySecurityTokenAuthenticator;
  244. }
  245. }
  246. SecurityTokenAuthenticator primaryTokenAuthenticator;
  247. if (factory.AllowSerializedSigningTokenOnReply)
  248. {
  249. primaryTokenAuthenticator = this.initiatorAsymmetricTokenAuthenticator;
  250. requiredReplySigningToken = null;
  251. }
  252. else
  253. {
  254. primaryTokenAuthenticator = null;
  255. }
  256. securityHeader.ConfigureAsymmetricBindingClientReceiveHeader(receiverToken,
  257. factory.AsymmetricTokenParameters, encryptionToken, factory.CryptoTokenParameters,
  258. primaryTokenAuthenticator);
  259. }
  260. else
  261. {
  262. SecurityToken wrappingToken;
  263. if (this.Factory.RecipientAsymmetricTokenProvider != null && this.Factory.RequireConfidentiality)
  264. {
  265. wrappingToken = GetToken(factory.RecipientAsymmetricTokenProvider, null, timeoutHelper.RemainingTime());
  266. }
  267. else
  268. {
  269. wrappingToken = null;
  270. }
  271. securityHeader.ConfigureAsymmetricBindingServerReceiveHeader(this.Factory.RecipientCryptoTokenAuthenticator,
  272. this.Factory.CryptoTokenParameters, wrappingToken, this.Factory.AsymmetricTokenParameters, supportingAuthenticators);
  273. securityHeader.WrappedKeySecurityTokenAuthenticator = this.Factory.WrappedKeySecurityTokenAuthenticator;
  274. securityHeader.ConfigureOutOfBandTokenResolver(MergeOutOfBandResolvers(supportingAuthenticators, this.Factory.RecipientOutOfBandTokenResolverList));
  275. }
  276. ProcessSecurityHeader(securityHeader, ref message, requiredReplySigningToken, timeoutHelper.RemainingTime(), correlationStates);
  277. SecurityToken signingToken = securityHeader.SignatureToken;
  278. SecurityToken encryptingToken = securityHeader.EncryptionToken;
  279. if (factory.RequireIntegrity)
  280. {
  281. if (factory.ActAsInitiator)
  282. {
  283. ReadOnlyCollection<IAuthorizationPolicy> signingTokenPolicies = this.initiatorAsymmetricTokenAuthenticator.ValidateToken(signingToken);
  284. EnsureNonWrappedToken(signingToken, message);
  285. DoIdentityCheckAndAttachInitiatorSecurityProperty(message, encryptingToken, signingToken, signingTokenPolicies);
  286. }
  287. else
  288. {
  289. EnsureNonWrappedToken(signingToken, message);
  290. AttachRecipientSecurityProperty(message, signingToken, encryptingToken, securityHeader.BasicSupportingTokens, securityHeader.EndorsingSupportingTokens, securityHeader.SignedEndorsingSupportingTokens,
  291. securityHeader.SignedSupportingTokens, securityHeader.SecurityTokenAuthorizationPoliciesMapping);
  292. }
  293. }
  294. return GetCorrelationState(signingToken, securityHeader);
  295. }
  296. bool TryGetTokenSynchronouslyForOutgoingSecurity(Message message, SecurityProtocolCorrelationState correlationState, bool isBlockingCall, TimeSpan timeout,
  297. out SecurityToken encryptingToken, out SecurityToken signingToken, out IList<SupportingTokenSpecification> supportingTokens, out SecurityProtocolCorrelationState newCorrelationState)
  298. {
  299. AsymmetricSecurityProtocolFactory factory = this.Factory;
  300. encryptingToken = null;
  301. signingToken = null;
  302. newCorrelationState = null;
  303. supportingTokens = null;
  304. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  305. if (factory.ActAsInitiator)
  306. {
  307. if (!isBlockingCall || !TryGetSupportingTokens(this.Factory, this.Target, this.Via, message, timeoutHelper.RemainingTime(), isBlockingCall, out supportingTokens))
  308. {
  309. return false;
  310. }
  311. if (factory.ApplyConfidentiality)
  312. {
  313. encryptingToken = GetTokenAndEnsureOutgoingIdentity(this.initiatorAsymmetricTokenProvider, true, timeoutHelper.RemainingTime(), this.initiatorAsymmetricTokenAuthenticator);
  314. }
  315. if (factory.ApplyIntegrity)
  316. {
  317. signingToken = GetToken(this.initiatorCryptoTokenProvider, this.Target, timeoutHelper.RemainingTime());
  318. newCorrelationState = GetCorrelationState(signingToken);
  319. }
  320. }
  321. else
  322. {
  323. if (factory.ApplyConfidentiality)
  324. {
  325. encryptingToken = GetCorrelationToken(correlationState);
  326. }
  327. if (factory.ApplyIntegrity)
  328. {
  329. signingToken = GetToken(factory.RecipientAsymmetricTokenProvider, null, timeoutHelper.RemainingTime());
  330. }
  331. }
  332. return true;
  333. }
  334. sealed class SecureOutgoingMessageAsyncResult : GetTwoTokensAndSetUpSecurityAsyncResult
  335. {
  336. public SecureOutgoingMessageAsyncResult(Message m, AsymmetricSecurityProtocol binding,
  337. SecurityTokenProvider primaryProvider, SecurityTokenProvider secondaryProvider, bool doIdentityChecks, SecurityTokenAuthenticator identityCheckAuthenticator,
  338. SecurityProtocolCorrelationState correlationState, TimeSpan timeout, AsyncCallback callback, object state)
  339. : base(m, binding, primaryProvider, secondaryProvider, doIdentityChecks, identityCheckAuthenticator, correlationState, timeout, callback, state)
  340. {
  341. Start();
  342. }
  343. protected override void OnBothGetTokenCallsDone(ref Message message, SecurityToken primaryToken, SecurityToken secondaryToken, TimeSpan timeout)
  344. {
  345. AsymmetricSecurityProtocol binding = (AsymmetricSecurityProtocol)this.Binding;
  346. if (secondaryToken != null)
  347. this.SetCorrelationToken(secondaryToken);
  348. binding.SetUpDelayedSecurityExecution(ref message, primaryToken, secondaryToken, this.SupportingTokens, binding.GetSignatureConfirmationCorrelationState(OldCorrelationState, NewCorrelationState));
  349. }
  350. }
  351. }
  352. }