SecurityAppliedMessage.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Security
  5. {
  6. using System.IO;
  7. using System.Runtime;
  8. using System.Security.Cryptography;
  9. using System.ServiceModel.Channels;
  10. using System.ServiceModel.Security.Tokens;
  11. using System.Xml;
  12. using System.IdentityModel.Tokens;
  13. using System.Collections.Generic;
  14. using IPrefixGenerator = System.IdentityModel.IPrefixGenerator;
  15. using ISecurityElement = System.IdentityModel.ISecurityElement;
  16. using XmlAttributeHolder = System.IdentityModel.XmlAttributeHolder;
  17. sealed class SecurityAppliedMessage : DelegatingMessage
  18. {
  19. string bodyId;
  20. bool bodyIdInserted;
  21. string bodyPrefix = MessageStrings.Prefix;
  22. XmlBuffer fullBodyBuffer;
  23. ISecurityElement encryptedBodyContent;
  24. XmlAttributeHolder[] bodyAttributes;
  25. bool delayedApplicationHandled;
  26. readonly MessagePartProtectionMode bodyProtectionMode;
  27. BodyState state = BodyState.Created;
  28. readonly SendSecurityHeader securityHeader;
  29. MemoryStream startBodyFragment;
  30. MemoryStream endBodyFragment;
  31. byte[] fullBodyFragment;
  32. int fullBodyFragmentLength;
  33. public SecurityAppliedMessage(Message messageToProcess, SendSecurityHeader securityHeader, bool signBody, bool encryptBody)
  34. : base(messageToProcess)
  35. {
  36. Fx.Assert(!(messageToProcess is SecurityAppliedMessage), "SecurityAppliedMessage should not be wrapped");
  37. this.securityHeader = securityHeader;
  38. this.bodyProtectionMode = MessagePartProtectionModeHelper.GetProtectionMode(signBody, encryptBody, securityHeader.SignThenEncrypt);
  39. }
  40. public string BodyId
  41. {
  42. get { return this.bodyId; }
  43. }
  44. public MessagePartProtectionMode BodyProtectionMode
  45. {
  46. get { return this.bodyProtectionMode; }
  47. }
  48. internal byte[] PrimarySignatureValue
  49. {
  50. get { return this.securityHeader.PrimarySignatureValue; }
  51. }
  52. Exception CreateBadStateException(string operation)
  53. {
  54. return new InvalidOperationException(SR.GetString(SR.MessageBodyOperationNotValidInBodyState,
  55. operation, this.state));
  56. }
  57. void EnsureUniqueSecurityApplication()
  58. {
  59. if (this.delayedApplicationHandled)
  60. {
  61. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DelayedSecurityApplicationAlreadyCompleted)));
  62. }
  63. this.delayedApplicationHandled = true;
  64. }
  65. protected override void OnBodyToString(XmlDictionaryWriter writer)
  66. {
  67. if (this.state == BodyState.Created || this.fullBodyFragment != null)
  68. {
  69. base.OnBodyToString(writer);
  70. }
  71. else
  72. {
  73. OnWriteBodyContents(writer);
  74. }
  75. }
  76. protected override void OnClose()
  77. {
  78. try
  79. {
  80. this.InnerMessage.Close();
  81. }
  82. finally
  83. {
  84. this.fullBodyBuffer = null;
  85. this.bodyAttributes = null;
  86. this.encryptedBodyContent = null;
  87. this.state = BodyState.Disposed;
  88. }
  89. }
  90. protected override void OnWriteStartBody(XmlDictionaryWriter writer)
  91. {
  92. if (this.startBodyFragment != null || this.fullBodyFragment != null)
  93. {
  94. WriteStartInnerMessageWithId(writer);
  95. return;
  96. }
  97. switch (this.state)
  98. {
  99. case BodyState.Created:
  100. case BodyState.Encrypted:
  101. this.InnerMessage.WriteStartBody(writer);
  102. return;
  103. case BodyState.Signed:
  104. case BodyState.EncryptedThenSigned:
  105. XmlDictionaryReader reader = fullBodyBuffer.GetReader(0);
  106. writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
  107. writer.WriteAttributes(reader, false);
  108. reader.Close();
  109. return;
  110. case BodyState.SignedThenEncrypted:
  111. writer.WriteStartElement(this.bodyPrefix, XD.MessageDictionary.Body, this.Version.Envelope.DictionaryNamespace);
  112. if (this.bodyAttributes != null)
  113. {
  114. XmlAttributeHolder.WriteAttributes(this.bodyAttributes, writer);
  115. }
  116. return;
  117. default:
  118. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBadStateException("OnWriteStartBody"));
  119. }
  120. }
  121. protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
  122. {
  123. switch (this.state)
  124. {
  125. case BodyState.Created:
  126. this.InnerMessage.WriteBodyContents(writer);
  127. return;
  128. case BodyState.Signed:
  129. case BodyState.EncryptedThenSigned:
  130. XmlDictionaryReader reader = fullBodyBuffer.GetReader(0);
  131. reader.ReadStartElement();
  132. while (reader.NodeType != XmlNodeType.EndElement)
  133. writer.WriteNode(reader, false);
  134. reader.ReadEndElement();
  135. reader.Close();
  136. return;
  137. case BodyState.Encrypted:
  138. case BodyState.SignedThenEncrypted:
  139. this.encryptedBodyContent.WriteTo(writer, ServiceModelDictionaryManager.Instance);
  140. break;
  141. default:
  142. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBadStateException("OnWriteBodyContents"));
  143. }
  144. }
  145. protected override void OnWriteMessage(XmlDictionaryWriter writer)
  146. {
  147. // For Kerb one shot, the channel binding will be need to be fished out of the message, cached and added to the
  148. // token before calling ISC.
  149. AttachChannelBindingTokenIfFound();
  150. EnsureUniqueSecurityApplication();
  151. MessagePrefixGenerator prefixGenerator = new MessagePrefixGenerator(writer);
  152. this.securityHeader.StartSecurityApplication();
  153. this.Headers.Add(this.securityHeader);
  154. this.InnerMessage.WriteStartEnvelope(writer);
  155. this.Headers.RemoveAt(this.Headers.Count - 1);
  156. this.securityHeader.ApplyBodySecurity(writer, prefixGenerator);
  157. this.InnerMessage.WriteStartHeaders(writer);
  158. this.securityHeader.ApplySecurityAndWriteHeaders(this.Headers, writer, prefixGenerator);
  159. this.securityHeader.RemoveSignatureEncryptionIfAppropriate();
  160. this.securityHeader.CompleteSecurityApplication();
  161. this.securityHeader.WriteHeader(writer, this.Version);
  162. writer.WriteEndElement();
  163. if (this.fullBodyFragment != null)
  164. {
  165. ((IFragmentCapableXmlDictionaryWriter) writer).WriteFragment(this.fullBodyFragment, 0, this.fullBodyFragmentLength);
  166. }
  167. else
  168. {
  169. if (this.startBodyFragment != null)
  170. {
  171. ((IFragmentCapableXmlDictionaryWriter) writer).WriteFragment(this.startBodyFragment.GetBuffer(), 0, (int) this.startBodyFragment.Length);
  172. }
  173. else
  174. {
  175. OnWriteStartBody(writer);
  176. }
  177. OnWriteBodyContents(writer);
  178. if (this.endBodyFragment != null)
  179. {
  180. ((IFragmentCapableXmlDictionaryWriter) writer).WriteFragment(this.endBodyFragment.GetBuffer(), 0, (int) this.endBodyFragment.Length);
  181. }
  182. else
  183. {
  184. writer.WriteEndElement();
  185. }
  186. }
  187. writer.WriteEndElement();
  188. }
  189. void AttachChannelBindingTokenIfFound()
  190. {
  191. ChannelBindingMessageProperty cbmp = null;
  192. ChannelBindingMessageProperty.TryGet(this.InnerMessage, out cbmp);
  193. if (cbmp != null)
  194. {
  195. if (this.securityHeader.ElementContainer != null && this.securityHeader.ElementContainer.EndorsingSupportingTokens != null)
  196. {
  197. foreach (SecurityToken token in this.securityHeader.ElementContainer.EndorsingSupportingTokens)
  198. {
  199. ProviderBackedSecurityToken pbst = token as ProviderBackedSecurityToken;
  200. if (pbst != null)
  201. {
  202. pbst.ChannelBinding = cbmp.ChannelBinding;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. void SetBodyId()
  209. {
  210. this.bodyId = this.InnerMessage.GetBodyAttribute(
  211. UtilityStrings.IdAttribute,
  212. this.securityHeader.StandardsManager.IdManager.DefaultIdNamespaceUri);
  213. if (this.bodyId == null)
  214. {
  215. this.bodyId = this.securityHeader.GenerateId();
  216. this.bodyIdInserted = true;
  217. }
  218. }
  219. public void WriteBodyToEncrypt(EncryptedData encryptedData, SymmetricAlgorithm algorithm)
  220. {
  221. encryptedData.Id = this.securityHeader.GenerateId();
  222. BodyContentHelper helper = new BodyContentHelper();
  223. XmlDictionaryWriter encryptingWriter = helper.CreateWriter();
  224. this.InnerMessage.WriteBodyContents(encryptingWriter);
  225. encryptedData.SetUpEncryption(algorithm, helper.ExtractResult());
  226. this.encryptedBodyContent = encryptedData;
  227. this.state = BodyState.Encrypted;
  228. }
  229. public void WriteBodyToEncryptThenSign(Stream canonicalStream, EncryptedData encryptedData, SymmetricAlgorithm algorithm)
  230. {
  231. encryptedData.Id = this.securityHeader.GenerateId();
  232. SetBodyId();
  233. XmlDictionaryWriter encryptingWriter = XmlDictionaryWriter.CreateTextWriter(Stream.Null);
  234. // The XmlSerializer body formatter would add a
  235. // document declaration to the body fragment when a fresh writer
  236. // is provided. Hence, insert a dummy element here and capture
  237. // the body contents as a fragment.
  238. encryptingWriter.WriteStartElement("a");
  239. MemoryStream ms = new MemoryStream();
  240. ((IFragmentCapableXmlDictionaryWriter)encryptingWriter).StartFragment(ms, true);
  241. this.InnerMessage.WriteBodyContents(encryptingWriter);
  242. ((IFragmentCapableXmlDictionaryWriter)encryptingWriter).EndFragment();
  243. encryptingWriter.WriteEndElement();
  244. ms.Flush();
  245. encryptedData.SetUpEncryption(algorithm, new ArraySegment<byte>(ms.GetBuffer(), 0, (int) ms.Length));
  246. this.fullBodyBuffer = new XmlBuffer(int.MaxValue);
  247. XmlDictionaryWriter canonicalWriter = this.fullBodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
  248. canonicalWriter.StartCanonicalization(canonicalStream, false, null);
  249. WriteStartInnerMessageWithId(canonicalWriter);
  250. encryptedData.WriteTo(canonicalWriter, ServiceModelDictionaryManager.Instance);
  251. canonicalWriter.WriteEndElement();
  252. canonicalWriter.EndCanonicalization();
  253. canonicalWriter.Flush();
  254. this.fullBodyBuffer.CloseSection();
  255. this.fullBodyBuffer.Close();
  256. this.state = BodyState.EncryptedThenSigned;
  257. }
  258. public void WriteBodyToSign(Stream canonicalStream)
  259. {
  260. SetBodyId();
  261. this.fullBodyBuffer = new XmlBuffer(int.MaxValue);
  262. XmlDictionaryWriter canonicalWriter = this.fullBodyBuffer.OpenSection(XmlDictionaryReaderQuotas.Max);
  263. canonicalWriter.StartCanonicalization(canonicalStream, false, null);
  264. WriteInnerMessageWithId(canonicalWriter);
  265. canonicalWriter.EndCanonicalization();
  266. canonicalWriter.Flush();
  267. this.fullBodyBuffer.CloseSection();
  268. this.fullBodyBuffer.Close();
  269. this.state = BodyState.Signed;
  270. }
  271. public void WriteBodyToSignThenEncrypt(Stream canonicalStream, EncryptedData encryptedData, SymmetricAlgorithm algorithm)
  272. {
  273. XmlBuffer buffer = new XmlBuffer(int.MaxValue);
  274. XmlDictionaryWriter fragmentingWriter = buffer.OpenSection(XmlDictionaryReaderQuotas.Max);
  275. WriteBodyToSignThenEncryptWithFragments(canonicalStream, false, null, encryptedData, algorithm, fragmentingWriter);
  276. ((IFragmentCapableXmlDictionaryWriter)fragmentingWriter).WriteFragment(this.startBodyFragment.GetBuffer(), 0, (int)this.startBodyFragment.Length);
  277. ((IFragmentCapableXmlDictionaryWriter)fragmentingWriter).WriteFragment(this.endBodyFragment.GetBuffer(), 0, (int)this.endBodyFragment.Length);
  278. buffer.CloseSection();
  279. buffer.Close();
  280. this.startBodyFragment = null;
  281. this.endBodyFragment = null;
  282. XmlDictionaryReader reader = buffer.GetReader(0);
  283. reader.MoveToContent();
  284. this.bodyPrefix = reader.Prefix;
  285. if (reader.HasAttributes)
  286. {
  287. this.bodyAttributes = XmlAttributeHolder.ReadAttributes(reader);
  288. }
  289. reader.Close();
  290. }
  291. public void WriteBodyToSignThenEncryptWithFragments(
  292. Stream stream, bool includeComments, string[] inclusivePrefixes,
  293. EncryptedData encryptedData, SymmetricAlgorithm algorithm, XmlDictionaryWriter writer)
  294. {
  295. IFragmentCapableXmlDictionaryWriter fragmentingWriter = (IFragmentCapableXmlDictionaryWriter) writer;
  296. SetBodyId();
  297. encryptedData.Id = this.securityHeader.GenerateId();
  298. this.startBodyFragment = new MemoryStream();
  299. BufferedOutputStream bodyContentFragment = new BufferManagerOutputStream(SR.XmlBufferQuotaExceeded, 1024, int.MaxValue, this.securityHeader.StreamBufferManager);
  300. this.endBodyFragment = new MemoryStream();
  301. writer.StartCanonicalization(stream, includeComments, inclusivePrefixes);
  302. fragmentingWriter.StartFragment(this.startBodyFragment, false);
  303. WriteStartInnerMessageWithId(writer);
  304. fragmentingWriter.EndFragment();
  305. fragmentingWriter.StartFragment(bodyContentFragment, true);
  306. this.InnerMessage.WriteBodyContents(writer);
  307. fragmentingWriter.EndFragment();
  308. fragmentingWriter.StartFragment(this.endBodyFragment, false);
  309. writer.WriteEndElement();
  310. fragmentingWriter.EndFragment();
  311. writer.EndCanonicalization();
  312. int bodyLength;
  313. byte[] bodyBuffer = bodyContentFragment.ToArray(out bodyLength);
  314. encryptedData.SetUpEncryption(algorithm, new ArraySegment<byte>(bodyBuffer, 0, bodyLength));
  315. this.encryptedBodyContent = encryptedData;
  316. this.state = BodyState.SignedThenEncrypted;
  317. }
  318. public void WriteBodyToSignWithFragments(Stream stream, bool includeComments, string[] inclusivePrefixes, XmlDictionaryWriter writer)
  319. {
  320. IFragmentCapableXmlDictionaryWriter fragmentingWriter = (IFragmentCapableXmlDictionaryWriter) writer;
  321. SetBodyId();
  322. BufferedOutputStream fullBodyFragment = new BufferManagerOutputStream(SR.XmlBufferQuotaExceeded, 1024, int.MaxValue, this.securityHeader.StreamBufferManager);
  323. writer.StartCanonicalization(stream, includeComments, inclusivePrefixes);
  324. fragmentingWriter.StartFragment(fullBodyFragment, false);
  325. WriteStartInnerMessageWithId(writer);
  326. this.InnerMessage.WriteBodyContents(writer);
  327. writer.WriteEndElement();
  328. fragmentingWriter.EndFragment();
  329. writer.EndCanonicalization();
  330. this.fullBodyFragment = fullBodyFragment.ToArray(out this.fullBodyFragmentLength);
  331. this.state = BodyState.Signed;
  332. }
  333. void WriteInnerMessageWithId(XmlDictionaryWriter writer)
  334. {
  335. WriteStartInnerMessageWithId(writer);
  336. this.InnerMessage.WriteBodyContents(writer);
  337. writer.WriteEndElement();
  338. }
  339. void WriteStartInnerMessageWithId(XmlDictionaryWriter writer)
  340. {
  341. this.InnerMessage.WriteStartBody(writer);
  342. if (this.bodyIdInserted)
  343. {
  344. this.securityHeader.StandardsManager.IdManager.WriteIdAttribute(writer, this.bodyId);
  345. }
  346. }
  347. enum BodyState
  348. {
  349. Created,
  350. Signed,
  351. SignedThenEncrypted,
  352. EncryptedThenSigned,
  353. Encrypted,
  354. Disposed,
  355. }
  356. struct BodyContentHelper
  357. {
  358. MemoryStream stream;
  359. XmlDictionaryWriter writer;
  360. public XmlDictionaryWriter CreateWriter()
  361. {
  362. this.stream = new MemoryStream();
  363. this.writer = XmlDictionaryWriter.CreateTextWriter(stream);
  364. return this.writer;
  365. }
  366. public ArraySegment<byte> ExtractResult()
  367. {
  368. this.writer.Flush();
  369. return new ArraySegment<byte>(this.stream.GetBuffer(), 0, (int) this.stream.Length);
  370. }
  371. }
  372. sealed class MessagePrefixGenerator : IPrefixGenerator
  373. {
  374. XmlWriter writer;
  375. public MessagePrefixGenerator(XmlWriter writer)
  376. {
  377. this.writer = writer;
  378. }
  379. public string GetPrefix(string namespaceUri, int depth, bool isForAttribute)
  380. {
  381. return this.writer.LookupPrefix(namespaceUri);
  382. }
  383. }
  384. }
  385. }