2 // MessageSecurityGenerator.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections.Generic;
31 using System.Collections.ObjectModel;
32 using System.Globalization;
33 using System.IdentityModel.Selectors;
34 using System.IdentityModel.Tokens;
35 using System.Runtime.Serialization;
36 using System.Security.Cryptography;
37 using System.Security.Cryptography.X509Certificates;
38 using System.Security.Cryptography.Xml;
39 using System.ServiceModel;
40 using System.ServiceModel.Channels;
41 using System.ServiceModel.Description;
42 using System.ServiceModel.Security;
43 using System.ServiceModel.Security.Tokens;
46 using System.Xml.XPath;
48 using ReqType = System.ServiceModel.Security.Tokens.ServiceModelSecurityTokenRequirement;
50 namespace System.ServiceModel.Channels.Security
52 internal class InitiatorMessageSecurityGenerator : MessageSecurityGenerator
54 EndpointAddress message_to;
55 InitiatorMessageSecurityBindingSupport security;
57 public InitiatorMessageSecurityGenerator (
59 InitiatorMessageSecurityBindingSupport security,
60 EndpointAddress messageTo)
61 : base (msg, security)
63 // FIXME: I believe it should be done at channel
64 // creation phase, but WinFX does not.
65 // if (!security.InitiatorParameters.InternalHasAsymmetricKey)
66 // 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.");
68 this.security = security;
69 this.message_to = messageTo;
72 public override SecurityTokenParameters Parameters {
73 get { return security.InitiatorParameters; }
76 public override SecurityTokenParameters CounterParameters {
77 get { return security.RecipientParameters; }
80 public override MessageDirection Direction {
81 get { return MessageDirection.Input; }
84 public override EndpointAddress MessageTo {
85 get { return message_to; }
88 public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
91 case SecurityTokenInclusionMode.Never:
92 case SecurityTokenInclusionMode.AlwaysToInitiator:
94 case SecurityTokenInclusionMode.AlwaysToRecipient:
96 case SecurityTokenInclusionMode.Once:
97 return !isInitialized;
99 throw new Exception ("Internal Error: should not happen.");
102 public override ScopedMessagePartSpecification SignatureParts {
103 get { return Security.ChannelRequirements.IncomingSignatureParts; }
106 public override ScopedMessagePartSpecification EncryptionParts {
107 get { return Security.ChannelRequirements.IncomingEncryptionParts; }
111 internal class RecipientMessageSecurityGenerator : MessageSecurityGenerator
113 RecipientMessageSecurityBindingSupport security;
115 public RecipientMessageSecurityGenerator (
117 SecurityMessageProperty requestSecProp,
118 RecipientMessageSecurityBindingSupport security)
119 : base (msg, security)
121 this.security = security;
122 SecurityMessageProperty secprop =
123 (SecurityMessageProperty) requestSecProp.CreateCopy ();
124 msg.Properties.Security = secprop;
127 public override SecurityTokenParameters Parameters {
128 get { return security.RecipientParameters; }
131 public override SecurityTokenParameters CounterParameters {
132 get { return security.InitiatorParameters; }
135 public override MessageDirection Direction {
136 get { return MessageDirection.Output; }
139 public override EndpointAddress MessageTo {
143 public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
146 case SecurityTokenInclusionMode.Never:
147 case SecurityTokenInclusionMode.AlwaysToRecipient:
149 case SecurityTokenInclusionMode.AlwaysToInitiator:
151 case SecurityTokenInclusionMode.Once:
152 return !isInitialized;
154 throw new Exception ("Internal Error: should not happen.");
157 public override ScopedMessagePartSpecification SignatureParts {
158 get { return Security.ChannelRequirements.OutgoingSignatureParts; }
161 public override ScopedMessagePartSpecification EncryptionParts {
162 get { return Security.ChannelRequirements.OutgoingEncryptionParts; }
166 internal abstract class MessageSecurityGenerator
169 SecurityMessageProperty secprop;
170 MessageSecurityBindingSupport security;
173 public MessageSecurityGenerator (Message msg,
174 MessageSecurityBindingSupport security)
177 this.security = security;
180 public Message Message {
184 public MessageSecurityBindingSupport Security {
185 get { return security; }
188 public abstract SecurityTokenParameters Parameters { get; }
190 public abstract SecurityTokenParameters CounterParameters { get; }
192 public abstract MessageDirection Direction { get; }
194 public abstract EndpointAddress MessageTo { get; }
196 public abstract ScopedMessagePartSpecification SignatureParts { get; }
198 public abstract ScopedMessagePartSpecification EncryptionParts { get; }
200 public MessagePartSpecification SignaturePart {
202 MessagePartSpecification spec;
203 if (!SignatureParts.TryGetParts (GetAction (), false, out spec))
204 spec = SignatureParts.ChannelParts;
209 public MessagePartSpecification EncryptionPart {
211 MessagePartSpecification spec;
212 if (!EncryptionParts.TryGetParts (GetAction (), false, out spec))
213 spec = EncryptionParts.ChannelParts;
218 public abstract bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized);
220 public bool ShouldOutputEncryptedKey {
221 get { return Direction == MessageDirection.Input || secprop.ProtectionToken == null; } //security.Element is AsymmetricSecurityBindingElement; }
224 public Message SecureMessage ()
226 secprop = Message.Properties.Security ?? new SecurityMessageProperty ();
228 SecurityToken encToken =
229 secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
230 // FIXME: it might be still incorrect.
231 SecurityToken signToken =
232 Parameters == CounterParameters ? null :
233 security.SigningToken;
234 MessageProtectionOrder protectionOrder =
235 security.MessageProtectionOrder;
236 SecurityBindingElement element =
238 SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;
240 string messageId = "uuid-" + Guid.NewGuid ();
241 int identForMessageId = 1;
242 XmlDocument doc = new XmlDocument ();
243 doc.PreserveWhitespace = true;
244 var action = msg.Headers.Action;
246 if (msg.Version.Addressing != AddressingVersion.None) {
247 AddAddressingToHeader (msg.Headers);
251 WSSecurityMessageHeader header =
252 new WSSecurityMessageHeader (security.TokenSerializer);
253 msg.Headers.Add (header);
255 if (element.IncludeTimestamp) {
256 AddTimestampToHeader (header, messageId + "-" + identForMessageId++);
259 XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
260 nsmgr.AddNamespace ("s", msg.Version.Envelope.Namespace);
261 nsmgr.AddNamespace ("o", Constants.WssNamespace);
262 nsmgr.AddNamespace ("u", Constants.WsuNamespace);
263 nsmgr.AddNamespace ("o11", Constants.Wss11Namespace);
265 /*WrappedKey*/SecurityToken primaryToken = null;
266 SecurityToken actualToken = null;
267 SecurityKeyIdentifierClause actualClause = null;
271 SymmetricAlgorithm masterKey = new RijndaelManaged ();
272 masterKey.KeySize = suite.DefaultSymmetricKeyLength;
273 masterKey.Mode = CipherMode.CBC;
274 masterKey.Padding = PaddingMode.ISO10126;
275 SymmetricAlgorithm actualKey = masterKey;
277 // 2. [Encryption Token]
279 // SecurityTokenInclusionMode
280 // - Initiator or Recipient
281 // - done or notyet. FIXME: not implemented yet
282 // It also affects on key reference output
284 bool includeEncToken = // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
286 Security.RecipientParameters.InclusionMode, false);
287 bool includeSigToken = // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
289 Security.InitiatorParameters.InclusionMode, false);
291 SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
292 CounterParameters.CallCreateKeyIdentifierClause (encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;
294 MessagePartSpecification encSpec = EncryptionPart;
296 // encryption key (possibly also used for signing)
297 // FIXME: get correct SymmetricAlgorithm according to the algorithm suite
298 if (secprop.EncryptionKey != null)
299 actualKey.Key = secprop.EncryptionKey;
301 // FIXME: remove thid hack
302 if (!ShouldOutputEncryptedKey)
303 primaryToken = secprop.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
306 // FIXME: remove this hack?
307 encToken is SecurityContextSecurityToken ? encToken :
308 new WrappedKeySecurityToken (messageId + "-" + identForMessageId++,
310 // security.DefaultKeyWrapAlgorithm,
311 Parameters.InternalHasAsymmetricKey ?
312 suite.DefaultAsymmetricKeyWrapAlgorithm :
313 suite.DefaultSymmetricKeyWrapAlgorithm,
315 encClause != null ? new SecurityKeyIdentifier (encClause) : null);
317 // If it reuses request's encryption key, do not output.
318 if (ShouldOutputEncryptedKey)
319 header.AddContent (primaryToken);
321 actualToken = primaryToken;
323 // FIXME: I doubt it is correct...
324 WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;
325 actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
326 new LocalIdKeyIdentifierClause (actualToken.Id, typeof (WrappedKeySecurityToken)) :
327 new InternalEncryptedKeyIdentifierClause (SHA1.Create ().ComputeHash (requestEncKey.GetWrappedKey ()));
329 // generate derived key if needed
330 if (CounterParameters.RequireDerivedKeys) {
331 var dkeyToken = CreateDerivedKey (GenerateId (doc), actualClause, actualKey);
332 actualToken = dkeyToken;
333 actualKey.Key = ((SymmetricSecurityKey)dkeyToken.SecurityKeys [0]).GetSymmetricKey ();
334 actualClause = new LocalIdKeyIdentifierClause (dkeyToken.Id);
335 header.AddContent (dkeyToken);
338 ReferenceList refList = new ReferenceList ();
339 // When encrypted with DerivedKeyToken, put references
340 // immediately after the derived token (not inside the
342 // Similarly, when we do not output EncryptedKey,
343 // output ReferenceList in the same way.
344 if (CounterParameters.RequireDerivedKeys ||
345 !ShouldOutputEncryptedKey)
346 header.AddContent (refList);
348 ((WrappedKeySecurityToken) primaryToken).ReferenceList = refList;
350 // [Signature Confirmation]
351 if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
352 foreach (string value in secprop.ConfirmedSignatures)
353 header.AddContent (new Wss11SignatureConfirmation (GenerateId (doc), value));
355 SupportingTokenInfoCollection tokenInfos =
356 Direction == MessageDirection.Input ?
357 security.CollectSupportingTokens (GetAction ()) :
358 new SupportingTokenInfoCollection (); // empty
360 foreach (SupportingTokenInfo tinfo in tokenInfos)
361 header.AddContent (tinfo.Token);
363 // populate DOM to sign.
364 XPathNavigator nav = doc.CreateNavigator ();
365 using (XmlWriter w = nav.AppendChild ()) {
366 msg.WriteMessage (w);
369 XmlElement body = doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
370 string bodyId = null;
371 Collection<WSSignedXml> endorsedSignatures =
372 new Collection<WSSignedXml> ();
373 bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);
375 // Below are o:Security contents that are not signed...
376 if (includeSigToken && signToken != null)
377 header.AddContent (signToken);
379 switch (protectionOrder) {
380 case MessageProtectionOrder.EncryptBeforeSign:
382 throw new NotImplementedException ();
383 case MessageProtectionOrder.SignBeforeEncrypt:
384 case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:
387 var sig = CreateSignature (doc, body, nsmgr, tokenInfos,
388 actualClause, actualKey, signToken, includeSigToken,
389 signatureProtection, header, endorsedSignatures,
395 WSEncryptedXml exml = new WSEncryptedXml (doc);
397 EncryptedData edata = Encrypt (body, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementContentUrl);
398 EncryptedXml.ReplaceElement (body, edata, false);
401 if (signatureProtection) {
402 XmlElement sigxml = sig.GetXml ();
403 edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
404 header.AddContent (edata);
406 foreach (WSSignedXml ssxml in endorsedSignatures) {
407 sigxml = ssxml.GetXml ();
408 edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
409 header.AddContent (edata);
412 if (security.RequireSignatureConfirmation) {
413 Collection<Wss11SignatureConfirmation> confs = header.FindAll<Wss11SignatureConfirmation> ();
415 foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr)) {
416 edata = Encrypt (elem, actualKey, confs [count].Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
417 EncryptedXml.ReplaceElement (elem, edata, false);
418 header.Contents.Insert (header.Contents.IndexOf (confs [count]), edata);
419 header.Contents.Remove (confs [count++]);
425 // encrypt Encrypted supporting tokens
426 foreach (SupportingTokenInfo tinfo in tokenInfos) {
427 if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted) {
428 XmlElement el = exml.GetIdElement (doc, tinfo.Token.Id);
429 tinfo.Encrypted = Encrypt (el, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
430 EncryptedXml.ReplaceElement (el, tinfo.Encrypted, false);
431 header.Contents.Insert (header.Contents.IndexOf (tinfo.Token), tinfo.Encrypted);
432 header.Contents.Remove (tinfo.Token);
441 Message ret = new WSSecurityMessage (Message.CreateMessage (msg.Version, action, new XmlNodeReader (doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);
442 ret.Properties.Security = (SecurityMessageProperty) secprop.CreateCopy ();
443 ret.Properties.Security.EncryptionKey = masterKey.Key;
445 // FIXME: can we support TransportToken here?
446 if (element is AsymmetricSecurityBindingElement) {
447 ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (encToken, null); // FIXME: second argument
448 ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (signToken, null); // FIXME: second argument
451 ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification (primaryToken, null);
453 ret.Headers.Clear ();
454 ret.Headers.CopyHeadersFrom (msg);
456 // Header contents are:
458 // - SignatureConfirmation if required
459 // - EncryptionToken if included
460 // - derived key token for EncryptionToken
461 // - ReferenceList for encrypted items
462 // - signed supporting tokens
463 // - signed endorsing supporting tokens
464 // (i.e. Signed/SignedEncrypted/SignedEndorsing)
465 // - Signature Token if different from enc token.
466 // - derived key token for sig token if different
469 // - supporting tokens (regardless of
471 // - message parts in SignedParts
472 // - SignatureToken if TokenProtection
473 // (regardless of its inclusion)
474 // - Signatures for the main signature (above),
475 // for every endorsing token and signed
479 //MessageBuffer zzz = ret.CreateBufferedCopy (100000);
480 //ret = zzz.CreateMessage ();
481 //Console.WriteLine (zzz.CreateMessage ());
485 Signature CreateSignature (XmlDocument doc, XmlElement body,
486 XmlNamespaceManager nsmgr,
487 SupportingTokenInfoCollection tokenInfos,
488 SecurityKeyIdentifierClause actualClause,
489 SymmetricAlgorithm actualKey,
490 SecurityToken signToken,
491 bool includeSigToken,
492 bool signatureProtection,
493 WSSecurityMessageHeader header,
494 Collection<WSSignedXml> endorsedSignatures,
498 // see clause 8 of WS-SecurityPolicy C.2.2
499 WSSignedXml sxml = new WSSignedXml (doc);
500 SecurityTokenReferenceKeyInfo sigKeyInfo;
501 XmlElement secElem = null;
502 var sigSpec = SignaturePart;
503 var serializer = security.TokenSerializer;
504 var suite = security.Element.DefaultAlgorithmSuite;
506 var sig = sxml.Signature;
507 sig.SignedInfo.CanonicalizationMethod =
508 suite.DefaultCanonicalizationAlgorithm;
509 foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/u:Timestamp", nsmgr))
510 CreateReference(sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
511 foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
512 CreateReference(sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
513 foreach (SupportingTokenInfo tinfo in tokenInfos)
514 if (tinfo.Mode != SecurityTokenAttachmentMode.Endorsing) {
515 XmlElement el = sxml.GetIdElement (doc, tinfo.Token.Id);
516 CreateReference (sig, el, el.GetAttribute ("Id", Constants.WsuNamespace));
518 XmlNodeList nodes = doc.SelectNodes ("/s:Envelope/s:Header/*", nsmgr);
519 for (int i = 0; i < msg.Headers.Count; i++) {
520 MessageHeaderInfo h = msg.Headers [i];
521 if (h.Name == "Security" && h.Namespace == Constants.WssNamespace)
522 secElem = nodes [i] as XmlElement;
523 else if ((sigSpec.HeaderTypes.Count == 0 ||
524 sigSpec.HeaderTypes.Contains (new XmlQualifiedName(h.Name, h.Namespace))) &&
525 (msg.Version.Addressing != AddressingVersion.None ||
526 !String.Equals (h.Name, "Action", StringComparison.Ordinal))) {
527 string id = GenerateId (doc);
529 CreateReference (sig, nodes [i] as XmlElement, id);
532 if (sigSpec.IsBodyIncluded) {
533 bodyId = GenerateId (doc);
534 CreateReference (sig, body.ParentNode as XmlElement, bodyId);
538 if (security.DefaultSignatureAlgorithm == SignedXml.XmlDsigHMACSHA1Url) {
539 // FIXME: use appropriate hash algorithm
540 sxml.ComputeSignature (new HMACSHA1(actualKey.Key));
541 sigKeyInfo = new SecurityTokenReferenceKeyInfo (actualClause, serializer, doc);
543 SecurityKeyIdentifierClause signClause =
544 CounterParameters.CallCreateKeyIdentifierClause (signToken, includeSigToken ? CounterParameters.ReferenceStyle : SecurityTokenReferenceStyle.External);
545 AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)signToken.ResolveKeyIdentifierClause (signClause);
546 sxml.SigningKey = signKey.GetAsymmetricAlgorithm (security.DefaultSignatureAlgorithm, true);
547 sxml.ComputeSignature ();
548 sigKeyInfo = new SecurityTokenReferenceKeyInfo (signClause, serializer, doc);
551 sxml.KeyInfo = new KeyInfo ();
552 sxml.KeyInfo.AddClause (sigKeyInfo);
554 if (!signatureProtection)
555 header.AddContent (sig);
557 // endorse the signature with (signed)endorsing
558 // supporting tokens.
560 foreach (SupportingTokenInfo tinfo in tokenInfos) {
561 switch (tinfo.Mode) {
562 case SecurityTokenAttachmentMode.Endorsing:
563 case SecurityTokenAttachmentMode.SignedEndorsing:
564 if (sxml.Signature.Id == null) {
565 sig.Id = GenerateId (doc);
566 secElem.AppendChild (sxml.GetXml ());
568 WSSignedXml ssxml = new WSSignedXml (doc);
569 ssxml.Signature.SignedInfo.CanonicalizationMethod = suite.DefaultCanonicalizationAlgorithm;
570 CreateReference (ssxml.Signature, doc, sig.Id);
571 SecurityToken sst = tinfo.Token;
572 SecurityKey ssk = sst.SecurityKeys [0]; // FIXME: could be different?
573 SecurityKeyIdentifierClause tclause = new LocalIdKeyIdentifierClause (sst.Id); // FIXME: could be different?
574 if (ssk is SymmetricSecurityKey) {
575 SymmetricSecurityKey signKey = (SymmetricSecurityKey)ssk;
576 ssxml.ComputeSignature (signKey.GetKeyedHashAlgorithm(suite.DefaultSymmetricSignatureAlgorithm));
578 AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)ssk;
579 ssxml.SigningKey = signKey.GetAsymmetricAlgorithm (suite.DefaultAsymmetricSignatureAlgorithm, true);
580 ssxml.ComputeSignature ();
582 ssxml.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (tclause, serializer, doc));
583 if (!signatureProtection)
584 header.AddContent (ssxml.Signature);
585 endorsedSignatures.Add (ssxml);
593 void AddAddressingToHeader (MessageHeaders headers)
595 // FIXME: get correct ReplyTo value
596 if (Direction == MessageDirection.Input)
597 headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri);
599 if (MessageTo != null)
600 headers.To = MessageTo.Uri;
603 DerivedKeySecurityToken CreateDerivedKey (string id,
604 SecurityKeyIdentifierClause actualClause,
605 SymmetricAlgorithm actualKey)
607 RijndaelManaged deriv = new RijndaelManaged ();
608 deriv.KeySize = security.Element.DefaultAlgorithmSuite.DefaultEncryptionKeyDerivationLength;
609 deriv.Mode = CipherMode.CBC;
610 deriv.Padding = PaddingMode.ISO10126;
611 deriv.GenerateKey ();
612 var dkeyToken = new DerivedKeySecurityToken (
616 new InMemorySymmetricSecurityKey (actualKey.Key),
626 void AddTimestampToHeader (WSSecurityMessageHeader header, string id)
628 WsuTimestamp timestamp = new WsuTimestamp ();
630 timestamp.Created = DateTime.Now;
631 // FIXME: on service side, use element.LocalServiceSettings.TimestampValidityDuration
632 timestamp.Expires = timestamp.Created.Add (security.Element.LocalClientSettings.TimestampValidityDuration);
633 header.AddContent (timestamp);
636 void CreateReference (Signature sig, XmlElement el, string id)
638 CreateReference (sig, el.OwnerDocument, id);
640 if (el.GetAttribute ("Id", Constants.WsuNamespace) != id) {
641 XmlAttribute a = el.SetAttributeNode ("Id", Constants.WsuNamespace);
647 void CreateReference (Signature sig, XmlDocument doc, string id)
649 SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
650 if (id == String.Empty)
651 id = GenerateId (doc);
652 Reference r = new Reference ("#" + id);
653 r.AddTransform (CreateTransform (suite.DefaultCanonicalizationAlgorithm));
654 r.DigestMethod = suite.DefaultDigestAlgorithm;
655 sig.SignedInfo.AddReference (r);
658 Transform CreateTransform (string url)
661 case SignedXml.XmlDsigC14NTransformUrl:
662 return new XmlDsigC14NTransform ();
663 case SignedXml.XmlDsigC14NWithCommentsTransformUrl:
664 return new XmlDsigC14NWithCommentsTransform ();
665 case SignedXml.XmlDsigExcC14NTransformUrl:
666 return new XmlDsigExcC14NTransform ();
667 case SignedXml.XmlDsigExcC14NWithCommentsTransformUrl:
668 return new XmlDsigExcC14NWithCommentsTransform ();
670 throw new Exception (String.Format ("INTERNAL ERROR: Invalid canonicalization URL: {0}", url));
673 EncryptedData Encrypt (XmlElement target, SymmetricAlgorithm actualKey, string ekeyId, ReferenceList refList, SecurityKeyIdentifierClause encClause, EncryptedXml exml, XmlDocument doc, string elementType)
675 SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
676 SecurityTokenSerializer serializer = security.TokenSerializer;
678 byte [] encrypted = exml.EncryptData (target, actualKey, false);
679 EncryptedData edata = new EncryptedData ();
680 edata.Id = GenerateId (doc);
681 edata.Type = elementType;
682 edata.EncryptionMethod = new EncryptionMethod (suite.DefaultEncryptionAlgorithm);
683 // FIXME: here wsse:DigestMethod should be embedded
684 // inside EncryptionMethod. Since it is not possible
685 // with S.S.C.Xml.EncryptionMethod, we will have to
686 // build our own XML encryption classes.
688 edata.CipherData.CipherValue = encrypted;
690 DataReference dr = new DataReference ();
691 dr.Uri = "#" + edata.Id;
694 if (ShouldOutputEncryptedKey && !CounterParameters.RequireDerivedKeys)
695 edata.KeyInfo = null;
697 edata.KeyInfo = new KeyInfo ();
698 edata.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (encClause, serializer, doc));
704 string GenerateId (XmlDocument doc)
707 return secprop.SenderIdPrefix + idbase;
710 public string GetAction ()
712 string ret = msg.Headers.Action;
714 HttpRequestMessageProperty reqprop =
715 msg.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
717 ret = reqprop.Headers ["Action"];
723 internal class WSSecurityMessage : Message
728 public WSSecurityMessage (Message msg, string bodyId)
731 this.body_id = bodyId;
734 public override MessageVersion Version {
735 get { return msg.Version; }
738 public override MessageHeaders Headers {
739 get { return msg.Headers; }
742 public override MessageProperties Properties {
743 get { return msg.Properties; }
746 protected override MessageBuffer OnCreateBufferedCopy (int maxBufferSize)
748 return new WSSecurityMessageBuffer (msg.CreateBufferedCopy (maxBufferSize), body_id);
751 protected override string OnGetBodyAttribute (string localName, string ns)
753 if (localName == "Id" && ns == Constants.WsuNamespace)
755 return msg.GetBodyAttribute (localName, ns);
758 protected override void OnWriteStartBody (
759 XmlDictionaryWriter writer)
761 var dic = Constants.SoapDictionary;
762 writer.WriteStartElement ("s", dic.Add ("Body"), dic.Add (Version.Envelope.Namespace));
765 writer.WriteAttributeString ("u", "Id", Constants.WsuNamespace, body_id);
769 protected override void OnWriteBodyContents (XmlDictionaryWriter w)
771 msg.WriteBodyContents (w);
775 internal class WSSecurityMessageBuffer : MessageBuffer
777 public WSSecurityMessageBuffer (MessageBuffer mb, string bodyId)
783 MessageBuffer buffer;
786 public override int BufferSize {
787 get { return buffer.BufferSize; }
790 public override void Close ()
795 public override Message CreateMessage ()
797 return new WSSecurityMessage (buffer.CreateMessage (), body_id);