Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

801 lines
30 KiB
C#

//
// MessageSecurityGenerator.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.ServiceModel.Security.Tokens;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using ReqType = System.ServiceModel.Security.Tokens.ServiceModelSecurityTokenRequirement;
namespace System.ServiceModel.Channels.Security
{
internal class InitiatorMessageSecurityGenerator : MessageSecurityGenerator
{
EndpointAddress message_to;
InitiatorMessageSecurityBindingSupport security;
public InitiatorMessageSecurityGenerator (
Message msg,
InitiatorMessageSecurityBindingSupport security,
EndpointAddress messageTo)
: base (msg, security)
{
// FIXME: I believe it should be done at channel
// creation phase, but WinFX does not.
// if (!security.InitiatorParameters.InternalHasAsymmetricKey)
// 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.");
this.security = security;
this.message_to = messageTo;
}
public override SecurityTokenParameters Parameters {
get { return security.InitiatorParameters; }
}
public override SecurityTokenParameters CounterParameters {
get { return security.RecipientParameters; }
}
public override MessageDirection Direction {
get { return MessageDirection.Input; }
}
public override EndpointAddress MessageTo {
get { return message_to; }
}
public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
{
switch (mode) {
case SecurityTokenInclusionMode.Never:
case SecurityTokenInclusionMode.AlwaysToInitiator:
return false;
case SecurityTokenInclusionMode.AlwaysToRecipient:
return true;
case SecurityTokenInclusionMode.Once:
return !isInitialized;
}
throw new Exception ("Internal Error: should not happen.");
}
public override ScopedMessagePartSpecification SignatureParts {
get { return Security.ChannelRequirements.IncomingSignatureParts; }
}
public override ScopedMessagePartSpecification EncryptionParts {
get { return Security.ChannelRequirements.IncomingEncryptionParts; }
}
}
internal class RecipientMessageSecurityGenerator : MessageSecurityGenerator
{
RecipientMessageSecurityBindingSupport security;
public RecipientMessageSecurityGenerator (
Message msg,
SecurityMessageProperty requestSecProp,
RecipientMessageSecurityBindingSupport security)
: base (msg, security)
{
this.security = security;
SecurityMessageProperty secprop =
(SecurityMessageProperty) requestSecProp.CreateCopy ();
msg.Properties.Security = secprop;
}
public override SecurityTokenParameters Parameters {
get { return security.RecipientParameters; }
}
public override SecurityTokenParameters CounterParameters {
get { return security.InitiatorParameters; }
}
public override MessageDirection Direction {
get { return MessageDirection.Output; }
}
public override EndpointAddress MessageTo {
get { return null; }
}
public override bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized)
{
switch (mode) {
case SecurityTokenInclusionMode.Never:
case SecurityTokenInclusionMode.AlwaysToRecipient:
return false;
case SecurityTokenInclusionMode.AlwaysToInitiator:
return true;
case SecurityTokenInclusionMode.Once:
return !isInitialized;
}
throw new Exception ("Internal Error: should not happen.");
}
public override ScopedMessagePartSpecification SignatureParts {
get { return Security.ChannelRequirements.OutgoingSignatureParts; }
}
public override ScopedMessagePartSpecification EncryptionParts {
get { return Security.ChannelRequirements.OutgoingEncryptionParts; }
}
}
internal abstract class MessageSecurityGenerator
{
Message msg;
SecurityMessageProperty secprop;
MessageSecurityBindingSupport security;
int idbase;
public MessageSecurityGenerator (Message msg,
MessageSecurityBindingSupport security)
{
this.msg = msg;
this.security = security;
}
public Message Message {
get { return msg; }
}
public MessageSecurityBindingSupport Security {
get { return security; }
}
public abstract SecurityTokenParameters Parameters { get; }
public abstract SecurityTokenParameters CounterParameters { get; }
public abstract MessageDirection Direction { get; }
public abstract EndpointAddress MessageTo { get; }
public abstract ScopedMessagePartSpecification SignatureParts { get; }
public abstract ScopedMessagePartSpecification EncryptionParts { get; }
public MessagePartSpecification SignaturePart {
get {
MessagePartSpecification spec;
if (!SignatureParts.TryGetParts (GetAction (), false, out spec))
spec = SignatureParts.ChannelParts;
return spec;
}
}
public MessagePartSpecification EncryptionPart {
get {
MessagePartSpecification spec;
if (!EncryptionParts.TryGetParts (GetAction (), false, out spec))
spec = EncryptionParts.ChannelParts;
return spec;
}
}
public abstract bool ShouldIncludeToken (SecurityTokenInclusionMode mode, bool isInitialized);
public bool ShouldOutputEncryptedKey {
get { return Direction == MessageDirection.Input || secprop.ProtectionToken == null; } //security.Element is AsymmetricSecurityBindingElement; }
}
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;
}
Signature CreateSignature (XmlDocument doc, XmlElement body,
XmlNamespaceManager nsmgr,
SupportingTokenInfoCollection tokenInfos,
SecurityKeyIdentifierClause actualClause,
SymmetricAlgorithm actualKey,
SecurityToken signToken,
bool includeSigToken,
bool signatureProtection,
WSSecurityMessageHeader header,
Collection<WSSignedXml> endorsedSignatures,
ref string bodyId)
{
// sign
// see clause 8 of WS-SecurityPolicy C.2.2
WSSignedXml sxml = new WSSignedXml (doc);
SecurityTokenReferenceKeyInfo sigKeyInfo;
XmlElement secElem = null;
var sigSpec = SignaturePart;
var serializer = security.TokenSerializer;
var suite = security.Element.DefaultAlgorithmSuite;
var 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))) &&
(msg.Version.Addressing != AddressingVersion.None ||
!String.Equals (h.Name, "Action", StringComparison.Ordinal))) {
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;
}
}
return sig;
}
void AddAddressingToHeader (MessageHeaders headers)
{
// FIXME: get correct ReplyTo value
if (Direction == MessageDirection.Input)
headers.ReplyTo = new EndpointAddress (Constants.WsaAnonymousUri);
if (MessageTo != null)
headers.To = MessageTo.Uri;
}
DerivedKeySecurityToken CreateDerivedKey (string id,
SecurityKeyIdentifierClause actualClause,
SymmetricAlgorithm actualKey)
{
RijndaelManaged deriv = new RijndaelManaged ();
deriv.KeySize = security.Element.DefaultAlgorithmSuite.DefaultEncryptionKeyDerivationLength;
deriv.Mode = CipherMode.CBC;
deriv.Padding = PaddingMode.ISO10126;
deriv.GenerateKey ();
var dkeyToken = new DerivedKeySecurityToken (
id,
null, // algorithm
actualClause,
new InMemorySymmetricSecurityKey (actualKey.Key),
null, // name
null, // generation
null, // offset
deriv.Key.Length,
null, // label
deriv.Key);
return dkeyToken;
}
void AddTimestampToHeader (WSSecurityMessageHeader header, string id)
{
WsuTimestamp timestamp = new WsuTimestamp ();
timestamp.Id = id;
timestamp.Created = DateTime.Now;
// FIXME: on service side, use element.LocalServiceSettings.TimestampValidityDuration
timestamp.Expires = timestamp.Created.Add (security.Element.LocalClientSettings.TimestampValidityDuration);
header.AddContent (timestamp);
}
void CreateReference (Signature sig, XmlElement el, string id)
{
CreateReference (sig, el.OwnerDocument, id);
if (el.GetAttribute ("Id", Constants.WsuNamespace) != id) {
XmlAttribute a = el.SetAttributeNode ("Id", Constants.WsuNamespace);
a.Prefix = "u";
a.Value = id;
}
}
void CreateReference (Signature sig, XmlDocument doc, string id)
{
SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
if (id == String.Empty)
id = GenerateId (doc);
Reference r = new Reference ("#" + id);
r.AddTransform (CreateTransform (suite.DefaultCanonicalizationAlgorithm));
r.DigestMethod = suite.DefaultDigestAlgorithm;
sig.SignedInfo.AddReference (r);
}
Transform CreateTransform (string url)
{
switch (url) {
case SignedXml.XmlDsigC14NTransformUrl:
return new XmlDsigC14NTransform ();
case SignedXml.XmlDsigC14NWithCommentsTransformUrl:
return new XmlDsigC14NWithCommentsTransform ();
case SignedXml.XmlDsigExcC14NTransformUrl:
return new XmlDsigExcC14NTransform ();
case SignedXml.XmlDsigExcC14NWithCommentsTransformUrl:
return new XmlDsigExcC14NWithCommentsTransform ();
}
throw new Exception (String.Format ("INTERNAL ERROR: Invalid canonicalization URL: {0}", url));
}
EncryptedData Encrypt (XmlElement target, SymmetricAlgorithm actualKey, string ekeyId, ReferenceList refList, SecurityKeyIdentifierClause encClause, EncryptedXml exml, XmlDocument doc, string elementType)
{
SecurityAlgorithmSuite suite = security.Element.DefaultAlgorithmSuite;
SecurityTokenSerializer serializer = security.TokenSerializer;
byte [] encrypted = exml.EncryptData (target, actualKey, false);
EncryptedData edata = new EncryptedData ();
edata.Id = GenerateId (doc);
edata.Type = elementType;
edata.EncryptionMethod = new EncryptionMethod (suite.DefaultEncryptionAlgorithm);
// FIXME: here wsse:DigestMethod should be embedded
// inside EncryptionMethod. Since it is not possible
// with S.S.C.Xml.EncryptionMethod, we will have to
// build our own XML encryption classes.
edata.CipherData.CipherValue = encrypted;
DataReference dr = new DataReference ();
dr.Uri = "#" + edata.Id;
refList.Add (dr);
if (ShouldOutputEncryptedKey && !CounterParameters.RequireDerivedKeys)
edata.KeyInfo = null;
else {
edata.KeyInfo = new KeyInfo ();
edata.KeyInfo.AddClause (new SecurityTokenReferenceKeyInfo (encClause, serializer, doc));
}
return edata;
}
string GenerateId (XmlDocument doc)
{
idbase++;
return secprop.SenderIdPrefix + idbase;
}
public string GetAction ()
{
string ret = msg.Headers.Action;
if (ret == null) {
HttpRequestMessageProperty reqprop =
msg.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
if (reqprop != null)
ret = reqprop.Headers ["Action"];
}
return ret;
}
}
internal class WSSecurityMessage : Message
{
Message msg;
string body_id;
public WSSecurityMessage (Message msg, string bodyId)
{
this.msg = msg;
this.body_id = bodyId;
}
public override MessageVersion Version {
get { return msg.Version; }
}
public override MessageHeaders Headers {
get { return msg.Headers; }
}
public override MessageProperties Properties {
get { return msg.Properties; }
}
protected override MessageBuffer OnCreateBufferedCopy (int maxBufferSize)
{
return new WSSecurityMessageBuffer (msg.CreateBufferedCopy (maxBufferSize), body_id);
}
protected override string OnGetBodyAttribute (string localName, string ns)
{
if (localName == "Id" && ns == Constants.WsuNamespace)
return body_id;
return msg.GetBodyAttribute (localName, ns);
}
protected override void OnWriteStartBody (
XmlDictionaryWriter writer)
{
var dic = Constants.SoapDictionary;
writer.WriteStartElement ("s", dic.Add ("Body"), dic.Add (Version.Envelope.Namespace));
if (body_id != null)
writer.WriteAttributeString ("u", "Id", Constants.WsuNamespace, body_id);
}
protected override void OnWriteBodyContents (XmlDictionaryWriter w)
{
msg.WriteBodyContents (w);
}
}
internal class WSSecurityMessageBuffer : MessageBuffer
{
public WSSecurityMessageBuffer (MessageBuffer mb, string bodyId)
{
buffer = mb;
body_id = bodyId;
}
MessageBuffer buffer;
string body_id;
public override int BufferSize {
get { return buffer.BufferSize; }
}
public override void Close ()
{
buffer.Close ();
}
public override Message CreateMessage ()
{
return new WSSecurityMessage (buffer.CreateMessage (), body_id);
}
}
}