SecureMessageGenerator.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  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
  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 SecurityRequestContext RequestContext {
  67. get { return null; }
  68. }
  69. public override UniqueId RelatesTo {
  70. get { return null; }
  71. }
  72. public override SecurityTokenParameters Parameters {
  73. get { return security.InitiatorParameters; }
  74. }
  75. public override SecurityTokenParameters CounterParameters {
  76. get { return security.RecipientParameters; }
  77. }
  78. public override MessageDirection Direction {
  79. get { return MessageDirection.Input; }
  80. }
  81. public override EndpointAddress MessageTo {
  82. get { return message_to; }
  83. }
  84. public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
  85. {
  86. switch (mode) {
  87. case SecurityTokenInclusionMode.Never:
  88. case SecurityTokenInclusionMode.AlwaysToInitiator:
  89. return false;
  90. case SecurityTokenInclusionMode.AlwaysToRecipient:
  91. return true;
  92. case SecurityTokenInclusionMode.Once:
  93. return !isInitialized;
  94. }
  95. throw new Exception ("Internal Error: should not happen.");
  96. }
  97. public override ScopedMessagePartSpecification SignatureParts {
  98. get { return Security.ChannelRequirements.IncomingSignatureParts; }
  99. }
  100. public override ScopedMessagePartSpecification EncryptionParts {
  101. get { return Security.ChannelRequirements.IncomingEncryptionParts; }
  102. }
  103. }
  104. internal class RecipientMessageSecurityGenerator : MessageSecurityGenerator
  105. {
  106. RecipientMessageSecurityBindingSupport security;
  107. SecurityRequestContext req_ctx;
  108. public RecipientMessageSecurityGenerator (
  109. Message msg,
  110. SecurityRequestContext requestContext,
  111. RecipientMessageSecurityBindingSupport security)
  112. : base (msg, security)
  113. {
  114. this.security = security;
  115. req_ctx = requestContext;
  116. SecurityMessageProperty secprop =
  117. (SecurityMessageProperty) req_ctx.RequestMessage.Properties.Security.CreateCopy ();
  118. msg.Properties.Security = secprop;
  119. }
  120. public override SecurityRequestContext RequestContext {
  121. get { return req_ctx; }
  122. }
  123. public override UniqueId RelatesTo {
  124. get { return req_ctx.RequestMessage.Headers.MessageId; }
  125. }
  126. public override SecurityTokenParameters Parameters {
  127. get { return security.RecipientParameters; }
  128. }
  129. public override SecurityTokenParameters CounterParameters {
  130. get { return security.InitiatorParameters; }
  131. }
  132. public override MessageDirection Direction {
  133. get { return MessageDirection.Output; }
  134. }
  135. public override EndpointAddress MessageTo {
  136. get { return null; }
  137. }
  138. public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
  139. {
  140. switch (mode) {
  141. case SecurityTokenInclusionMode.Never:
  142. case SecurityTokenInclusionMode.AlwaysToRecipient:
  143. return false;
  144. case SecurityTokenInclusionMode.AlwaysToInitiator:
  145. return true;
  146. case SecurityTokenInclusionMode.Once:
  147. return !isInitialized;
  148. }
  149. throw new Exception ("Internal Error: should not happen.");
  150. }
  151. public override ScopedMessagePartSpecification SignatureParts {
  152. get { return Security.ChannelRequirements.OutgoingSignatureParts; }
  153. }
  154. public override ScopedMessagePartSpecification EncryptionParts {
  155. get { return Security.ChannelRequirements.OutgoingEncryptionParts; }
  156. }
  157. }
  158. internal abstract class MessageSecurityGenerator
  159. {
  160. Message msg;
  161. SecurityMessageProperty secprop;
  162. MessageSecurityBindingSupport security;
  163. int idbase;
  164. public MessageSecurityGenerator (Message msg,
  165. MessageSecurityBindingSupport security)
  166. {
  167. this.msg = msg;
  168. this.security = security;
  169. }
  170. public Message Message {
  171. get { return msg; }
  172. }
  173. public MessageSecurityBindingSupport Security {
  174. get { return security; }
  175. }
  176. public abstract SecurityTokenParameters Parameters { get; }
  177. public abstract SecurityTokenParameters CounterParameters { get; }
  178. public abstract MessageDirection Direction { get; }
  179. public abstract EndpointAddress MessageTo { get; }
  180. public abstract ScopedMessagePartSpecification SignatureParts { get; }
  181. public abstract ScopedMessagePartSpecification EncryptionParts { get; }
  182. public MessagePartSpecification SignaturePart {
  183. get {
  184. MessagePartSpecification spec;
  185. if (!SignatureParts.TryGetParts (GetAction (), false, out spec))
  186. spec = SignatureParts.ChannelParts;
  187. return spec;
  188. }
  189. }
  190. public MessagePartSpecification EncryptionPart {
  191. get {
  192. MessagePartSpecification spec;
  193. if (!EncryptionParts.TryGetParts (GetAction (), false, out spec))
  194. spec = EncryptionParts.ChannelParts;
  195. return spec;
  196. }
  197. }
  198. public abstract bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized);
  199. public bool ShouldOutputEncryptedKey {
  200. get { return RequestContext == null || RequestContext.RequestMessage.Properties.Security.ProtectionToken == null; } //security.Element is AsymmetricSecurityBindingElement; }
  201. }
  202. public abstract UniqueId RelatesTo { get; }
  203. public abstract SecurityRequestContext RequestContext { get; }
  204. public Message SecureMessage ()
  205. {
  206. secprop = Message.Properties.Security ?? new SecurityMessageProperty ();
  207. SecurityToken encToken =
  208. secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
  209. // FIXME: it might be still incorrect.
  210. SecurityToken signToken =
  211. Parameters == CounterParameters ? null :
  212. security.SigningToken;
  213. MessageProtectionOrder protectionOrder =
  214. security.MessageProtectionOrder;
  215. SecurityTokenSerializer serializer =
  216. security.TokenSerializer;
  217. SecurityBindingElement element =
  218. security.Element;
  219. SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;
  220. // FIXME: remove this hack
  221. if (!ShouldOutputEncryptedKey)
  222. encToken = new BinarySecretSecurityToken (secprop.EncryptionKey);
  223. string messageId = "uuid-" + Guid.NewGuid ();
  224. int identForMessageId = 1;
  225. XmlDocument doc = new XmlDocument ();
  226. doc.PreserveWhitespace = true;
  227. UniqueId relatesTo = RelatesTo;
  228. if (relatesTo != null)
  229. msg.Headers.RelatesTo = relatesTo;
  230. else // FIXME: probably it is always added when it is stateful ?
  231. msg.Headers.MessageId = new UniqueId ("urn:" + messageId);
  232. // FIXME: get correct ReplyTo value
  233. if (Direction == MessageDirection.Input)
  234. msg.Headers.Add (MessageHeader.CreateHeader ("ReplyTo", msg.Version.Addressing.Namespace, EndpointAddress10.FromEndpointAddress (new EndpointAddress (Constants.WsaAnonymousUri))));
  235. if (MessageTo != null)
  236. msg.Headers.Add (MessageHeader.CreateHeader ("To", msg.Version.Addressing.Namespace, MessageTo.Uri.AbsoluteUri, true));
  237. // wss:Security
  238. WSSecurityMessageHeader header =
  239. new WSSecurityMessageHeader (serializer);
  240. msg.Headers.Add (header);
  241. // 1. [Timestamp]
  242. if (element.IncludeTimestamp) {
  243. WsuTimestamp timestamp = new WsuTimestamp ();
  244. timestamp.Id = messageId + "-" + identForMessageId++;
  245. timestamp.Created = DateTime.Now;
  246. // FIXME: on service side, use element.LocalServiceSettings.TimestampValidityDuration
  247. timestamp.Expires = timestamp.Created.Add (element.LocalClientSettings.TimestampValidityDuration);
  248. header.AddContent (timestamp);
  249. }
  250. XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
  251. nsmgr.AddNamespace ("s", msg.Version.Envelope.Namespace);
  252. nsmgr.AddNamespace ("o", Constants.WssNamespace);
  253. nsmgr.AddNamespace ("u", Constants.WsuNamespace);
  254. nsmgr.AddNamespace ("o11", Constants.Wss11Namespace);
  255. /*WrappedKey*/SecurityToken primaryToken = null;
  256. DerivedKeySecurityToken dkeyToken = null;
  257. SecurityToken actualToken = null;
  258. SecurityKeyIdentifierClause actualClause = null;
  259. Signature sig = null;
  260. List<DerivedKeySecurityToken> derivedKeys =
  261. new List<DerivedKeySecurityToken> ();
  262. SymmetricAlgorithm masterKey = new RijndaelManaged ();
  263. masterKey.KeySize = suite.DefaultSymmetricKeyLength;
  264. masterKey.Mode = CipherMode.CBC;
  265. masterKey.Padding = PaddingMode.ISO10126;
  266. SymmetricAlgorithm actualKey = masterKey;
  267. // 2. [Encryption Token]
  268. // SecurityTokenInclusionMode
  269. // - Initiator or Recipient
  270. // - done or notyet. FIXME: not implemented yet
  271. // It also affects on key reference output
  272. bool includeEncToken = // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
  273. ShouldIncludeToken (
  274. Security.RecipientParameters.InclusionMode, false);
  275. bool includeSigToken = // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
  276. ShouldIncludeToken (
  277. Security.InitiatorParameters.InclusionMode, false);
  278. SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
  279. CounterParameters.CallCreateKeyIdentifierClause (encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;
  280. MessagePartSpecification sigSpec = SignaturePart;
  281. MessagePartSpecification encSpec = EncryptionPart;
  282. // encryption key (possibly also used for signing)
  283. // FIXME: get correct SymmetricAlgorithm according to the algorithm suite
  284. if (secprop.EncryptionKey != null)
  285. actualKey.Key = secprop.EncryptionKey;
  286. // FIXME: remove thid hack
  287. if (!ShouldOutputEncryptedKey)
  288. primaryToken = RequestContext.RequestMessage.Properties.Security.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
  289. else
  290. primaryToken =
  291. // FIXME: remove this hack?
  292. encToken is SecurityContextSecurityToken ? encToken :
  293. new WrappedKeySecurityToken (messageId + "-" + identForMessageId++,
  294. actualKey.Key,
  295. // security.DefaultKeyWrapAlgorithm,
  296. Parameters.InternalHasAsymmetricKey ?
  297. suite.DefaultAsymmetricKeyWrapAlgorithm :
  298. suite.DefaultSymmetricKeyWrapAlgorithm,
  299. encToken,
  300. encClause != null ? new SecurityKeyIdentifier (encClause) : null);
  301. // If it reuses request's encryption key, do not output.
  302. if (ShouldOutputEncryptedKey)
  303. header.AddContent (primaryToken);
  304. actualToken = primaryToken;
  305. // FIXME: I doubt it is correct...
  306. WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;
  307. actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
  308. new LocalIdKeyIdentifierClause (actualToken.Id, typeof (WrappedKeySecurityToken)) :
  309. new InternalEncryptedKeyIdentifierClause (SHA1.Create ().ComputeHash (requestEncKey.GetWrappedKey ()));
  310. // generate derived key if needed
  311. if (CounterParameters.RequireDerivedKeys) {
  312. RijndaelManaged deriv = new RijndaelManaged ();
  313. deriv.KeySize = suite.DefaultEncryptionKeyDerivationLength;
  314. deriv.Mode = CipherMode.CBC;
  315. deriv.Padding = PaddingMode.ISO10126;
  316. deriv.GenerateKey ();
  317. dkeyToken = new DerivedKeySecurityToken (
  318. GenerateId (doc),
  319. null, // algorithm
  320. actualClause,
  321. new InMemorySymmetricSecurityKey (actualKey.Key),
  322. null, // name
  323. null, // generation
  324. null, // offset
  325. deriv.Key.Length,
  326. null, // label
  327. deriv.Key);
  328. derivedKeys.Add (dkeyToken);
  329. actualToken = dkeyToken;
  330. actualKey.Key = ((SymmetricSecurityKey) dkeyToken.SecurityKeys [0]).GetSymmetricKey ();
  331. actualClause = new LocalIdKeyIdentifierClause (dkeyToken.Id);
  332. header.AddContent (dkeyToken);
  333. }
  334. ReferenceList refList = new ReferenceList ();
  335. // When encrypted with DerivedKeyToken, put references
  336. // immediately after the derived token (not inside the
  337. // primary token).
  338. // Similarly, when we do not output EncryptedKey,
  339. // output ReferenceList in the same way.
  340. if (CounterParameters.RequireDerivedKeys ||
  341. !ShouldOutputEncryptedKey)
  342. header.AddContent (refList);
  343. else
  344. ((WrappedKeySecurityToken) primaryToken).ReferenceList = refList;
  345. // [Signature Confirmation]
  346. if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
  347. foreach (string value in secprop.ConfirmedSignatures)
  348. header.AddContent (new Wss11SignatureConfirmation (GenerateId (doc), value));
  349. SupportingTokenInfoCollection tokenInfos =
  350. Direction == MessageDirection.Input ?
  351. security.CollectSupportingTokens (GetAction ()) :
  352. new SupportingTokenInfoCollection (); // empty
  353. foreach (SupportingTokenInfo tinfo in tokenInfos)
  354. header.AddContent (tinfo.Token);
  355. // populate DOM to sign.
  356. XPathNavigator nav = doc.CreateNavigator ();
  357. using (XmlWriter w = nav.AppendChild ()) {
  358. msg.WriteMessage (w);
  359. }
  360. XmlElement body = doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
  361. string bodyId = null;
  362. XmlElement secElem = null;
  363. Collection<WSSignedXml> endorsedSignatures =
  364. new Collection<WSSignedXml> ();
  365. bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);
  366. // Below are o:Security contents that are not signed...
  367. if (includeSigToken && signToken != null)
  368. header.AddContent (signToken);
  369. switch (protectionOrder) {
  370. case MessageProtectionOrder.EncryptBeforeSign:
  371. // FIXME: implement
  372. throw new NotImplementedException ();
  373. case MessageProtectionOrder.SignBeforeEncrypt:
  374. case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:
  375. // sign
  376. // see clause 8 of WS-SecurityPolicy C.2.2
  377. WSSignedXml sxml = new WSSignedXml (doc);
  378. SecurityTokenReferenceKeyInfo sigKeyInfo;
  379. sig = sxml.Signature;
  380. sig.SignedInfo.CanonicalizationMethod =
  381. suite.DefaultCanonicalizationAlgorithm;
  382. foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/u:Timestamp", nsmgr))
  383. CreateReference (sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
  384. foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
  385. CreateReference (sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
  386. foreach (SupportingTokenInfo tinfo in tokenInfos)
  387. if (tinfo.Mode != SecurityTokenAttachmentMode.Endorsing) {
  388. XmlElement el = sxml.GetIdElement (doc, tinfo.Token.Id);
  389. CreateReference (sig, el, el.GetAttribute ("Id", Constants.WsuNamespace));
  390. }
  391. XmlNodeList nodes = doc.SelectNodes ("/s:Envelope/s:Header/*", nsmgr);
  392. for (int i = 0; i < msg.Headers.Count; i++) {
  393. MessageHeaderInfo h = msg.Headers [i];
  394. if (h.Name == "Security" && h.Namespace == Constants.WssNamespace)
  395. secElem = nodes [i] as XmlElement;
  396. else if (sigSpec.HeaderTypes.Count == 0 ||
  397. sigSpec.HeaderTypes.Contains (new XmlQualifiedName (h.Name, h.Namespace))) {
  398. string id = GenerateId (doc);
  399. h.Id = id;
  400. CreateReference (sig, nodes [i] as XmlElement, id);
  401. }
  402. }
  403. if (sigSpec.IsBodyIncluded) {
  404. bodyId = GenerateId (doc);
  405. CreateReference (sig, body.ParentNode as XmlElement, bodyId);
  406. }
  407. if (security.DefaultSignatureAlgorithm == SignedXml.XmlDsigHMACSHA1Url) {
  408. // FIXME: use appropriate hash algorithm
  409. sxml.ComputeSignature (new HMACSHA1 (actualKey.Key));
  410. sigKeyInfo = new SecurityTokenReferenceKeyInfo (actualClause, serializer, doc);
  411. }
  412. else {
  413. SecurityKeyIdentifierClause signClause =
  414. CounterParameters.CallCreateKeyIdentifierClause (signToken, includeSigToken ? CounterParameters.ReferenceStyle : SecurityTokenReferenceStyle.External);
  415. AsymmetricSecurityKey signKey = (AsymmetricSecurityKey) signToken.ResolveKeyIdentifierClause (signClause);
  416. sxml.SigningKey = signKey.GetAsymmetricAlgorithm (security.DefaultSignatureAlgorithm, true);
  417. sxml.ComputeSignature ();
  418. sigKeyInfo = new SecurityTokenReferenceKeyInfo (signClause, serializer, doc);
  419. }
  420. sxml.KeyInfo = new KeyInfo ();
  421. sxml.KeyInfo.AddClause (sigKeyInfo);
  422. if (!signatureProtection)
  423. header.AddContent (sig);
  424. // endorse the signature with (signed)endorsing
  425. // supporting tokens.
  426. foreach (SupportingTokenInfo tinfo in tokenInfos) {
  427. switch (tinfo.Mode) {
  428. case SecurityTokenAttachmentMode.Endorsing:
  429. case SecurityTokenAttachmentMode.SignedEndorsing:
  430. if (sxml.Signature.Id == null) {
  431. sig.Id = GenerateId (doc);
  432. secElem.AppendChild (sxml.GetXml ());
  433. }
  434. WSSignedXml ssxml = new WSSignedXml (doc);
  435. ssxml.Signature.SignedInfo.CanonicalizationMethod = suite.DefaultCanonicalizationAlgorithm;
  436. CreateReference (ssxml.Signature, doc, sig.Id);
  437. SecurityToken sst = tinfo.Token;
  438. SecurityKey ssk = sst.SecurityKeys [0]; // FIXME: could be different?
  439. SecurityKeyIdentifierClause tclause = new LocalIdKeyIdentifierClause (sst.Id); // FIXME: could be different?
  440. if (ssk is SymmetricSecurityKey) {
  441. SymmetricSecurityKey signKey = (SymmetricSecurityKey) ssk;
  442. ssxml.ComputeSignature (signKey.GetKeyedHashAlgorithm (suite.DefaultSymmetricSignatureAlgorithm));
  443. } else {
  444. AsymmetricSecurityKey signKey = (AsymmetricSecurityKey) ssk;
  445. ssxml.SigningKey = signKey.GetAsymmetricAlgorithm (suite.DefaultAsymmetricSignatureAlgorithm, true);
  446. ssxml.ComputeSignature ();
  447. }
  448. ssxml.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (tclause, serializer, doc));
  449. if (!signatureProtection)
  450. header.AddContent (ssxml.Signature);
  451. endorsedSignatures.Add (ssxml);
  452. break;
  453. }
  454. }
  455. // encrypt
  456. WSEncryptedXml exml = new WSEncryptedXml (doc);
  457. EncryptedData edata = Encrypt (body, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  458. EncryptedXml.ReplaceElement (body, edata, false);
  459. // encrypt signature
  460. if (signatureProtection) {
  461. XmlElement sigxml = sig.GetXml ();
  462. edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  463. header.AddContent (edata);
  464. foreach (WSSignedXml ssxml in endorsedSignatures) {
  465. sigxml = ssxml.GetXml ();
  466. edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  467. header.AddContent (edata);
  468. }
  469. if (security.RequireSignatureConfirmation) {
  470. Collection<Wss11SignatureConfirmation> confs = header.FindAll<Wss11SignatureConfirmation> ();
  471. int count = 0;
  472. foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr)) {
  473. edata = Encrypt (elem, actualKey, confs [count].Id, refList, actualClause, exml, doc);
  474. EncryptedXml.ReplaceElement (elem, edata, false);
  475. header.Contents.Insert (header.Contents.IndexOf (confs [count]), edata);
  476. header.Contents.Remove (confs [count++]);
  477. }
  478. }
  479. }
  480. // encrypt Encrypted supporting tokens
  481. foreach (SupportingTokenInfo tinfo in tokenInfos) {
  482. if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted) {
  483. XmlElement el = exml.GetIdElement (doc, tinfo.Token.Id);
  484. tinfo.Encrypted = Encrypt (el, actualKey, actualToken.Id, refList, actualClause, exml, doc);
  485. EncryptedXml.ReplaceElement (el, tinfo.Encrypted, false);
  486. header.Contents.Insert (header.Contents.IndexOf (tinfo.Token), tinfo.Encrypted);
  487. header.Contents.Remove (tinfo.Token);
  488. }
  489. }
  490. break;
  491. }
  492. Message ret = Message.CreateMessage (msg.Version, msg.Headers.Action, new XmlNodeReader (doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement));
  493. ret.Properties.Security = (SecurityMessageProperty) secprop.CreateCopy ();
  494. ret.Properties.Security.EncryptionKey = masterKey.Key;
  495. ret.BodyId = bodyId;
  496. // FIXME: can we support TransportToken here?
  497. if (element is AsymmetricSecurityBindingElement) {
  498. ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (encToken, null); // FIXME: second argument
  499. ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (signToken, null); // FIXME: second argument
  500. }
  501. else
  502. ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification (primaryToken, null);
  503. ret.Headers.Clear ();
  504. ret.Headers.CopyHeadersFrom (msg);
  505. // Header contents are:
  506. // - Timestamp
  507. // - SignatureConfirmation if required
  508. // - EncryptionToken if included
  509. // - derived key token for EncryptionToken
  510. // - ReferenceList for encrypted items
  511. // - signed supporting tokens
  512. // - signed endorsing supporting tokens
  513. // (i.e. Signed/SignedEncrypted/SignedEndorsing)
  514. // - Signature Token if different from enc token.
  515. // - derived key token for sig token if different
  516. // - Signature for:
  517. // - Timestamp
  518. // - supporting tokens (regardless of
  519. // its inclusion)
  520. // - message parts in SignedParts
  521. // - SignatureToken if TokenProtection
  522. // (regardless of its inclusion)
  523. // - Signatures for the main signature (above),
  524. // for every endorsing token and signed
  525. // endorsing token.
  526. //
  527. //MessageBuffer zzz = ret.CreateBufferedCopy (100000);
  528. //ret = zzz.CreateMessage ();
  529. //Console.WriteLine (zzz.CreateMessage ());
  530. return ret;
  531. }
  532. void CreateReference (Signature sig, XmlElement el, string id)
  533. {
  534. CreateReference (sig, el.OwnerDocument, id);
  535. if (el.GetAttribute ("Id", Constants.WsuNamespace) != id) {
  536. XmlAttribute a = el.SetAttributeNode ("Id", Constants.WsuNamespace);
  537. a.Prefix = "u";
  538. a.Value = id;
  539. }
  540. }
  541. void CreateReference (Signature sig, XmlDocument doc, string id)
  542. {
  543. SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
  544. if (id == String.Empty)
  545. id = GenerateId (doc);
  546. Reference r = new Reference ("#" + id);
  547. r.AddTransform (CreateTransform (suite.DefaultCanonicalizationAlgorithm));
  548. r.DigestMethod = suite.DefaultDigestAlgorithm;
  549. sig.SignedInfo.AddReference (r);
  550. }
  551. Transform CreateTransform (string url)
  552. {
  553. switch (url) {
  554. case SignedXml.XmlDsigC14NTransformUrl:
  555. return new XmlDsigC14NTransform ();
  556. case SignedXml.XmlDsigC14NWithCommentsTransformUrl:
  557. return new XmlDsigC14NWithCommentsTransform ();
  558. case SignedXml.XmlDsigExcC14NTransformUrl:
  559. return new XmlDsigExcC14NTransform ();
  560. case SignedXml.XmlDsigExcC14NWithCommentsTransformUrl:
  561. return new XmlDsigExcC14NWithCommentsTransform ();
  562. }
  563. throw new Exception (String.Format ("INTERNAL ERROR: Invalid canonicalization URL: {0}", url));
  564. }
  565. EncryptedData Encrypt (XmlElement target, SymmetricAlgorithm actualKey, string ekeyId, ReferenceList refList, SecurityKeyIdentifierClause encClause, EncryptedXml exml, XmlDocument doc)
  566. {
  567. SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
  568. SecurityTokenSerializer serializer = security.TokenSerializer;
  569. byte [] encrypted = exml.EncryptData (target, actualKey, false);
  570. EncryptedData edata = new EncryptedData ();
  571. edata.Id = GenerateId (doc);
  572. edata.Type = EncryptedXml.XmlEncElementContentUrl;
  573. edata.EncryptionMethod = new EncryptionMethod (suite.DefaultEncryptionAlgorithm);
  574. // FIXME: here wsse:DigestMethod should be embedded
  575. // inside EncryptionMethod. Since it is not possible
  576. // with S.S.C.Xml.EncryptionMethod, we will have to
  577. // build our own XML encryption classes.
  578. edata.CipherData.CipherValue = encrypted;
  579. DataReference dr = new DataReference ();
  580. dr.Uri = "#" + edata.Id;
  581. refList.Add (dr);
  582. if (ShouldOutputEncryptedKey && !CounterParameters.RequireDerivedKeys)
  583. edata.KeyInfo = null;
  584. else {
  585. edata.KeyInfo = new KeyInfo ();
  586. edata.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (encClause, serializer, doc));
  587. }
  588. return edata;
  589. }
  590. string GenerateId (XmlDocument doc)
  591. {
  592. idbase++;
  593. return secprop.SenderIdPrefix + idbase;
  594. }
  595. public string GetAction ()
  596. {
  597. string ret = msg.Headers.Action;
  598. if (ret == null) {
  599. HttpRequestMessageProperty reqprop =
  600. msg.Properties ["Action"] as HttpRequestMessageProperty;
  601. if (reqprop != null)
  602. ret = reqprop.Headers ["Action"];
  603. }
  604. return ret;
  605. }
  606. }
  607. }