2004-03-26 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Security / System.Security.Cryptography.Xml / SignedInfo.cs
1 //
2 // SignedInfo.cs - SignedInfo implementation for XML Signature
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
8 // (C) 2004 Novell (http://www.novell.com)
9 //
10
11 using System.Collections;
12 using System.Xml;
13
14 namespace System.Security.Cryptography.Xml { 
15
16         public class SignedInfo : ICollection, IEnumerable {
17
18                 private ArrayList references;
19                 private string c14nMethod;
20                 private string id;
21                 private string signatureMethod;
22                 private string signatureLength;
23                 private XmlElement element;
24
25                 public SignedInfo() 
26                 {
27                         references = new ArrayList ();
28                         c14nMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
29                 }
30
31                 public string CanonicalizationMethod {
32                         get { return c14nMethod; }
33                         set {
34                                 c14nMethod = value;
35                                 element = null;
36                         }
37                 }
38
39                 // documented as not supported (and throwing exception)
40                 public int Count {
41                         get { throw new NotSupportedException (); }
42                 }
43
44                 public string Id {
45                         get { return id; }
46                         set {
47                                 element = null;
48                                 id = value;
49                         }
50                 }
51
52                 // documented as not supported (and throwing exception)
53                 public bool IsReadOnly {
54                         get { throw new NotSupportedException (); }
55                 }
56
57                 // documented as not supported (and throwing exception)
58                 public bool IsSynchronized {
59                         get { throw new NotSupportedException (); }
60                 }
61
62                 // Manipulating this array never affects GetXml() when 
63                 // LoadXml() was used. 
64                 // (Actually, there is no way to detect modification.)
65                 public ArrayList References {
66                         get { return references; }
67                 }
68
69                 public string SignatureLength {
70                         get { return signatureLength; }
71                         set {
72                                 element = null;
73                                 signatureLength = value;
74                         }
75                 }
76
77                 public string SignatureMethod {
78                         get { return signatureMethod; }
79                         set {
80                                 element = null;
81                                 signatureMethod = value;
82                         }
83                 }
84
85                 // documented as not supported (and throwing exception)
86                 public object SyncRoot {
87                         get { throw new NotSupportedException (); }
88                 }
89
90                 public void AddReference (Reference reference) 
91                 {
92                         references.Add (reference);
93                 }
94
95                 // documented as not supported (and throwing exception)
96                 public void CopyTo (Array array, int index) 
97                 {
98                         throw new NotSupportedException ();
99                 }
100
101                 public IEnumerator GetEnumerator () 
102                 {
103                         return references.GetEnumerator ();
104                 }
105
106                 public XmlElement GetXml ()
107                 {
108                         if (element != null)
109                                 return element;
110
111                         if (signatureMethod == null)
112                                 throw new CryptographicException ("SignatureMethod");
113                         if (references.Count == 0)
114                                 throw new CryptographicException ("References empty");
115
116                         XmlDocument document = new XmlDocument ();
117                         XmlElement xel = document.CreateElement (XmlSignature.ElementNames.SignedInfo, XmlSignature.NamespaceURI);
118                         if (id != null)
119                                 xel.SetAttribute (XmlSignature.AttributeNames.Id, id);
120
121                         if (c14nMethod != null) {
122                                 XmlElement c14n = document.CreateElement (XmlSignature.ElementNames.CanonicalizationMethod, XmlSignature.NamespaceURI);
123                                 c14n.SetAttribute (XmlSignature.AttributeNames.Algorithm, c14nMethod);
124                                 xel.AppendChild (c14n);
125                         }
126                         if (signatureMethod != null) {
127                                 XmlElement sm = document.CreateElement (XmlSignature.ElementNames.SignatureMethod, XmlSignature.NamespaceURI);
128                                 sm.SetAttribute (XmlSignature.AttributeNames.Algorithm, signatureMethod);
129                                 if (signatureLength != null) {
130                                         XmlElement hmac = document.CreateElement (XmlSignature.ElementNames.HMACOutputLength, XmlSignature.NamespaceURI);
131                                         hmac.InnerText = signatureLength;
132                                         sm.AppendChild (hmac);
133                                 }
134                                 xel.AppendChild (sm);
135                         }
136
137                         // This check is only done when element is created here.
138                         if (references.Count == 0)
139                                 throw new CryptographicException ("At least one Reference element is required in SignedInfo.");
140
141                         // we add References afterward so we don't end up with extraneous
142                         // xmlns="..." in each reference elements.
143                         foreach (Reference r in references) {
144                                 XmlNode xn = r.GetXml ();
145                                 XmlNode newNode = document.ImportNode (xn, true);
146                                 xel.AppendChild (newNode);
147                         }
148
149                         return xel;
150                 }
151
152                 private string GetAttribute (XmlElement xel, string attribute) 
153                 {
154                         XmlAttribute xa = xel.Attributes [attribute];
155                         return ((xa != null) ? xa.InnerText : null);
156                 }
157
158                 public void LoadXml (XmlElement value) 
159                 {
160                         if (value == null)
161                                 throw new ArgumentNullException ("value");
162
163                         if ((value.LocalName != XmlSignature.ElementNames.SignedInfo) || (value.NamespaceURI != XmlSignature.NamespaceURI))
164                                 throw new CryptographicException ();
165
166                         id = GetAttribute (value, XmlSignature.AttributeNames.Id);
167                         c14nMethod = XmlSignature.GetAttributeFromElement (value, XmlSignature.AttributeNames.Algorithm, XmlSignature.ElementNames.CanonicalizationMethod);
168
169                         XmlElement sm = XmlSignature.GetChildElement (value, XmlSignature.ElementNames.SignatureMethod, XmlSignature.NamespaceURI);
170                         if (sm != null) {
171                                 signatureMethod = sm.GetAttribute (XmlSignature.AttributeNames.Algorithm);
172                                 XmlElement length = XmlSignature.GetChildElement (sm, XmlSignature.ElementNames.HMACOutputLength, XmlSignature.NamespaceURI);
173                                 if (length != null) {
174                                         signatureLength = length.InnerText;
175                                 }
176                         }
177
178                         for (int i = 0; i < value.ChildNodes.Count; i++) {
179                                 XmlNode n = value.ChildNodes [i];
180                                 if (n.NodeType == XmlNodeType.Element &&
181                                         n.LocalName == XmlSignature.ElementNames.Reference &&
182                                         n.NamespaceURI == XmlSignature.NamespaceURI) {
183                                         Reference r = new Reference ();
184                                         r.LoadXml ((XmlElement) n);
185                                         AddReference (r);
186                                 }
187                         }
188                         element = value;
189                 }
190         }
191 }