Exemplo n.º 1
0
        public Message SecureMessage()
        {
            secprop = Message.Properties.Security ?? new SecurityMessageProperty();

            SecurityToken encToken =
                secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
            // FIXME: it might be still incorrect.
            SecurityToken signToken =
                Parameters == CounterParameters ? null :
                security.SigningToken;
            MessageProtectionOrder protectionOrder =
                security.MessageProtectionOrder;
            SecurityBindingElement element =
                security.Element;
            SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;

            string      messageId         = "uuid-" + Guid.NewGuid();
            int         identForMessageId = 1;
            XmlDocument doc = new XmlDocument();

            doc.PreserveWhitespace = true;
            var action = msg.Headers.Action;

            if (msg.Version.Addressing != AddressingVersion.None)
            {
                AddAddressingToHeader(msg.Headers);
            }

            // wss:Security
            WSSecurityMessageHeader header =
                new WSSecurityMessageHeader(security.TokenSerializer);

            msg.Headers.Add(header);
            // 1. [Timestamp]
            if (element.IncludeTimestamp)
            {
                AddTimestampToHeader(header, messageId + "-" + identForMessageId++);
            }

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);

            nsmgr.AddNamespace("s", msg.Version.Envelope.Namespace);
            nsmgr.AddNamespace("o", Constants.WssNamespace);
            nsmgr.AddNamespace("u", Constants.WsuNamespace);
            nsmgr.AddNamespace("o11", Constants.Wss11Namespace);

            /*WrappedKey*/ SecurityToken primaryToken = null;
            SecurityToken actualToken = null;
            SecurityKeyIdentifierClause actualClause = null;



            SymmetricAlgorithm masterKey = new RijndaelManaged();

            masterKey.KeySize = suite.DefaultSymmetricKeyLength;
            masterKey.Mode    = CipherMode.CBC;
            masterKey.Padding = PaddingMode.ISO10126;
            SymmetricAlgorithm actualKey = masterKey;

            // 2. [Encryption Token]

            // SecurityTokenInclusionMode
            // - Initiator or Recipient
            // - done or notyet. FIXME: not implemented yet
            // It also affects on key reference output

            bool includeEncToken =             // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.RecipientParameters.InclusionMode, false);
            bool includeSigToken =             // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.InitiatorParameters.InclusionMode, false);

            SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
                                                    CounterParameters.CallCreateKeyIdentifierClause(encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;

            MessagePartSpecification encSpec = EncryptionPart;

            // encryption key (possibly also used for signing)
            // FIXME: get correct SymmetricAlgorithm according to the algorithm suite
            if (secprop.EncryptionKey != null)
            {
                actualKey.Key = secprop.EncryptionKey;
            }

// FIXME: remove thid hack
            if (!ShouldOutputEncryptedKey)
            {
                primaryToken = secprop.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
            }
            else
            {
                primaryToken =
                    // FIXME: remove this hack?
                    encToken is SecurityContextSecurityToken ? encToken :
                    new WrappedKeySecurityToken(messageId + "-" + identForMessageId++,
                                                actualKey.Key,
                                                // security.DefaultKeyWrapAlgorithm,
                                                Parameters.InternalHasAsymmetricKey ?
                                                suite.DefaultAsymmetricKeyWrapAlgorithm :
                                                suite.DefaultSymmetricKeyWrapAlgorithm,
                                                encToken,
                                                encClause != null ? new SecurityKeyIdentifier(encClause) : null);
            }

            // If it reuses request's encryption key, do not output.
            if (ShouldOutputEncryptedKey)
            {
                header.AddContent(primaryToken);
            }

            actualToken = primaryToken;

            // FIXME: I doubt it is correct...
            WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;

            actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
                           new LocalIdKeyIdentifierClause(actualToken.Id, typeof(WrappedKeySecurityToken)) :
                           new InternalEncryptedKeyIdentifierClause(SHA1.Create().ComputeHash(requestEncKey.GetWrappedKey()));

            // generate derived key if needed
            if (CounterParameters.RequireDerivedKeys)
            {
                var dkeyToken = CreateDerivedKey(GenerateId(doc), actualClause, actualKey);
                actualToken   = dkeyToken;
                actualKey.Key = ((SymmetricSecurityKey)dkeyToken.SecurityKeys [0]).GetSymmetricKey();
                actualClause  = new LocalIdKeyIdentifierClause(dkeyToken.Id);
                header.AddContent(dkeyToken);
            }

            ReferenceList refList = new ReferenceList();

            // When encrypted with DerivedKeyToken, put references
            // immediately after the derived token (not inside the
            // primary token).
            // Similarly, when we do not output EncryptedKey,
            // output ReferenceList in the same way.
            if (CounterParameters.RequireDerivedKeys ||
                !ShouldOutputEncryptedKey)
            {
                header.AddContent(refList);
            }
            else
            {
                ((WrappedKeySecurityToken)primaryToken).ReferenceList = refList;
            }

            // [Signature Confirmation]
            if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
            {
                foreach (string value in secprop.ConfirmedSignatures)
                {
                    header.AddContent(new Wss11SignatureConfirmation(GenerateId(doc), value));
                }
            }

            SupportingTokenInfoCollection tokenInfos =
                Direction == MessageDirection.Input ?
                security.CollectSupportingTokens(GetAction()) :
                new SupportingTokenInfoCollection();                  // empty

            foreach (SupportingTokenInfo tinfo in tokenInfos)
            {
                header.AddContent(tinfo.Token);
            }

            // populate DOM to sign.
            XPathNavigator nav = doc.CreateNavigator();

            using (XmlWriter w = nav.AppendChild()) {
                msg.WriteMessage(w);
            }

            XmlElement body   = doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
            string     bodyId = null;
            Collection <WSSignedXml> endorsedSignatures =
                new Collection <WSSignedXml> ();
            bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);

            // Below are o:Security contents that are not signed...
            if (includeSigToken && signToken != null)
            {
                header.AddContent(signToken);
            }

            switch (protectionOrder)
            {
            case MessageProtectionOrder.EncryptBeforeSign:
                // FIXME: implement
                throw new NotImplementedException();

            case MessageProtectionOrder.SignBeforeEncrypt:
            case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:


                var sig = CreateSignature(doc, body, nsmgr, tokenInfos,
                                          actualClause, actualKey, signToken, includeSigToken,
                                          signatureProtection, header, endorsedSignatures,
                                          ref bodyId);


                // encrypt

                WSEncryptedXml exml = new WSEncryptedXml(doc);

                EncryptedData edata = Encrypt(body, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementContentUrl);
                EncryptedXml.ReplaceElement(body, edata, false);

                // encrypt signature
                if (signatureProtection)
                {
                    XmlElement sigxml = sig.GetXml();
                    edata = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                    header.AddContent(edata);

                    foreach (WSSignedXml ssxml in endorsedSignatures)
                    {
                        sigxml = ssxml.GetXml();
                        edata  = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                        header.AddContent(edata);
                    }

                    if (security.RequireSignatureConfirmation)
                    {
                        Collection <Wss11SignatureConfirmation> confs = header.FindAll <Wss11SignatureConfirmation> ();
                        int count = 0;
                        foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
                        {
                            edata = Encrypt(elem, actualKey, confs [count].Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                            EncryptedXml.ReplaceElement(elem, edata, false);
                            header.Contents.Insert(header.Contents.IndexOf(confs [count]), edata);
                            header.Contents.Remove(confs [count++]);
                        }
                    }
                }


                // encrypt Encrypted supporting tokens
                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted)
                    {
                        XmlElement el = exml.GetIdElement(doc, tinfo.Token.Id);
                        tinfo.Encrypted = Encrypt(el, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
                        EncryptedXml.ReplaceElement(el, tinfo.Encrypted, false);
                        header.Contents.Insert(header.Contents.IndexOf(tinfo.Token), tinfo.Encrypted);
                        header.Contents.Remove(tinfo.Token);
                    }
                }
                break;
            }



            Message ret = new WSSecurityMessage(Message.CreateMessage(msg.Version, action, new XmlNodeReader(doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);

            ret.Properties.Security = (SecurityMessageProperty)secprop.CreateCopy();
            ret.Properties.Security.EncryptionKey = masterKey.Key;

            // FIXME: can we support TransportToken here?
            if (element is AsymmetricSecurityBindingElement)
            {
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(encToken, null);                  // FIXME: second argument
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(signToken, null);                 // FIXME: second argument
            }
            else
            {
                ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification(primaryToken, null);
            }

            ret.Headers.Clear();
            ret.Headers.CopyHeadersFrom(msg);

            // Header contents are:
            //	- Timestamp
            //	- SignatureConfirmation if required
            //	- EncryptionToken if included
            //	- derived key token for EncryptionToken
            //	- ReferenceList for encrypted items
            //	- signed supporting tokens
            //	- signed endorsing supporting tokens
            //	(i.e. Signed/SignedEncrypted/SignedEndorsing)
            //	- Signature Token if different from enc token.
            //	- derived key token for sig token if different
            //	- Signature for:
            //		- Timestamp
            //		- supporting tokens (regardless of
            //		  its inclusion)
            //		- message parts in SignedParts
            //		- SignatureToken if TokenProtection
            //		  (regardless of its inclusion)
            //	- Signatures for the main signature (above),
            //	  for every endorsing token and signed
            //	  endorsing token.
            //

//MessageBuffer zzz = ret.CreateBufferedCopy (100000);
//ret = zzz.CreateMessage ();
//Console.WriteLine (zzz.CreateMessage ());
            return(ret);
        }
Exemplo n.º 2
0
		public Message SecureMessage ()
		{
			secprop = Message.Properties.Security ?? new SecurityMessageProperty ();

			SecurityToken encToken =
				secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
			// FIXME: it might be still incorrect.
			SecurityToken signToken =
				Parameters == CounterParameters ? null :
				security.SigningToken;
			MessageProtectionOrder protectionOrder =
				security.MessageProtectionOrder;
			SecurityBindingElement element =
				security.Element;
			SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;

			string messageId = "uuid-" + Guid.NewGuid ();
			int identForMessageId = 1;
			XmlDocument doc = new XmlDocument ();
			doc.PreserveWhitespace = true;
            var action = msg.Headers.Action;

			if (msg.Version.Addressing != AddressingVersion.None) {
                AddAddressingToHeader (msg.Headers);
			}
				
			// wss:Security
			WSSecurityMessageHeader header =
                new WSSecurityMessageHeader (security.TokenSerializer);
			msg.Headers.Add (header);
			// 1. [Timestamp]
			if (element.IncludeTimestamp) {
                AddTimestampToHeader (header, messageId + "-" + identForMessageId++);
			}

			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
			nsmgr.AddNamespace ("s", msg.Version.Envelope.Namespace);
			nsmgr.AddNamespace ("o", Constants.WssNamespace);
			nsmgr.AddNamespace ("u", Constants.WsuNamespace);
			nsmgr.AddNamespace ("o11", Constants.Wss11Namespace);

			/*WrappedKey*/SecurityToken primaryToken = null;
			SecurityToken actualToken = null;
			SecurityKeyIdentifierClause actualClause = null;

			

			SymmetricAlgorithm masterKey = new RijndaelManaged ();
			masterKey.KeySize = suite.DefaultSymmetricKeyLength;
			masterKey.Mode = CipherMode.CBC;
			masterKey.Padding = PaddingMode.ISO10126;
			SymmetricAlgorithm actualKey = masterKey;

			// 2. [Encryption Token]

			// SecurityTokenInclusionMode
			// - Initiator or Recipient
			// - done or notyet. FIXME: not implemented yet
			// It also affects on key reference output

			bool includeEncToken = // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
						ShouldIncludeToken (
				Security.RecipientParameters.InclusionMode, false);
			bool includeSigToken = // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
						ShouldIncludeToken (
				Security.InitiatorParameters.InclusionMode, false);

			SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
				CounterParameters.CallCreateKeyIdentifierClause (encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;

			MessagePartSpecification encSpec = EncryptionPart;

			// encryption key (possibly also used for signing)
			// FIXME: get correct SymmetricAlgorithm according to the algorithm suite
			if (secprop.EncryptionKey != null)
				actualKey.Key = secprop.EncryptionKey;

// FIXME: remove thid hack
if (!ShouldOutputEncryptedKey)
primaryToken = secprop.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
else
			primaryToken =
				// FIXME: remove this hack?
				encToken is SecurityContextSecurityToken ? encToken :
				new WrappedKeySecurityToken (messageId + "-" + identForMessageId++,
				actualKey.Key,
				// security.DefaultKeyWrapAlgorithm,
				Parameters.InternalHasAsymmetricKey ?
					suite.DefaultAsymmetricKeyWrapAlgorithm :
					suite.DefaultSymmetricKeyWrapAlgorithm,
				encToken,
				encClause != null ? new SecurityKeyIdentifier (encClause) : null);

			// If it reuses request's encryption key, do not output.
			if (ShouldOutputEncryptedKey)
				header.AddContent (primaryToken);

			actualToken = primaryToken;

			// FIXME: I doubt it is correct...
			WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;
			actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
				new LocalIdKeyIdentifierClause (actualToken.Id, typeof (WrappedKeySecurityToken)) :
				new InternalEncryptedKeyIdentifierClause (SHA1.Create ().ComputeHash (requestEncKey.GetWrappedKey ()));

			// generate derived key if needed
			if (CounterParameters.RequireDerivedKeys) {
                var dkeyToken = CreateDerivedKey (GenerateId (doc), actualClause, actualKey);
                actualToken = dkeyToken;
                actualKey.Key = ((SymmetricSecurityKey)dkeyToken.SecurityKeys [0]).GetSymmetricKey ();
                actualClause = new LocalIdKeyIdentifierClause (dkeyToken.Id);
                header.AddContent (dkeyToken);
			}

			ReferenceList refList = new ReferenceList ();
			// When encrypted with DerivedKeyToken, put references
			// immediately after the derived token (not inside the
			// primary token).
			// Similarly, when we do not output EncryptedKey,
			// output ReferenceList in the same way.
			if (CounterParameters.RequireDerivedKeys ||
			    !ShouldOutputEncryptedKey)
				header.AddContent (refList);
			else
				((WrappedKeySecurityToken) primaryToken).ReferenceList = refList;

			// [Signature Confirmation]
			if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
				foreach (string value in secprop.ConfirmedSignatures)
					header.AddContent (new Wss11SignatureConfirmation (GenerateId (doc), value));

			SupportingTokenInfoCollection tokenInfos =
				Direction == MessageDirection.Input ?
				security.CollectSupportingTokens (GetAction ()) :
				new SupportingTokenInfoCollection (); // empty

			foreach (SupportingTokenInfo tinfo in tokenInfos)
				header.AddContent (tinfo.Token);

			// populate DOM to sign.
			XPathNavigator nav = doc.CreateNavigator ();
			using (XmlWriter w = nav.AppendChild ()) {
				msg.WriteMessage (w);
			}

			XmlElement body = doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
			string bodyId = null;
			Collection<WSSignedXml> endorsedSignatures =
				new Collection<WSSignedXml> ();
			bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);

			// Below are o:Security contents that are not signed...
			if (includeSigToken && signToken != null)
				header.AddContent (signToken);

			switch (protectionOrder) {
			case MessageProtectionOrder.EncryptBeforeSign:
				// FIXME: implement
				throw new NotImplementedException ();
			case MessageProtectionOrder.SignBeforeEncrypt:
			case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:

               
                var sig = CreateSignature (doc, body, nsmgr, tokenInfos, 
                    actualClause, actualKey, signToken, includeSigToken, 
                    signatureProtection, header, endorsedSignatures, 
                    ref bodyId);

				
				// encrypt

				WSEncryptedXml exml = new WSEncryptedXml (doc);

				EncryptedData edata = Encrypt (body, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementContentUrl);
				EncryptedXml.ReplaceElement (body, edata, false);

				// encrypt signature
				if (signatureProtection) {
					XmlElement sigxml = sig.GetXml ();
					edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
					header.AddContent (edata);

					foreach (WSSignedXml ssxml in endorsedSignatures) {
						sigxml = ssxml.GetXml ();
						edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
						header.AddContent (edata);
					}

					if (security.RequireSignatureConfirmation) {
						Collection<Wss11SignatureConfirmation> confs = header.FindAll<Wss11SignatureConfirmation> ();
						int count = 0;
						foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr)) {
							edata = Encrypt (elem, actualKey, confs [count].Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
							EncryptedXml.ReplaceElement (elem, edata, false);
							header.Contents.Insert (header.Contents.IndexOf (confs [count]), edata);
							header.Contents.Remove (confs [count++]);
						}
					}
				}


				// encrypt Encrypted supporting tokens
				foreach (SupportingTokenInfo tinfo in tokenInfos) {
					if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted) {
						XmlElement el = exml.GetIdElement (doc, tinfo.Token.Id);
						tinfo.Encrypted = Encrypt (el, actualKey, actualToken.Id, refList, actualClause, exml, doc, EncryptedXml.XmlEncElementUrl);
						EncryptedXml.ReplaceElement (el, tinfo.Encrypted, false);
						header.Contents.Insert (header.Contents.IndexOf (tinfo.Token), tinfo.Encrypted);
						header.Contents.Remove (tinfo.Token);
					}
				}
				break;
			}


            

			Message ret = new WSSecurityMessage (Message.CreateMessage (msg.Version, action, new XmlNodeReader (doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);
			ret.Properties.Security = (SecurityMessageProperty) secprop.CreateCopy ();
			ret.Properties.Security.EncryptionKey = masterKey.Key;

			// FIXME: can we support TransportToken here?
			if (element is AsymmetricSecurityBindingElement) {
				ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (encToken, null); // FIXME: second argument
				ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (signToken, null); // FIXME: second argument
			}
			else
				ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification (primaryToken, null);

			ret.Headers.Clear ();
			ret.Headers.CopyHeadersFrom (msg);
            
			// Header contents are:
			//	- Timestamp
			//	- SignatureConfirmation if required
			//	- EncryptionToken if included
			//	- derived key token for EncryptionToken
			//	- ReferenceList for encrypted items
			//	- signed supporting tokens
			//	- signed endorsing supporting tokens
			//	(i.e. Signed/SignedEncrypted/SignedEndorsing)
			//	- Signature Token if different from enc token.
			//	- derived key token for sig token if different
			//	- Signature for:
			//		- Timestamp
			//		- supporting tokens (regardless of
			//		  its inclusion)
			//		- message parts in SignedParts
			//		- SignatureToken if TokenProtection
			//		  (regardless of its inclusion)
			//	- Signatures for the main signature (above),
			//	  for every endorsing token and signed
			//	  endorsing token.
			//	

//MessageBuffer zzz = ret.CreateBufferedCopy (100000);
//ret = zzz.CreateMessage ();
//Console.WriteLine (zzz.CreateMessage ());
			return ret;
		}
Exemplo n.º 3
0
		public Message SecureMessage ()
		{
			secprop = Message.Properties.Security ?? new SecurityMessageProperty ();

			SecurityToken encToken =
				secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
			// FIXME: it might be still incorrect.
			SecurityToken signToken =
				Parameters == CounterParameters ? null :
				security.SigningToken;
			MessageProtectionOrder protectionOrder =
				security.MessageProtectionOrder;
			SecurityTokenSerializer serializer =
				security.TokenSerializer;
			SecurityBindingElement element =
				security.Element;
			SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;

// FIXME: remove this hack
if (!ShouldOutputEncryptedKey)
	encToken = new BinarySecretSecurityToken (secprop.EncryptionKey);

			string messageId = "uuid-" + Guid.NewGuid ();
			int identForMessageId = 1;
			XmlDocument doc = new XmlDocument ();
			doc.PreserveWhitespace = true;

			UniqueId relatesTo = RelatesTo;
			if (relatesTo != null)
				msg.Headers.RelatesTo = relatesTo;
			else // FIXME: probably it is always added when it is stateful ?
				msg.Headers.MessageId = new UniqueId ("urn:" + messageId);

			// FIXME: get correct ReplyTo value
			if (Direction == MessageDirection.Input)
				msg.Headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri);

			if (MessageTo != null)
				msg.Headers.To = MessageTo.Uri;

			// wss:Security
			WSSecurityMessageHeader header =
				new WSSecurityMessageHeader (serializer);
			msg.Headers.Add (header);
			// 1. [Timestamp]
			if (element.IncludeTimestamp) {
				WsuTimestamp timestamp = new WsuTimestamp ();
				timestamp.Id = messageId + "-" + identForMessageId++;
				timestamp.Created = DateTime.Now;
				// FIXME: on service side, use element.LocalServiceSettings.TimestampValidityDuration
				timestamp.Expires = timestamp.Created.Add (element.LocalClientSettings.TimestampValidityDuration);
				header.AddContent (timestamp);
			}

			XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
			nsmgr.AddNamespace ("s", msg.Version.Envelope.Namespace);
			nsmgr.AddNamespace ("o", Constants.WssNamespace);
			nsmgr.AddNamespace ("u", Constants.WsuNamespace);
			nsmgr.AddNamespace ("o11", Constants.Wss11Namespace);

			/*WrappedKey*/SecurityToken primaryToken = null;
			DerivedKeySecurityToken dkeyToken = null;
			SecurityToken actualToken = null;
			SecurityKeyIdentifierClause actualClause = null;
			Signature sig = null;

			List<DerivedKeySecurityToken> derivedKeys =
				new List<DerivedKeySecurityToken> ();

			SymmetricAlgorithm masterKey = new RijndaelManaged ();
			masterKey.KeySize = suite.DefaultSymmetricKeyLength;
			masterKey.Mode = CipherMode.CBC;
			masterKey.Padding = PaddingMode.ISO10126;
			SymmetricAlgorithm actualKey = masterKey;

			// 2. [Encryption Token]

			// SecurityTokenInclusionMode
			// - Initiator or Recipient
			// - done or notyet. FIXME: not implemented yet
			// It also affects on key reference output

			bool includeEncToken = // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
						ShouldIncludeToken (
				Security.RecipientParameters.InclusionMode, false);
			bool includeSigToken = // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
						ShouldIncludeToken (
				Security.InitiatorParameters.InclusionMode, false);

			SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
				CounterParameters.CallCreateKeyIdentifierClause (encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;

			MessagePartSpecification sigSpec = SignaturePart;
			MessagePartSpecification encSpec = EncryptionPart;

			// encryption key (possibly also used for signing)
			// FIXME: get correct SymmetricAlgorithm according to the algorithm suite
			if (secprop.EncryptionKey != null)
				actualKey.Key = secprop.EncryptionKey;

// FIXME: remove thid hack
if (!ShouldOutputEncryptedKey)
primaryToken = RequestContext.RequestMessage.Properties.Security.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
else
			primaryToken =
				// FIXME: remove this hack?
				encToken is SecurityContextSecurityToken ? encToken :
				new WrappedKeySecurityToken (messageId + "-" + identForMessageId++,
				actualKey.Key,
				// security.DefaultKeyWrapAlgorithm,
				Parameters.InternalHasAsymmetricKey ?
					suite.DefaultAsymmetricKeyWrapAlgorithm :
					suite.DefaultSymmetricKeyWrapAlgorithm,
				encToken,
				encClause != null ? new SecurityKeyIdentifier (encClause) : null);

			// If it reuses request's encryption key, do not output.
			if (ShouldOutputEncryptedKey)
				header.AddContent (primaryToken);

			actualToken = primaryToken;

			// FIXME: I doubt it is correct...
			WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;
			actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
				new LocalIdKeyIdentifierClause (actualToken.Id, typeof (WrappedKeySecurityToken)) :
				new InternalEncryptedKeyIdentifierClause (SHA1.Create ().ComputeHash (requestEncKey.GetWrappedKey ()));

			// generate derived key if needed
			if (CounterParameters.RequireDerivedKeys) {
				RijndaelManaged deriv = new RijndaelManaged ();
				deriv.KeySize = suite.DefaultEncryptionKeyDerivationLength;
				deriv.Mode = CipherMode.CBC;
				deriv.Padding = PaddingMode.ISO10126;
				deriv.GenerateKey ();
				dkeyToken = new DerivedKeySecurityToken (
					GenerateId (doc),
					null, // algorithm
					actualClause,
					new InMemorySymmetricSecurityKey (actualKey.Key),
					null, // name
					null, // generation
					null, // offset
					deriv.Key.Length,
					null, // label
					deriv.Key);
				derivedKeys.Add (dkeyToken);
				actualToken = dkeyToken;
				actualKey.Key = ((SymmetricSecurityKey) dkeyToken.SecurityKeys [0]).GetSymmetricKey ();
				actualClause = new LocalIdKeyIdentifierClause (dkeyToken.Id);
				header.AddContent (dkeyToken);
			}

			ReferenceList refList = new ReferenceList ();
			// When encrypted with DerivedKeyToken, put references
			// immediately after the derived token (not inside the
			// primary token).
			// Similarly, when we do not output EncryptedKey,
			// output ReferenceList in the same way.
			if (CounterParameters.RequireDerivedKeys ||
			    !ShouldOutputEncryptedKey)
				header.AddContent (refList);
			else
				((WrappedKeySecurityToken) primaryToken).ReferenceList = refList;

			// [Signature Confirmation]
			if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
				foreach (string value in secprop.ConfirmedSignatures)
					header.AddContent (new Wss11SignatureConfirmation (GenerateId (doc), value));

			SupportingTokenInfoCollection tokenInfos =
				Direction == MessageDirection.Input ?
				security.CollectSupportingTokens (GetAction ()) :
				new SupportingTokenInfoCollection (); // empty

			foreach (SupportingTokenInfo tinfo in tokenInfos)
				header.AddContent (tinfo.Token);

			// populate DOM to sign.
			XPathNavigator nav = doc.CreateNavigator ();
			using (XmlWriter w = nav.AppendChild ()) {
				msg.WriteMessage (w);
			}

			XmlElement body = doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
			string bodyId = null;
			XmlElement secElem = null;
			Collection<WSSignedXml> endorsedSignatures =
				new Collection<WSSignedXml> ();
			bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);

			// Below are o:Security contents that are not signed...
			if (includeSigToken && signToken != null)
				header.AddContent (signToken);

			switch (protectionOrder) {
			case MessageProtectionOrder.EncryptBeforeSign:
				// FIXME: implement
				throw new NotImplementedException ();
			case MessageProtectionOrder.SignBeforeEncrypt:
			case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:

				// sign
				// see clause 8 of WS-SecurityPolicy C.2.2
				WSSignedXml sxml = new WSSignedXml (doc);
				SecurityTokenReferenceKeyInfo sigKeyInfo;

				sig = sxml.Signature;
				sig.SignedInfo.CanonicalizationMethod =
					suite.DefaultCanonicalizationAlgorithm;
				foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/u:Timestamp", nsmgr))
					CreateReference (sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
				foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
					CreateReference (sig, elem, elem.GetAttribute ("Id", Constants.WsuNamespace));
				foreach (SupportingTokenInfo tinfo in tokenInfos)
					if (tinfo.Mode != SecurityTokenAttachmentMode.Endorsing) {
						XmlElement el = sxml.GetIdElement (doc, tinfo.Token.Id);
						CreateReference (sig, el, el.GetAttribute ("Id", Constants.WsuNamespace));
					}
				XmlNodeList nodes = doc.SelectNodes ("/s:Envelope/s:Header/*", nsmgr);
				for (int i = 0; i < msg.Headers.Count; i++) {
					MessageHeaderInfo h = msg.Headers [i];
					if (h.Name == "Security" && h.Namespace == Constants.WssNamespace)
						secElem = nodes [i] as XmlElement;
					else if (sigSpec.HeaderTypes.Count == 0 ||
					    sigSpec.HeaderTypes.Contains (new XmlQualifiedName (h.Name, h.Namespace))) {
						string id = GenerateId (doc);
						h.Id = id;
						CreateReference (sig, nodes [i] as XmlElement, id);
					}
				}
				if (sigSpec.IsBodyIncluded) {
					bodyId = GenerateId (doc);
					CreateReference (sig, body.ParentNode as XmlElement, bodyId);
				}

				if (security.DefaultSignatureAlgorithm == SignedXml.XmlDsigHMACSHA1Url) {
					// FIXME: use appropriate hash algorithm
					sxml.ComputeSignature (new HMACSHA1 (actualKey.Key));
					sigKeyInfo = new SecurityTokenReferenceKeyInfo (actualClause, serializer, doc);
				}
				else {
					SecurityKeyIdentifierClause signClause =
						CounterParameters.CallCreateKeyIdentifierClause (signToken, includeSigToken ? CounterParameters.ReferenceStyle : SecurityTokenReferenceStyle.External);
					AsymmetricSecurityKey signKey = (AsymmetricSecurityKey) signToken.ResolveKeyIdentifierClause (signClause);
					sxml.SigningKey = signKey.GetAsymmetricAlgorithm (security.DefaultSignatureAlgorithm, true);
					sxml.ComputeSignature ();
					sigKeyInfo = new SecurityTokenReferenceKeyInfo (signClause, serializer, doc);
				}

				sxml.KeyInfo = new KeyInfo ();
				sxml.KeyInfo.AddClause (sigKeyInfo);

				if (!signatureProtection)
					header.AddContent (sig);

				// endorse the signature with (signed)endorsing
				// supporting tokens.

				foreach (SupportingTokenInfo tinfo in tokenInfos) {
					switch (tinfo.Mode) {
					case SecurityTokenAttachmentMode.Endorsing:
					case SecurityTokenAttachmentMode.SignedEndorsing:
						if (sxml.Signature.Id == null) {
							sig.Id = GenerateId (doc);
							secElem.AppendChild (sxml.GetXml ());
						}
						WSSignedXml ssxml = new WSSignedXml (doc);
						ssxml.Signature.SignedInfo.CanonicalizationMethod = suite.DefaultCanonicalizationAlgorithm;
						CreateReference (ssxml.Signature, doc, sig.Id);
						SecurityToken sst = tinfo.Token;
						SecurityKey ssk = sst.SecurityKeys [0]; // FIXME: could be different?
						SecurityKeyIdentifierClause tclause = new LocalIdKeyIdentifierClause (sst.Id); // FIXME: could be different?
						if (ssk is SymmetricSecurityKey) {
							SymmetricSecurityKey signKey = (SymmetricSecurityKey) ssk;
							ssxml.ComputeSignature (signKey.GetKeyedHashAlgorithm (suite.DefaultSymmetricSignatureAlgorithm));
						} else {
							AsymmetricSecurityKey signKey = (AsymmetricSecurityKey) ssk;
							ssxml.SigningKey = signKey.GetAsymmetricAlgorithm (suite.DefaultAsymmetricSignatureAlgorithm, true);
							ssxml.ComputeSignature ();
						}
						ssxml.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (tclause, serializer, doc));
						if (!signatureProtection)
							header.AddContent (ssxml.Signature);
						endorsedSignatures.Add (ssxml);

						break;
					}
				}

				// encrypt

				WSEncryptedXml exml = new WSEncryptedXml (doc);

				EncryptedData edata = Encrypt (body, actualKey, actualToken.Id, refList, actualClause, exml, doc);
				EncryptedXml.ReplaceElement (body, edata, false);

				// encrypt signature
				if (signatureProtection) {
					XmlElement sigxml = sig.GetXml ();
					edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
					header.AddContent (edata);

					foreach (WSSignedXml ssxml in endorsedSignatures) {
						sigxml = ssxml.GetXml ();
						edata = Encrypt (sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
						header.AddContent (edata);
					}

					if (security.RequireSignatureConfirmation) {
						Collection<Wss11SignatureConfirmation> confs = header.FindAll<Wss11SignatureConfirmation> ();
						int count = 0;
						foreach (XmlElement elem in doc.SelectNodes ("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr)) {
							edata = Encrypt (elem, actualKey, confs [count].Id, refList, actualClause, exml, doc);
							EncryptedXml.ReplaceElement (elem, edata, false);
							header.Contents.Insert (header.Contents.IndexOf (confs [count]), edata);
							header.Contents.Remove (confs [count++]);
						}
					}
				}

				// encrypt Encrypted supporting tokens
				foreach (SupportingTokenInfo tinfo in tokenInfos) {
					if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted) {
						XmlElement el = exml.GetIdElement (doc, tinfo.Token.Id);
						tinfo.Encrypted = Encrypt (el, actualKey, actualToken.Id, refList, actualClause, exml, doc);
						EncryptedXml.ReplaceElement (el, tinfo.Encrypted, false);
						header.Contents.Insert (header.Contents.IndexOf (tinfo.Token), tinfo.Encrypted);
						header.Contents.Remove (tinfo.Token);
					}
				}
				break;
			}

			Message ret = new WSSecurityMessage (Message.CreateMessage (msg.Version, msg.Headers.Action, new XmlNodeReader (doc.SelectSingleNode ("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);
			ret.Properties.Security = (SecurityMessageProperty) secprop.CreateCopy ();
			ret.Properties.Security.EncryptionKey = masterKey.Key;

			// FIXME: can we support TransportToken here?
			if (element is AsymmetricSecurityBindingElement) {
				ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (encToken, null); // FIXME: second argument
				ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification (signToken, null); // FIXME: second argument
			}
			else
				ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification (primaryToken, null);

			ret.Headers.Clear ();
			ret.Headers.CopyHeadersFrom (msg);

			// Header contents are:
			//	- Timestamp
			//	- SignatureConfirmation if required
			//	- EncryptionToken if included
			//	- derived key token for EncryptionToken
			//	- ReferenceList for encrypted items
			//	- signed supporting tokens
			//	- signed endorsing supporting tokens
			//	(i.e. Signed/SignedEncrypted/SignedEndorsing)
			//	- Signature Token if different from enc token.
			//	- derived key token for sig token if different
			//	- Signature for:
			//		- Timestamp
			//		- supporting tokens (regardless of
			//		  its inclusion)
			//		- message parts in SignedParts
			//		- SignatureToken if TokenProtection
			//		  (regardless of its inclusion)
			//	- Signatures for the main signature (above),
			//	  for every endorsing token and signed
			//	  endorsing token.
			//	

//MessageBuffer zzz = ret.CreateBufferedCopy (100000);
//ret = zzz.CreateMessage ();
//Console.WriteLine (zzz.CreateMessage ());
			return ret;
		}
Exemplo n.º 4
0
        public Message SecureMessage()
        {
            secprop = Message.Properties.Security ?? new SecurityMessageProperty();

            SecurityToken encToken =
                secprop.InitiatorToken != null ? secprop.InitiatorToken.SecurityToken : security.EncryptionToken;
            // FIXME: it might be still incorrect.
            SecurityToken signToken =
                Parameters == CounterParameters ? null :
                security.SigningToken;
            MessageProtectionOrder protectionOrder =
                security.MessageProtectionOrder;
            SecurityTokenSerializer serializer =
                security.TokenSerializer;
            SecurityBindingElement element =
                security.Element;
            SecurityAlgorithmSuite suite = element.DefaultAlgorithmSuite;

            string      messageId         = "uuid-" + Guid.NewGuid();
            int         identForMessageId = 1;
            XmlDocument doc = new XmlDocument();

            doc.PreserveWhitespace = true;

            // FIXME: get correct ReplyTo value
            if (Direction == MessageDirection.Input)
            {
                msg.Headers.ReplyTo = new EndpointAddress(Constants.WsaAnonymousUri);
            }

            if (MessageTo != null)
            {
                msg.Headers.To = MessageTo.Uri;
            }

            // wss:Security
            WSSecurityMessageHeader header =
                new WSSecurityMessageHeader(serializer);

            msg.Headers.Add(header);
            // 1. [Timestamp]
            if (element.IncludeTimestamp)
            {
                WsuTimestamp timestamp = new WsuTimestamp();
                timestamp.Id      = messageId + "-" + identForMessageId++;
                timestamp.Created = DateTime.Now;
                // FIXME: on service side, use element.LocalServiceSettings.TimestampValidityDuration
                timestamp.Expires = timestamp.Created.Add(element.LocalClientSettings.TimestampValidityDuration);
                header.AddContent(timestamp);
            }

            XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);

            nsmgr.AddNamespace("s", msg.Version.Envelope.Namespace);
            nsmgr.AddNamespace("o", Constants.WssNamespace);
            nsmgr.AddNamespace("u", Constants.WsuNamespace);
            nsmgr.AddNamespace("o11", Constants.Wss11Namespace);

            /*WrappedKey*/ SecurityToken primaryToken = null;
            DerivedKeySecurityToken      dkeyToken    = null;
            SecurityToken actualToken = null;
            SecurityKeyIdentifierClause actualClause = null;
            Signature sig = null;

            List <DerivedKeySecurityToken> derivedKeys =
                new List <DerivedKeySecurityToken> ();

            SymmetricAlgorithm masterKey = new RijndaelManaged();

            masterKey.KeySize = suite.DefaultSymmetricKeyLength;
            masterKey.Mode    = CipherMode.CBC;
            masterKey.Padding = PaddingMode.ISO10126;
            SymmetricAlgorithm actualKey = masterKey;

            // 2. [Encryption Token]

            // SecurityTokenInclusionMode
            // - Initiator or Recipient
            // - done or notyet. FIXME: not implemented yet
            // It also affects on key reference output

            bool includeEncToken =             // /* FIXME: remove this hack */Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.RecipientParameters.InclusionMode, false);
            bool includeSigToken =             // /* FIXME: remove this hack */ Parameters is SslSecurityTokenParameters ? false :
                                   ShouldIncludeToken(
                Security.InitiatorParameters.InclusionMode, false);

            SecurityKeyIdentifierClause encClause = ShouldOutputEncryptedKey ?
                                                    CounterParameters.CallCreateKeyIdentifierClause(encToken, !ShouldOutputEncryptedKey ? SecurityTokenReferenceStyle.Internal : includeEncToken ? Parameters.ReferenceStyle : SecurityTokenReferenceStyle.External) : null;

            MessagePartSpecification sigSpec = SignaturePart;
            MessagePartSpecification encSpec = EncryptionPart;

            // encryption key (possibly also used for signing)
            // FIXME: get correct SymmetricAlgorithm according to the algorithm suite
            if (secprop.EncryptionKey != null)
            {
                actualKey.Key = secprop.EncryptionKey;
            }

// FIXME: remove thid hack
            if (!ShouldOutputEncryptedKey)
            {
                primaryToken = secprop.ProtectionToken.SecurityToken as WrappedKeySecurityToken;
            }
            else
            {
                primaryToken =
                    // FIXME: remove this hack?
                    encToken is SecurityContextSecurityToken ? encToken :
                    new WrappedKeySecurityToken(messageId + "-" + identForMessageId++,
                                                actualKey.Key,
                                                // security.DefaultKeyWrapAlgorithm,
                                                Parameters.InternalHasAsymmetricKey ?
                                                suite.DefaultAsymmetricKeyWrapAlgorithm :
                                                suite.DefaultSymmetricKeyWrapAlgorithm,
                                                encToken,
                                                encClause != null ? new SecurityKeyIdentifier(encClause) : null);
            }

            // If it reuses request's encryption key, do not output.
            if (ShouldOutputEncryptedKey)
            {
                header.AddContent(primaryToken);
            }

            actualToken = primaryToken;

            // FIXME: I doubt it is correct...
            WrappedKeySecurityToken requestEncKey = ShouldOutputEncryptedKey ? null : primaryToken as WrappedKeySecurityToken;

            actualClause = requestEncKey == null ? (SecurityKeyIdentifierClause)
                           new LocalIdKeyIdentifierClause(actualToken.Id, typeof(WrappedKeySecurityToken)) :
                           new InternalEncryptedKeyIdentifierClause(SHA1.Create().ComputeHash(requestEncKey.GetWrappedKey()));

            // generate derived key if needed
            if (CounterParameters.RequireDerivedKeys)
            {
                RijndaelManaged deriv = new RijndaelManaged();
                deriv.KeySize = suite.DefaultEncryptionKeyDerivationLength;
                deriv.Mode    = CipherMode.CBC;
                deriv.Padding = PaddingMode.ISO10126;
                deriv.GenerateKey();
                dkeyToken = new DerivedKeySecurityToken(
                    GenerateId(doc),
                    null,                     // algorithm
                    actualClause,
                    new InMemorySymmetricSecurityKey(actualKey.Key),
                    null,                     // name
                    null,                     // generation
                    null,                     // offset
                    deriv.Key.Length,
                    null,                     // label
                    deriv.Key);
                derivedKeys.Add(dkeyToken);
                actualToken   = dkeyToken;
                actualKey.Key = ((SymmetricSecurityKey)dkeyToken.SecurityKeys [0]).GetSymmetricKey();
                actualClause  = new LocalIdKeyIdentifierClause(dkeyToken.Id);
                header.AddContent(dkeyToken);
            }

            ReferenceList refList = new ReferenceList();

            // When encrypted with DerivedKeyToken, put references
            // immediately after the derived token (not inside the
            // primary token).
            // Similarly, when we do not output EncryptedKey,
            // output ReferenceList in the same way.
            if (CounterParameters.RequireDerivedKeys ||
                !ShouldOutputEncryptedKey)
            {
                header.AddContent(refList);
            }
            else
            {
                ((WrappedKeySecurityToken)primaryToken).ReferenceList = refList;
            }

            // [Signature Confirmation]
            if (security.RequireSignatureConfirmation && secprop.ConfirmedSignatures.Count > 0)
            {
                foreach (string value in secprop.ConfirmedSignatures)
                {
                    header.AddContent(new Wss11SignatureConfirmation(GenerateId(doc), value));
                }
            }

            SupportingTokenInfoCollection tokenInfos =
                Direction == MessageDirection.Input ?
                security.CollectSupportingTokens(GetAction()) :
                new SupportingTokenInfoCollection();                  // empty

            foreach (SupportingTokenInfo tinfo in tokenInfos)
            {
                header.AddContent(tinfo.Token);
            }

            // populate DOM to sign.
            XPathNavigator nav = doc.CreateNavigator();

            using (XmlWriter w = nav.AppendChild()) {
                msg.WriteMessage(w);
            }

            XmlElement body    = doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement;
            string     bodyId  = null;
            XmlElement secElem = null;
            Collection <WSSignedXml> endorsedSignatures =
                new Collection <WSSignedXml> ();
            bool signatureProtection = (protectionOrder == MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature);

            // Below are o:Security contents that are not signed...
            if (includeSigToken && signToken != null)
            {
                header.AddContent(signToken);
            }

            switch (protectionOrder)
            {
            case MessageProtectionOrder.EncryptBeforeSign:
                // FIXME: implement
                throw new NotImplementedException();

            case MessageProtectionOrder.SignBeforeEncrypt:
            case MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature:

                // sign
                // see clause 8 of WS-SecurityPolicy C.2.2
                WSSignedXml sxml = new WSSignedXml(doc);
                SecurityTokenReferenceKeyInfo sigKeyInfo;

                sig = sxml.Signature;
                sig.SignedInfo.CanonicalizationMethod =
                    suite.DefaultCanonicalizationAlgorithm;
                foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/u:Timestamp", nsmgr))
                {
                    CreateReference(sig, elem, elem.GetAttribute("Id", Constants.WsuNamespace));
                }
                foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
                {
                    CreateReference(sig, elem, elem.GetAttribute("Id", Constants.WsuNamespace));
                }
                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    if (tinfo.Mode != SecurityTokenAttachmentMode.Endorsing)
                    {
                        XmlElement el = sxml.GetIdElement(doc, tinfo.Token.Id);
                        CreateReference(sig, el, el.GetAttribute("Id", Constants.WsuNamespace));
                    }
                }
                XmlNodeList nodes = doc.SelectNodes("/s:Envelope/s:Header/*", nsmgr);
                for (int i = 0; i < msg.Headers.Count; i++)
                {
                    MessageHeaderInfo h = msg.Headers [i];
                    if (h.Name == "Security" && h.Namespace == Constants.WssNamespace)
                    {
                        secElem = nodes [i] as XmlElement;
                    }
                    else if (sigSpec.HeaderTypes.Count == 0 ||
                             sigSpec.HeaderTypes.Contains(new XmlQualifiedName(h.Name, h.Namespace)))
                    {
                        string id = GenerateId(doc);
                        h.Id = id;
                        CreateReference(sig, nodes [i] as XmlElement, id);
                    }
                }
                if (sigSpec.IsBodyIncluded)
                {
                    bodyId = GenerateId(doc);
                    CreateReference(sig, body.ParentNode as XmlElement, bodyId);
                }

                if (security.DefaultSignatureAlgorithm == SignedXml.XmlDsigHMACSHA1Url)
                {
                    // FIXME: use appropriate hash algorithm
                    sxml.ComputeSignature(new HMACSHA1(actualKey.Key));
                    sigKeyInfo = new SecurityTokenReferenceKeyInfo(actualClause, serializer, doc);
                }
                else
                {
                    SecurityKeyIdentifierClause signClause =
                        CounterParameters.CallCreateKeyIdentifierClause(signToken, includeSigToken ? CounterParameters.ReferenceStyle : SecurityTokenReferenceStyle.External);
                    AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)signToken.ResolveKeyIdentifierClause(signClause);
                    sxml.SigningKey = signKey.GetAsymmetricAlgorithm(security.DefaultSignatureAlgorithm, true);
                    sxml.ComputeSignature();
                    sigKeyInfo = new SecurityTokenReferenceKeyInfo(signClause, serializer, doc);
                }

                sxml.KeyInfo = new KeyInfo();
                sxml.KeyInfo.AddClause(sigKeyInfo);

                if (!signatureProtection)
                {
                    header.AddContent(sig);
                }

                // endorse the signature with (signed)endorsing
                // supporting tokens.

                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    switch (tinfo.Mode)
                    {
                    case SecurityTokenAttachmentMode.Endorsing:
                    case SecurityTokenAttachmentMode.SignedEndorsing:
                        if (sxml.Signature.Id == null)
                        {
                            sig.Id = GenerateId(doc);
                            secElem.AppendChild(sxml.GetXml());
                        }
                        WSSignedXml ssxml = new WSSignedXml(doc);
                        ssxml.Signature.SignedInfo.CanonicalizationMethod = suite.DefaultCanonicalizationAlgorithm;
                        CreateReference(ssxml.Signature, doc, sig.Id);
                        SecurityToken sst = tinfo.Token;
                        SecurityKey   ssk = sst.SecurityKeys [0];                                     // FIXME: could be different?
                        SecurityKeyIdentifierClause tclause = new LocalIdKeyIdentifierClause(sst.Id); // FIXME: could be different?
                        if (ssk is SymmetricSecurityKey)
                        {
                            SymmetricSecurityKey signKey = (SymmetricSecurityKey)ssk;
                            ssxml.ComputeSignature(signKey.GetKeyedHashAlgorithm(suite.DefaultSymmetricSignatureAlgorithm));
                        }
                        else
                        {
                            AsymmetricSecurityKey signKey = (AsymmetricSecurityKey)ssk;
                            ssxml.SigningKey = signKey.GetAsymmetricAlgorithm(suite.DefaultAsymmetricSignatureAlgorithm, true);
                            ssxml.ComputeSignature();
                        }
                        ssxml.KeyInfo.AddClause(new SecurityTokenReferenceKeyInfo(tclause, serializer, doc));
                        if (!signatureProtection)
                        {
                            header.AddContent(ssxml.Signature);
                        }
                        endorsedSignatures.Add(ssxml);

                        break;
                    }
                }

                // encrypt

                WSEncryptedXml exml = new WSEncryptedXml(doc);

                EncryptedData edata = Encrypt(body, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                EncryptedXml.ReplaceElement(body, edata, false);

                // encrypt signature
                if (signatureProtection)
                {
                    XmlElement sigxml = sig.GetXml();
                    edata = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                    header.AddContent(edata);

                    foreach (WSSignedXml ssxml in endorsedSignatures)
                    {
                        sigxml = ssxml.GetXml();
                        edata  = Encrypt(sigxml, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                        header.AddContent(edata);
                    }

                    if (security.RequireSignatureConfirmation)
                    {
                        Collection <Wss11SignatureConfirmation> confs = header.FindAll <Wss11SignatureConfirmation> ();
                        int count = 0;
                        foreach (XmlElement elem in doc.SelectNodes("/s:Envelope/s:Header/o:Security/o11:SignatureConfirmation", nsmgr))
                        {
                            edata = Encrypt(elem, actualKey, confs [count].Id, refList, actualClause, exml, doc);
                            EncryptedXml.ReplaceElement(elem, edata, false);
                            header.Contents.Insert(header.Contents.IndexOf(confs [count]), edata);
                            header.Contents.Remove(confs [count++]);
                        }
                    }
                }

                // encrypt Encrypted supporting tokens
                foreach (SupportingTokenInfo tinfo in tokenInfos)
                {
                    if (tinfo.Mode == SecurityTokenAttachmentMode.SignedEncrypted)
                    {
                        XmlElement el = exml.GetIdElement(doc, tinfo.Token.Id);
                        tinfo.Encrypted = Encrypt(el, actualKey, actualToken.Id, refList, actualClause, exml, doc);
                        EncryptedXml.ReplaceElement(el, tinfo.Encrypted, false);
                        header.Contents.Insert(header.Contents.IndexOf(tinfo.Token), tinfo.Encrypted);
                        header.Contents.Remove(tinfo.Token);
                    }
                }
                break;
            }

            Message ret = new WSSecurityMessage(Message.CreateMessage(msg.Version, msg.Headers.Action, new XmlNodeReader(doc.SelectSingleNode("/s:Envelope/s:Body/*", nsmgr) as XmlElement)), bodyId);

            ret.Properties.Security = (SecurityMessageProperty)secprop.CreateCopy();
            ret.Properties.Security.EncryptionKey = masterKey.Key;

            // FIXME: can we support TransportToken here?
            if (element is AsymmetricSecurityBindingElement)
            {
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(encToken, null);                  // FIXME: second argument
                ret.Properties.Security.InitiatorToken = new SecurityTokenSpecification(signToken, null);                 // FIXME: second argument
            }
            else
            {
                ret.Properties.Security.ProtectionToken = new SecurityTokenSpecification(primaryToken, null);
            }

            ret.Headers.Clear();
            ret.Headers.CopyHeadersFrom(msg);

            // Header contents are:
            //	- Timestamp
            //	- SignatureConfirmation if required
            //	- EncryptionToken if included
            //	- derived key token for EncryptionToken
            //	- ReferenceList for encrypted items
            //	- signed supporting tokens
            //	- signed endorsing supporting tokens
            //	(i.e. Signed/SignedEncrypted/SignedEndorsing)
            //	- Signature Token if different from enc token.
            //	- derived key token for sig token if different
            //	- Signature for:
            //		- Timestamp
            //		- supporting tokens (regardless of
            //		  its inclusion)
            //		- message parts in SignedParts
            //		- SignatureToken if TokenProtection
            //		  (regardless of its inclusion)
            //	- Signatures for the main signature (above),
            //	  for every endorsing token and signed
            //	  endorsing token.
            //

//MessageBuffer zzz = ret.CreateBufferedCopy (100000);
//ret = zzz.CreateMessage ();
//Console.WriteLine (zzz.CreateMessage ());
            return(ret);
        }