33b13c1c3c40da0440b9e456fd8103c6f9dc4cf8
[mono.git] / mcs / class / System.Security / System.Security.Cryptography.Xml / Reference.cs
1 //
2 // Reference.cs - Reference 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 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.IO;
33 using System.Xml;
34
35 namespace System.Security.Cryptography.Xml { 
36
37         // http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/Overview.html#sec-Reference
38         public class Reference {
39
40                 private TransformChain chain;
41                 private string digestMethod;
42                 private byte[] digestValue;
43                 private string id;
44                 private string uri;
45                 private string type;
46                 private Stream stream;
47                 private XmlElement element;
48
49                 public Reference () 
50                 {
51                         chain = new TransformChain ();
52                         digestMethod = XmlSignature.NamespaceURI + "sha1";
53                 }
54
55                 [MonoTODO ("There is no description about how it is used.")]
56                 public Reference (Stream stream) : this () 
57                 {
58                         this.stream = stream;
59                 }
60
61                 public Reference (string uri) : this ()
62                 {
63                         this.uri = uri;
64                 }
65
66                 // default to SHA1
67                 public string DigestMethod {
68                         get { return digestMethod; }
69                         set {
70                                 element = null;
71                                 digestMethod = value;
72                         }
73                 }
74
75                 public byte[] DigestValue {
76                         get { return digestValue; }
77                         set {
78                                 element = null;
79                                 digestValue = value;
80                         }
81                 }
82
83                 public string Id {
84                         get { return id; }
85                         set {
86                                 element = null;
87                                 id = value;
88                         }
89                 }
90
91                 public TransformChain TransformChain {
92                         get { return chain; }
93                 }
94
95                 public string Type {
96                         get { return type; }
97                         set {
98                                 element = null;
99                                 type = value;
100                         }
101                 }
102
103                 public string Uri {
104                         get { return uri; }
105                         set {
106                                 element = null;
107                                 uri = value;
108                         }
109                 }
110
111                 public void AddTransform (Transform transform) 
112                 {
113                         chain.Add (transform);
114                 }
115
116                 public XmlElement GetXml () 
117                 {
118                         if (element != null)
119                                 return element;
120
121                         if (digestMethod == null)
122                                 throw new CryptographicException ("DigestMethod");
123                         if (digestValue == null)
124                                 throw new NullReferenceException ("DigestValue");
125
126                         XmlDocument document = new XmlDocument ();
127                         XmlElement xel = document.CreateElement (XmlSignature.ElementNames.Reference, XmlSignature.NamespaceURI);
128                         if (id != null)
129                                 xel.SetAttribute (XmlSignature.AttributeNames.Id, id);
130                         if (uri != null)
131                                 xel.SetAttribute (XmlSignature.AttributeNames.URI, uri);
132                         if (type != null)
133                                 xel.SetAttribute (XmlSignature.AttributeNames.Type, type);
134
135                         if (chain.Count > 0) {
136                                 XmlElement ts = document.CreateElement (XmlSignature.ElementNames.Transforms, XmlSignature.NamespaceURI);
137                                 foreach (Transform t in chain) {
138                                         XmlNode xn = t.GetXml ();
139                                         XmlNode newNode = document.ImportNode (xn, true);
140                                         ts.AppendChild (newNode);
141                                 }
142                                 xel.AppendChild (ts);
143                         }
144
145                         XmlElement dm = document.CreateElement (XmlSignature.ElementNames.DigestMethod, XmlSignature.NamespaceURI);
146                         dm.SetAttribute (XmlSignature.AttributeNames.Algorithm, digestMethod);
147                         xel.AppendChild (dm);
148
149                         XmlElement dv = document.CreateElement (XmlSignature.ElementNames.DigestValue, XmlSignature.NamespaceURI);
150                         dv.InnerText = Convert.ToBase64String (digestValue);
151                         xel.AppendChild (dv);
152
153                         return xel;
154                 }
155
156                 // note: we do NOT return null -on purpose- if attribute isn't found
157                 private string GetAttribute (XmlElement xel, string attribute) 
158                 {
159                         XmlAttribute xa = xel.Attributes [attribute];
160                         return ((xa != null) ? xa.InnerText : null);
161                 }
162
163                 public void LoadXml (XmlElement value) 
164                 {
165                         if (value == null)
166                                 throw new ArgumentNullException ("value");
167
168                         if ((value.LocalName != XmlSignature.ElementNames.Reference) || (value.NamespaceURI != XmlSignature.NamespaceURI))
169                                 throw new CryptographicException ();
170
171                         id = GetAttribute (value, XmlSignature.AttributeNames.Id);
172                         uri = GetAttribute (value, XmlSignature.AttributeNames.URI);
173                         type = GetAttribute (value, XmlSignature.AttributeNames.Type);
174                         // Note: order is important for validations
175                         XmlNodeList xnl = value.GetElementsByTagName (XmlSignature.ElementNames.Transform, XmlSignature.NamespaceURI);
176                         if ((xnl != null) && (xnl.Count > 0)) {
177                                 Transform t = null;
178                                 foreach (XmlNode xn in xnl) {
179                                         string a = GetAttribute ((XmlElement)xn, XmlSignature.AttributeNames.Algorithm);
180 /*      This code is useful for debugging in VS.NET because using CryptoConfig
181         (from MS mscorlib) would throw InvalidCastException because it's 
182         Transform would come from MS System.Security.dll not Mono's.
183                                         switch (a) {
184                                                 case "http://www.w3.org/2000/09/xmldsig#base64":
185                                                         t = new XmlDsigBase64Transform ();
186                                                         break;
187                                                 case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315":
188                                                         t = new XmlDsigC14NTransform ();
189                                                         break;
190                                                 case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments":
191                                                         t = new XmlDsigC14NWithCommentsTransform ();
192                                                         break;
193                                                 case "http://www.w3.org/2000/09/xmldsig#enveloped-signature":
194                                                         t = new XmlDsigEnvelopedSignatureTransform ();
195                                                         break;
196                                                 case "http://www.w3.org/TR/1999/REC-xpath-19991116":
197                                                         t = new XmlDsigXPathTransform ();
198                                                         break;
199                                                 case "http://www.w3.org/TR/1999/REC-xslt-19991116":
200                                                         t = new XmlDsigXsltTransform ();
201                                                         break;
202                                                 default:
203                                                         throw new NotSupportedException ();
204                                         }
205 */
206                                         t = (Transform) CryptoConfig.CreateFromName (a);
207                                         if (t == null)
208                                                 throw new CryptographicException ("Unknown transform {0}.", a);
209
210                                         if (xn.ChildNodes.Count > 0) {
211                                                 t.LoadInnerXml (xn.ChildNodes);
212                                         }
213                                         AddTransform (t);
214                                 }
215                         }
216                         // get DigestMethod
217                         DigestMethod = XmlSignature.GetAttributeFromElement (value, XmlSignature.AttributeNames.Algorithm, XmlSignature.ElementNames.DigestMethod);
218                         // get DigestValue
219                         XmlElement dig = XmlSignature.GetChildElement (value, XmlSignature.ElementNames.DigestValue, XmlSignature.NamespaceURI);
220                         if (dig != null)
221                                 DigestValue = Convert.FromBase64String (dig.InnerText);
222                         element = value;
223                 }
224         }
225 }