SecureMessageGenerator.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. //
  2. // MessageSecurityGenerator.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Collections.ObjectModel;
  31. using System.Globalization;
  32. using System.IdentityModel.Selectors;
  33. using System.IdentityModel.Tokens;
  34. using System.Runtime.Serialization;
  35. using System.Security.Cryptography;
  36. using System.Security.Cryptography.X509Certificates;
  37. using System.Security.Cryptography.Xml;
  38. using System.ServiceModel;
  39. using System.ServiceModel.Channels;
  40. using System.ServiceModel.Description;
  41. using System.ServiceModel.Security;
  42. using System.ServiceModel.Security.Tokens;
  43. using System.Text;
  44. using System.Xml;
  45. using System.Xml.XPath;
  46. using ReqType = System.ServiceModel.Security.Tokens.ServiceModelSecurityTokenRequirement;
  47. namespace System.ServiceModel.Channels.Security
  48. {
  49. internal class InitiatorMessageSecurityGenerator : MessageSecurityGenerator
  50. {
  51. EndpointAddress message_to;
  52. InitiatorMessageSecurityBindingSupport security;
  53. public InitiatorMessageSecurityGenerator (
  54. Message msg,
  55. InitiatorMessageSecurityBindingSupport security,
  56. EndpointAddress messageTo)
  57. : base (msg, security)
  58. {
  59. // FIXME: I believe it should be done at channel
  60. // creation phase, but WinFX does not.
  61. // if (!security.InitiatorParameters.InternalHasAsymmetricKey)
  62. // throw new InvalidOperationException ("Wrong security token parameters: it must have an asymmetric key (HasAsymmetricKey). There is likely a misconfiguration in the custom security binding element.");
  63. this.security = security;
  64. this.message_to = messageTo;
  65. }
  66. public override SecurityTokenParameters Parameters {
  67. get { return security.InitiatorParameters; }
  68. }
  69. public override SecurityTokenParameters CounterParameters {
  70. get { return security.RecipientParameters; }
  71. }
  72. public override MessageDirection Direction {
  73. get { return MessageDirection.Input; }
  74. }
  75. public override EndpointAddress MessageTo {
  76. get { return message_to; }
  77. }
  78. public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
  79. {
  80. switch (mode) {
  81. case SecurityTokenInclusionMode.Never:
  82. case SecurityTokenInclusionMode.AlwaysToInitiator:
  83. return false;
  84. case SecurityTokenInclusionMode.AlwaysToRecipient:
  85. return true;
  86. case SecurityTokenInclusionMode.Once:
  87. return !isInitialized;
  88. }
  89. throw new Exception ("Internal Error: should not happen.");
  90. }
  91. public override ScopedMessagePartSpecification SignatureParts {
  92. get { return Security.ChannelRequirements.IncomingSignatureParts; }
  93. }
  94. public override ScopedMessagePartSpecification EncryptionParts {
  95. get { return Security.ChannelRequirements.IncomingEncryptionParts; }
  96. }
  97. }
  98. internal class RecipientMessageSecurityGenerator : MessageSecurityGenerator
  99. {
  100. RecipientMessageSecurityBindingSupport security;
  101. public RecipientMessageSecurityGenerator (
  102. Message msg,
  103. SecurityMessageProperty requestSecProp,
  104. RecipientMessageSecurityBindingSupport security)
  105. : base (msg, security)
  106. {
  107. this.security = security;
  108. SecurityMessageProperty secprop =
  109. (SecurityMessageProperty) requestSecProp.CreateCopy ();
  110. msg.Properties.Security = secprop;
  111. }
  112. public override SecurityTokenParameters Parameters {
  113. get { return security.RecipientParameters; }
  114. }
  115. public override SecurityTokenParameters CounterParameters {
  116. get { return security.InitiatorParameters; }
  117. }
  118. public override MessageDirection Direction {
  119. get { return MessageDirection.Output; }
  120. }
  121. public override EndpointAddress MessageTo {
  122. get { return null; }
  123. }
  124. public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
  125. {
  126. switch (mode) {
  127. case SecurityTokenInclusionMode.Never:
  128. case SecurityTokenInclusionMode.AlwaysToRecipient:
  129. return false;
  130. case SecurityTokenInclusionMode.AlwaysToInitiator:
  131. return true;
  132. case SecurityTokenInclusionMode.Once:
  133. return !isInitialized;
  134. }
  135. throw new Exception ("Internal Error: should not happen.");
  136. }
  137. public override ScopedMessagePartSpecification SignatureParts {
  138. get { return Security.ChannelRequirements.OutgoingSignatureParts; }
  139. }
  140. public override ScopedMessagePartSpecification EncryptionParts {
  141. get { return Security.ChannelRequirements.OutgoingEncryptionParts; }
  142. }
  143. }
  144. internal abstract class MessageSecurityGenerator
  145. {
  146. Message msg;
  147. SecurityMessageProperty secprop;
  148. MessageSecurityBindingSupport security;
  149. int idbase;
  150. public MessageSecurityGenerator (Message msg,
  151. MessageSecurityBindingSupport security)
  152. {
  153. this.msg = msg;
  154. this.security = security;
  155. }
  156. public Message Message {
  157. get { return msg; }
  158. }
  159. public MessageSecurityBindingSupport Security {
  160. get { return security; }
  161. }
  162. public abstract SecurityTokenParameters Parameters { get; }
  163. public abstract SecurityTokenParameters CounterParameters { get; }
  164. public abstract MessageDirection Direction { get; }
  165. public abstract EndpointAddress MessageTo { get; }
  166. public abstract ScopedMessagePartSpecification SignatureParts { get; }
  167. public abstract ScopedMessagePartSpecification EncryptionParts { get; }
  168. public MessagePartSpecification SignaturePart {
  169. get {
  170. MessagePartSpecification spec;
  171. if (!SignatureParts.TryGetParts (GetAction (), false, out spec))
  172. spec = SignatureParts.ChannelParts;
  173. return spec;
  174. }
  175. }
  176. public MessagePartSpecification EncryptionPart {
  177. get {
  178. MessagePartSpecification spec;
  179. if (!EncryptionParts.TryGetParts (GetAction (), false, out spec))
  180. spec = EncryptionParts.ChannelParts;
  181. return spec;
  182. }
  183. }
  184. public abstract bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized);
  185. public bool ShouldOutputEncryptedKey {
  186. get { return Direction == MessageDirection.Input || secprop.ProtectionToken == null; } //security.Element is AsymmetricSecurityBindingElement; }
  187. }
  188. public Message SecureMessage ()
  189. {
  190. secprop = Message.Properties.Security ?? new SecurityMessageProperty ();
  191. SecurityToken encToken =
  192. secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
  193. // FIXME: it might be still incorrect.
  194. SecurityToken signToken =
  195. Parameters == CounterParameters ? null :
  196. security.SigningToken;
  197. MessageProtectionOrder protectionOrder =
  198. security.MessageProtectionOrder;
  199. SecurityTokenSerializer serializer =
  200. security.TokenSerializer;
  201. SecurityBindingElement element =
  202. security.Element;
  203. SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;
  204. string messageId = "uuid-" + Guid.NewGuid ();
  205. int identForMessageId = 1;
  206. XmlDocument doc = new XmlDocument ();
  207. doc.PreserveWhitespace = true;
  208. // FIXME: get correct ReplyTo value
  209. if (Direction == MessageDirection.Input)
  210. msg.Headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri);
  211. if (MessageTo != null)
  212. msg.Headers.To = MessageTo.Uri;
  213. // wss:Security
  214. WSSecurityMessageHeader header =
  215. new WSSecurityMessageHeader (serializer);
  216. msg.Headers.Add (header);
  217. // 1. [Timestamp]
  218. if (element.IncludeTimestamp) {
  219. WsuTimestamp timestamp = new WsuTimestamp ();
  220. timestamp.Id = messageId + "-" + identForMessageId++;
  221. timestamp.Created = DateTime.Now;
  222. // FIXME: on service side, use element.LocalServiceSettings.TimestampValidityDuration
  223. timestamp.Expires = timestamp.Created.Add (element.LocalClientSettings.TimestampValidityDuration);
  224. header.AddContent (timestamp);
  225. }
  226. XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
  227. nsmgr.AddNamespace ("s", msg.Version.Envelope.Namespace);
  228. nsmgr.AddNamespace ("o", Constants.WssNamespace);
  229. nsmgr.AddNamespace ("u", Constants.WsuNamespace);
  230. nsmgr.AddNamespace ("o11", Constants.Wss11Namespace);
  231. /*WrappedKey*/SecurityToken primaryToken = null;
  232. DerivedKeySecurityToken dkeyToken = null;
  233. SecurityToken actualToken = null;
  234. SecurityKeyIdentifierClause actualClause = null;
  235. Signature sig = null;
  236. List<DerivedKeySecurityToken> derivedKeys =
  237. new List<DerivedKeySecurityToken> ();
  238. SymmetricAlgorithm masterKey = new RijndaelManaged ();
  239. masterKey.KeySize = suite.DefaultSymmetricKeyLength;
  240. masterKey.Mode = CipherMode.CBC;
  241. masterKey.Padding = PaddingMode.ISO10126;
  242. SymmetricAlgorithm actualKey = masterKey;
  243. // 2. [Encryption Token]
  244. // SecurityTokenInclusionMode
  245. // - Initiator or Recipient
  246. // - done or notyet. FIXME: not implemented yet
  247. // It also affects on key reference output
  248. bool includeEncToken = // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
  249. ShouldIncludeToken (
  250. Security.RecipientParameters.InclusionMode, false);
  251. bool includeSigToken = // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
  252. ShouldIncludeToken (
  253. Security.InitiatorParameters.InclusionMode, false);
  254. SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
  255. CounterParameters.CallCreateKeyIdentifierClause (encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;
  256. MessagePartSpecification sigSpec = SignaturePart;
  257. MessagePartSpecification encSpec = EncryptionPart;
  258. // encryption key (possibly also used for signing)
  259. // FIXME: get correct SymmetricAlgorithm according to the algorithm suite
  260. if (secprop.EncryptionKey != null)
  261. actualKey.Key = secprop.EncryptionKey;
  262. // FIXME: remove thid hack
  263. if (!ShouldOutputEncryptedKey)
  264. primaryToken = secprop.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
  265. else
  266. primaryToken =
  267. // FIXME: remove this hack?
  268. encToken is SecurityContextSecurityToken ? encToken :
  269. new WrappedKeySecurityToken (messageId + "-" + identForMessageId++,
  270. actualKey.Key,
  271. // security.DefaultKeyWrapAlgorithm,
  272. Parameters.InternalHasAsymmetricKey ?
  273. suite.DefaultAsymmetricKeyWrapAlgorithm :
  274. suite.DefaultSymmetricKeyWrapAlgorithm,
  275. encToken,
  276. encClause != null ? new SecurityKeyIdentifier (encClause) : null);
  277. // If it reuses request's encryption key, do not output.
  278. if (ShouldOutputEncryptedKey)
  279. header.AddContent (primaryToken);
  280. actualToken = primaryToken;
  281. // FIXME: I doubt it is correct...
  282. WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;
  283. actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
  284. new LocalIdKeyIdentifierClause (actualToken.Id, typeof (WrappedKeySecurityToken)) :
  285. new InternalEncryptedKeyIdentifierClause (SHA1.Create ().ComputeHash (requestEncKey.GetWrappedKey ()));
  286. // generate derived key if needed
  287. if (CounterParameters.RequireDerivedKeys) {
  288. RijndaelManaged deriv = new RijndaelManaged ();
  289. deriv.KeySize = suite.DefaultEncryptionKeyDerivationLength;
  290. deriv.Mode = CipherMode.CBC;
  291. deriv.Padding = PaddingMode.ISO10126;
  292. deriv.GenerateKey ();
  293. dkeyToken = new DerivedKeySecurityToken (
  294. GenerateId (doc),
  295. null, // algorithm
  296. actualClause,
  297. new InMemorySymmetricSecurityKey (actualKey.Key),
  298. null, // name
  299. null, // generation
  300. null, // offset
  301. deriv.Key.Length,
  302. null, // label
  303. deriv.Key);
  304. derivedKeys.Add (dkeyToken);
  305. actualToken = dkeyToken;
  306. actualKey.Key = ((SymmetricSecurityKey) dkeyToken.SecurityKeys [0]).GetSymmetricKey ();
  307. actualClause = new LocalIdKeyIdentifierClause (dkeyToken.Id);
  308. header.AddContent (dkeyToken);
  309. }
  310. ReferenceList refList = new ReferenceList ();
  311. // When encrypted with DerivedKeyToken, put references
  312. // immediately after the derived token (not inside the
  313. // primary token).
  314. // Similarly, when we do not output EncryptedKey,
  315. // output ReferenceList in the same way.
  316. if (CounterParameters.RequireDerivedKeys ||
  317. !ShouldOutputEncryptedKey)
  318. header.AddContent (refList);
  319. else
  320. ((WrappedKeySecurityToken) primaryToken).ReferenceList = refList;
  321. // [Signature Confirmation]
  322. if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
  323. foreach (string value in secprop.ConfirmedSignatures)
  324. header.AddContent (new Wss11SignatureConfirmation (GenerateId (doc), value));
  325. SupportingTokenInfoCollection tokenInfos =
  326. Direction == MessageDirection.Input ?
  327. security.CollectSupportingTokens (GetAction ()) :
  328. new SupportingTokenInfoCollection (); // empty
  329. foreach (SupportingTokenInfo tinfo in tokenInfos)
  330. header.AddContent (tinfo.Token);
  331. // populate DOM to sign.
  332. XPathNavigator nav = doc.CreateNavigator ();
  333. using (XmlWriter w = nav.AppendChild ()) {
  334. msg.WriteMessage (w);
  335. }
  336. XmlElement body = doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
  337. string bodyId = null;
  338. XmlElement secElem = null;
  339. Collection<WSSignedXml> endorsedSignatures =
  340. new Collection<WSSignedXml> ();
  341. bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);
  342. // Below are o:Security contents that are not signed...
  343. if (includeSigToken && signToken != null)
  344. header.AddContent (signToken);
  345. switch (protectionOrder) {
  346. case MessageProtectionOrder.EncryptBeforeSign:
  347. // FIXME: implement
  348. throw new NotImplementedException ();
  349. case MessageProtectionOrder.SignBeforeEncrypt:
  350. case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:
  351. // sign
  352. // see clause 8 of WS-SecurityPolicy C.2.2
  353. WSSignedXml sxml = new WSSignedXml (doc);
  354. SecurityTokenReferenceKeyInfo sigKeyInfo;
  355. sig = sxml.Signature;
  356. sig.SignedInfo.CanonicalizationMethod =
  357. suite.DefaultCanonicalizationAlgorithm;
  358. foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/u:Timestamp", nsmgr))
  359. CreateReference (sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
  360. foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
  361. CreateReference (sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
  362. foreach (SupportingTokenInfo tinfo in tokenInfos)
  363. if (tinfo.Mode != SecurityTokenAttachmentMode.Endorsing) {
  364. XmlElement el = sxml.GetIdElement (doc, tinfo.Token.Id);
  365. CreateReference (sig, el, el.GetAttribute ("Id", Constants.WsuNamespace));
  366. }
  367. XmlNodeList nodes = doc.SelectNodes ("/s:Envelope/s:Header/*", nsmgr);
  368. for (int i = 0; i < msg.Headers.Count; i++) {
  369. MessageHeaderInfo h = msg.Headers [i];
  370. if (h.Name == "Security" && h.Namespace == Constants.WssNamespace)
  371. secElem = nodes [i] as XmlElement;
  372. else if (sigSpec.HeaderTypes.Count == 0 ||
  373. sigSpec.HeaderTypes.Contains (new XmlQualifiedName (h.Name, h.Namespace))) {
  374. string id = GenerateId (doc);
  375. h.Id = id;
  376. CreateReference (sig, nodes [i] as XmlElement, id);
  377. }
  378. }
  379. if (sigSpec.IsBodyIncluded) {
  380. bodyId = GenerateId (doc);
  381. CreateReference (sig, body.ParentNode as XmlElement, bodyId);
  382. }
  383. if (security.DefaultSignatureAlgorithm == SignedXml.XmlDsigHMACSHA1Url) {
  384. // FIXME: use appropriate hash algorithm
  385. sxml.ComputeSignature (new HMACSHA1 (actualKey.Key));
  386. sigKeyInfo = new SecurityTokenReferenceKeyInfo (actualClause, serializer, doc);
  387. }
  388. else {
  389. SecurityKeyIdentifierClause signClause =
  390. CounterParameters.CallCreateKeyIdentifierClause (signToken, includeSigToken ? CounterParameters.ReferenceStyle : SecurityTokenReferenceStyle.External);
  391. AsymmetricSecurityKey signKey = (AsymmetricSecurityKey) signToken.ResolveKeyIdentifierClause (signClause);
  392. sxml.SigningKey = signKey.GetAsymmetricAlgorithm (security.DefaultSignatureAlgorithm, true);
  393. sxml.ComputeSignature ();
  394. sigKeyInfo = new SecurityTokenReferenceKeyInfo (signClause, serializer, doc);
  395. }
  396. sxml.KeyInfo = new KeyInfo ();
  397. sxml.KeyInfo.AddClause (sigKeyInfo);
  398. if (!signatureProtection)
  399. header.AddContent (sig);
  400. // endorse the signature with (signed)endorsing
  401. // supporting tokens.
  402. foreach (SupportingTokenInfo tinfo in tokenInfos) {
  403. switch (tinfo.Mode) {
  404. case SecurityTokenAttachmentMode.Endorsing:
  405. case SecurityTokenAttachmentMode.SignedEndorsing:
  406. if (sxml.Signature.Id == null) {
  407. sig.Id = GenerateId (doc);
  408. secElem.AppendChild (sxml.GetXml ());
  409. }
  410. WSSignedXml ssxml = new WSSignedXml (doc);
  411. ssxml.Signature.SignedInfo.CanonicalizationMethod = suite.DefaultCanonicalizationAlgorithm;
  412. CreateReference (ssxml.Signature, doc, sig.Id);
  413. SecurityToken sst = tinfo.Token;
  414. SecurityKey ssk = sst.SecurityKeys [0]; // FIXME: could be different?
  415. SecurityKeyIdentifierClause tclause = new LocalIdKeyIdentifierClause (sst.Id); // FIXME: could be different?
  416. if (ssk is SymmetricSecurityKey) {
  417. SymmetricSecurityKey signKey = (SymmetricSecurityKey) ssk;
  418. ssxml.ComputeSignature (signKey.GetKeyedHashAlgorithm (suite.DefaultSymmetricSignatureAlgorithm));
  419. } else {
  420. AsymmetricSecurityKey signKey = (AsymmetricSecurityKey) ssk;
  421. ssxml.SigningKey = signKey.GetAsymmetricAlgorithm (suite.DefaultAsymmetricSignatureAlgorithm, true);
  422. ssxml.ComputeSignature ();
  423. }
  424. ssxml.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (tclause, serializer, doc));
  425. if (!signatureProtection)
  426. header.AddContent (ssxml.Signature);
  427. endorsedSignatures.Add (ssxml);
  428. break;
  429. }
  430. }
  431. // encrypt
  432. WSEncryptedXml exml = new WSEncryptedXml (doc);
  433. EncryptedData edata = Encrypt (body, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  434. EncryptedXml.ReplaceElement (body, edata, false);
  435. // encrypt signature
  436. if (signatureProtection) {
  437. XmlElement sigxml = sig.GetXml ();
  438. edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  439. header.AddContent (edata);
  440. foreach (WSSignedXml ssxml in endorsedSignatures) {
  441. sigxml = ssxml.GetXml ();
  442. edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  443. header.AddContent (edata);
  444. }
  445. if (security.RequireSignatureConfirmation) {
  446. Collection<Wss11SignatureConfirmation> confs = header.FindAll<Wss11SignatureConfirmation> ();
  447. int count = 0;
  448. foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr)) {
  449. edata = Encrypt (elem, actualKey, confs [count].Id, refList, actualClause, exml, doc);
  450. EncryptedXml.ReplaceElement (elem, edata, false);
  451. header.Contents.Insert (header.Contents.IndexOf (confs [count]), edata);
  452. header.Contents.Remove (confs [count++]);
  453. }
  454. }
  455. }
  456. // encrypt Encrypted supporting tokens
  457. foreach (SupportingTokenInfo tinfo in tokenInfos) {
  458. if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted) {
  459. XmlElement el = exml.GetIdElement (doc, tinfo.Token.Id);
  460. tinfo.Encrypted = Encrypt (el, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  461. EncryptedXml.ReplaceElement (el, tinfo.Encrypted, false);
  462. header.Contents.Insert (header.Contents.IndexOf (tinfo.Token), tinfo.Encrypted);
  463. header.Contents.Remove (tinfo.Token);
  464. }
  465. }
  466. break;
  467. }
  468. Message ret = new WSSecurityMessage (Message.CreateMessage (msg.Version, msg.Headers.Action, new XmlNodeReader (doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);
  469. ret.Properties.Security = (SecurityMessageProperty) secprop.CreateCopy ();
  470. ret.Properties.Security.EncryptionKey = masterKey.Key;
  471. // FIXME: can we support TransportToken here?
  472. if (element is AsymmetricSecurityBindingElement) {
  473. ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (encToken, null); // FIXME: second argument
  474. ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (signToken, null); // FIXME: second argument
  475. }
  476. else
  477. ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification (primaryToken, null);
  478. ret.Headers.Clear ();
  479. ret.Headers.CopyHeadersFrom (msg);
  480. // Header contents are:
  481. // - Timestamp
  482. // - SignatureConfirmation if required
  483. // - EncryptionToken if included
  484. // - derived key token for EncryptionToken
  485. // - ReferenceList for encrypted items
  486. // - signed supporting tokens
  487. // - signed endorsing supporting tokens
  488. // (i.e. Signed/SignedEncrypted/SignedEndorsing)
  489. // - Signature Token if different from enc token.
  490. // - derived key token for sig token if different
  491. // - Signature for:
  492. // - Timestamp
  493. // - supporting tokens (regardless of
  494. // its inclusion)
  495. // - message parts in SignedParts
  496. // - SignatureToken if TokenProtection
  497. // (regardless of its inclusion)
  498. // - Signatures for the main signature (above),
  499. // for every endorsing token and signed
  500. // endorsing token.
  501. //
  502. //MessageBuffer zzz = ret.CreateBufferedCopy (100000);
  503. //ret = zzz.CreateMessage ();
  504. //Console.WriteLine (zzz.CreateMessage ());
  505. return ret;
  506. }
  507. void CreateReference (Signature sig, XmlElement el, string id)
  508. {
  509. CreateReference (sig, el.OwnerDocument, id);
  510. if (el.GetAttribute ("Id", Constants.WsuNamespace) != id) {
  511. XmlAttribute a = el.SetAttributeNode ("Id", Constants.WsuNamespace);
  512. a.Prefix = "u";
  513. a.Value = id;
  514. }
  515. }
  516. void CreateReference (Signature sig, XmlDocument doc, string id)
  517. {
  518. SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
  519. if (id == String.Empty)
  520. id = GenerateId (doc);
  521. Reference r = new Reference ("#" + id);
  522. r.AddTransform (CreateTransform (suite.DefaultCanonicalizationAlgorithm));
  523. r.DigestMethod = suite.DefaultDigestAlgorithm;
  524. sig.SignedInfo.AddReference (r);
  525. }
  526. Transform CreateTransform (string url)
  527. {
  528. switch (url) {
  529. case SignedXml.XmlDsigC14NTransformUrl:
  530. return new XmlDsigC14NTransform ();
  531. case SignedXml.XmlDsigC14NWithCommentsTransformUrl:
  532. return new XmlDsigC14NWithCommentsTransform ();
  533. case SignedXml.XmlDsigExcC14NTransformUrl:
  534. return new XmlDsigExcC14NTransform ();
  535. case SignedXml.XmlDsigExcC14NWithCommentsTransformUrl:
  536. return new XmlDsigExcC14NWithCommentsTransform ();
  537. }
  538. throw new Exception (String.Format ("INTERNAL ERROR: Invalid canonicalization URL: {0}", url));
  539. }
  540. EncryptedData Encrypt (XmlElement target, SymmetricAlgorithm actualKey, string ekeyId, ReferenceList refList, SecurityKeyIdentifierClause encClause, EncryptedXml exml, XmlDocument doc)
  541. {
  542. SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
  543. SecurityTokenSerializer serializer = security.TokenSerializer;
  544. byte [] encrypted = exml.EncryptData (target, actualKey, false);
  545. EncryptedData edata = new EncryptedData ();
  546. edata.Id = GenerateId (doc);
  547. edata.Type = EncryptedXml.XmlEncElementContentUrl;
  548. edata.EncryptionMethod = new EncryptionMethod (suite.DefaultEncryptionAlgorithm);
  549. // FIXME: here wsse:DigestMethod should be embedded
  550. // inside EncryptionMethod. Since it is not possible
  551. // with S.S.C.Xml.EncryptionMethod, we will have to
  552. // build our own XML encryption classes.
  553. edata.CipherData.CipherValue = encrypted;
  554. DataReference dr = new DataReference ();
  555. dr.Uri = "#" + edata.Id;
  556. refList.Add (dr);
  557. if (ShouldOutputEncryptedKey && !CounterParameters.RequireDerivedKeys)
  558. edata.KeyInfo = null;
  559. else {
  560. edata.KeyInfo = new KeyInfo ();
  561. edata.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (encClause, serializer, doc));
  562. }
  563. return edata;
  564. }
  565. string GenerateId (XmlDocument doc)
  566. {
  567. idbase++;
  568. return secprop.SenderIdPrefix + idbase;
  569. }
  570. public string GetAction ()
  571. {
  572. string ret = msg.Headers.Action;
  573. if (ret == null) {
  574. HttpRequestMessageProperty reqprop =
  575. msg.Properties ["Action"] as HttpRequestMessageProperty;
  576. if (reqprop != null)
  577. ret = reqprop.Headers ["Action"];
  578. }
  579. return ret;
  580. }
  581. }
  582. internal class WSSecurityMessage : Message
  583. {
  584. Message msg;
  585. string body_id;
  586. public WSSecurityMessage (Message msg, string bodyId)
  587. {
  588. this.msg = msg;
  589. this.body_id = bodyId;
  590. }
  591. public override MessageVersion Version {
  592. get { return msg.Version; }
  593. }
  594. public override MessageHeaders Headers {
  595. get { return msg.Headers; }
  596. }
  597. public override MessageProperties Properties {
  598. get { return msg.Properties; }
  599. }
  600. protected override MessageBuffer OnCreateBufferedCopy (int maxBufferSize)
  601. {
  602. return new WSSecurityMessageBuffer (msg.CreateBufferedCopy (maxBufferSize), body_id);
  603. }
  604. protected override string OnGetBodyAttribute (string localName, string ns)
  605. {
  606. if (localName == "Id" && ns == Constants.WsuNamespace)
  607. return body_id;
  608. return msg.GetBodyAttribute (localName, ns);
  609. }
  610. protected override void OnWriteStartBody (
  611. XmlDictionaryWriter writer)
  612. {
  613. var dic = Constants.SoapDictionary;
  614. writer.WriteStartElement ("s", dic.Add ("Body"), dic.Add (Version.Envelope.Namespace));
  615. if (body_id != null)
  616. writer.WriteAttributeString ("Id", Constants.WsuNamespace, body_id);
  617. }
  618. protected override void OnWriteBodyContents (XmlDictionaryWriter w)
  619. {
  620. msg.WriteBodyContents (w);
  621. }
  622. }
  623. internal class WSSecurityMessageBuffer : MessageBuffer
  624. {
  625. public WSSecurityMessageBuffer (MessageBuffer mb, string bodyId)
  626. {
  627. buffer = mb;
  628. body_id = bodyId;
  629. }
  630. MessageBuffer buffer;
  631. string body_id;
  632. public override int BufferSize {
  633. get { return buffer.BufferSize; }
  634. }
  635. public override void Close ()
  636. {
  637. buffer.Close ();
  638. }
  639. public override Message CreateMessage ()
  640. {
  641. return new WSSecurityMessage (buffer.CreateMessage (), body_id);
  642. }
  643. }
  644. }