// // Signature.cs - Signature implementation for XML Signature // // Author: // Sebastien Pouliot (spouliot@motus.com) // Tim Coleman (tim@timcoleman.com) // // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) // Copyright (C) Tim Coleman, 2004 // // // 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.Collections; using System.Security.Cryptography; using System.Xml; namespace System.Security.Cryptography.Xml { public class Signature { static XmlNamespaceManager dsigNsmgr; static Signature () { dsigNsmgr = new XmlNamespaceManager (new NameTable ()); dsigNsmgr.AddNamespace ("xd", XmlSignature.NamespaceURI); } private ArrayList list; private SignedInfo info; private KeyInfo key; private string id; private byte[] signature; private XmlElement element; public Signature () { list = new ArrayList (); } public string Id { get { return id; } set { element = null; id = value; } } public KeyInfo KeyInfo { get { return key; } set { element = null; key = value; } } public IList ObjectList { get { return list; } set { list = ArrayList.Adapter (value); } } public byte[] SignatureValue { get { return signature; } set { element = null; signature = value; } } public SignedInfo SignedInfo { get { return info; } set { element = null; info = value; } } public void AddObject (DataObject dataObject) { list.Add (dataObject); } public XmlElement GetXml () { return GetXml (null); } internal XmlElement GetXml (XmlDocument document) { if (element != null) return element; if (info == null) throw new CryptographicException ("SignedInfo"); if (signature == null) throw new CryptographicException ("SignatureValue"); if (document == null) document = new XmlDocument (); XmlElement xel = document.CreateElement (XmlSignature.ElementNames.Signature, XmlSignature.NamespaceURI); if (id != null) xel.SetAttribute (XmlSignature.AttributeNames.Id, id); XmlNode xn = info.GetXml (); XmlNode newNode = document.ImportNode (xn, true); xel.AppendChild (newNode); if (signature != null) { XmlElement sv = document.CreateElement (XmlSignature.ElementNames.SignatureValue, XmlSignature.NamespaceURI); sv.InnerText = Convert.ToBase64String (signature); xel.AppendChild (sv); } if (key != null) { xn = key.GetXml (); newNode = document.ImportNode (xn, true); xel.AppendChild (newNode); } if (list.Count > 0) { foreach (DataObject obj in list) { xn = obj.GetXml (); newNode = document.ImportNode (xn, true); xel.AppendChild (newNode); } } return xel; } private string GetAttribute (XmlElement xel, string attribute) { XmlAttribute xa = xel.Attributes [attribute]; return ((xa != null) ? xa.InnerText : null); } public void LoadXml (XmlElement value) { if (value == null) throw new ArgumentNullException ("value"); if ((value.LocalName == XmlSignature.ElementNames.Signature) && (value.NamespaceURI == XmlSignature.NamespaceURI)) { id = GetAttribute (value, XmlSignature.AttributeNames.Id); // LAMESPEC: This library is totally useless against eXtensibly Marked-up document. int i = NextElementPos (value.ChildNodes, 0, XmlSignature.ElementNames.SignedInfo, XmlSignature.NamespaceURI, true); XmlElement sinfo = (XmlElement) value.ChildNodes [i]; info = new SignedInfo (); info.LoadXml (sinfo); i = NextElementPos (value.ChildNodes, ++i, XmlSignature.ElementNames.SignatureValue, XmlSignature.NamespaceURI, true); XmlElement sigValue = (XmlElement) value.ChildNodes [i]; signature = Convert.FromBase64String (sigValue.InnerText); // signature isn't required: i = NextElementPos (value.ChildNodes, ++i, XmlSignature.ElementNames.KeyInfo, XmlSignature.NamespaceURI, false); if (i > 0) { XmlElement kinfo = (XmlElement) value.ChildNodes [i]; key = new KeyInfo (); key.LoadXml (kinfo); } XmlNodeList xnl = value.SelectNodes ("xd:Object", dsigNsmgr); foreach (XmlElement xn in xnl) { DataObject obj = new DataObject (); obj.LoadXml (xn); AddObject (obj); } } else throw new CryptographicException ("Malformed element: Signature."); // if invalid if (info == null) throw new CryptographicException ("SignedInfo"); if (signature == null) throw new CryptographicException ("SignatureValue"); } private int NextElementPos (XmlNodeList nl, int pos, string name, string ns, bool required) { while (pos < nl.Count) { if (nl [pos].NodeType == XmlNodeType.Element) { if (nl [pos].LocalName != name || nl [pos].NamespaceURI != ns) { if (required) throw new CryptographicException ("Malformed element " + name); else return -2; } else return pos; } else pos++; } if (required) throw new CryptographicException ("Malformed element " + name); return -1; } } }