2004-03-20 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Security / System.Security.Cryptography.Xml / Signature.cs
1 //
2 // Signature.cs - Signature implementation for XML Signature
3 //
4 // Author:
5 //      Sebastien Pouliot (spouliot@motus.com)
6 //
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 //
9
10 using System.Collections;
11 using System.Security.Cryptography;
12 using System.Xml;
13
14 namespace System.Security.Cryptography.Xml {
15
16         public class Signature {
17                 static XmlNamespaceManager dsigNsmgr;
18                 
19                 static Signature ()
20                 {
21                         dsigNsmgr = new XmlNamespaceManager (new NameTable ());
22                         dsigNsmgr.AddNamespace ("xd", XmlSignature.NamespaceURI);
23                 }
24
25                 private ArrayList list;
26                 private SignedInfo info;
27                 private KeyInfo key;
28                 private string id;
29                 private byte[] signature;
30
31                 public Signature() 
32                 {
33                         list = new ArrayList ();
34                 }
35
36                 public string Id {
37                         get { return id; }
38                         set { id = value; }
39                 }
40
41                 public KeyInfo KeyInfo {
42                         get { return key; }
43                         set { key = value; }
44                 }
45
46                 public IList ObjectList {
47                         get { return list; }
48                         set { list = ArrayList.Adapter (value); }
49                 }
50
51                 public byte[] SignatureValue {
52                         get { return signature; }
53                         set { signature = value; }
54                 }
55
56                 public SignedInfo SignedInfo {
57                         get { return info; }
58                         set { info = value; }
59                 }
60
61                 public void AddObject (DataObject dataObject) 
62                 {
63                         list.Add (dataObject);
64                 }
65
66                 public XmlElement GetXml () 
67                 {
68                         if (info == null)
69                                 throw new CryptographicException ("SignedInfo");
70                         if (signature == null)
71                                 throw new CryptographicException ("SignatureValue");
72
73                         XmlDocument document = new XmlDocument ();
74                         XmlElement xel = document.CreateElement (XmlSignature.ElementNames.Signature, XmlSignature.NamespaceURI);
75                         if (id != null)
76                                 xel.SetAttribute (XmlSignature.AttributeNames.Id, id);
77
78                         XmlNode xn = info.GetXml ();
79                         XmlNode newNode = document.ImportNode (xn, true);
80                         xel.AppendChild (newNode);
81
82                         if (signature != null) {
83                                 XmlElement sv = document.CreateElement (XmlSignature.ElementNames.SignatureValue, XmlSignature.NamespaceURI);
84                                 sv.InnerText = Convert.ToBase64String (signature);
85                                 xel.AppendChild (sv);
86                         }
87
88                         if (key != null) {
89                                 xn = key.GetXml ();
90                                 newNode = document.ImportNode (xn, true);
91                                 xel.AppendChild (newNode);
92                         }
93
94                         if (list.Count > 0) {
95                                 foreach (DataObject obj in list) {
96                                         xn = obj.GetXml ();
97                                         newNode = document.ImportNode (xn, true);
98                                         xel.AppendChild (newNode);
99                                 }
100                         }
101
102                         return xel;
103                 }
104
105                 private string GetAttribute (XmlElement xel, string attribute) 
106                 {
107                         XmlAttribute xa = xel.Attributes [attribute];
108                         return ((xa != null) ? xa.InnerText : null);
109                 }
110
111                 public void LoadXml (XmlElement value) 
112                 {
113                         if (value == null)
114                                 throw new ArgumentNullException ("value");
115
116                         if ((value.LocalName == XmlSignature.ElementNames.Signature) && (value.NamespaceURI == XmlSignature.NamespaceURI)) {
117                                 id = GetAttribute (value, XmlSignature.AttributeNames.Id);
118
119                                 // LAMESPEC: This library is totally useless against eXtensibly Marked-up document.
120                                 int i = NextElementPos (value.ChildNodes, 0, XmlSignature.ElementNames.SignedInfo, XmlSignature.NamespaceURI, true);
121                                 XmlElement sinfo = (XmlElement) value.ChildNodes [i];
122                                 info = new SignedInfo ();
123                                 info.LoadXml (sinfo);
124
125                                 i = NextElementPos (value.ChildNodes, ++i, XmlSignature.ElementNames.SignatureValue, XmlSignature.NamespaceURI, true);
126                                 XmlElement sigValue = (XmlElement) value.ChildNodes [i];
127                                 signature = Convert.FromBase64String (sigValue.InnerText);
128
129                                 // signature isn't required: <element ref="ds:KeyInfo" minOccurs="0"/> 
130                                 i = NextElementPos (value.ChildNodes, ++i, XmlSignature.ElementNames.KeyInfo, XmlSignature.NamespaceURI, false);
131                                 if (i > 0) {
132                                         XmlElement kinfo = (XmlElement) value.ChildNodes [i];
133                                         key = new KeyInfo ();
134                                         key.LoadXml (kinfo);
135                                 }
136
137                                 XmlNodeList xnl = value.SelectNodes ("xd:Object", dsigNsmgr);
138                                 foreach (XmlElement xn in xnl) {
139                                         DataObject obj = new DataObject ();
140                                         obj.LoadXml (xn);
141                                         AddObject (obj);
142                                 }
143                         }
144                         else
145                                 throw new CryptographicException ("Malformed element: Signature.");
146
147                         // if invalid
148                         if (info == null)
149                                 throw new CryptographicException ("SignedInfo");
150                         if (signature == null)
151                                 throw new CryptographicException ("SignatureValue");
152                 }
153
154                 private int NextElementPos (XmlNodeList nl, int pos, string name, string ns, bool required)
155                 {
156                         while (pos < nl.Count) {
157                                 if (nl [pos].NodeType == XmlNodeType.Element) {
158                                         if (nl [pos].LocalName != name && nl [pos].NamespaceURI != ns) {
159                                                 if (required)
160                                                         throw new CryptographicException ("Malformed element " + name);
161                                                 else
162                                                         return -2;
163                                         }
164                                         return pos;
165                                 }
166                                 else
167                                         pos++;
168                         }
169                         if (required)
170                                 throw new CryptographicException ("Malformed element " + name);
171                         return -1;
172                 }
173         }
174 }