Copied remotely
[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 #if NET_2_0
94                         set { chain = value; }
95 #endif
96                 }
97
98                 public string Type {
99                         get { return type; }
100                         set {
101                                 element = null;
102                                 type = value;
103                         }
104                 }
105
106                 public string Uri {
107                         get { return uri; }
108                         set {
109                                 element = null;
110                                 uri = value;
111                         }
112                 }
113
114                 public void AddTransform (Transform transform) 
115                 {
116                         chain.Add (transform);
117                 }
118
119                 public XmlElement GetXml () 
120                 {
121                         if (element != null)
122                                 return element;
123
124                         if (digestMethod == null)
125                                 throw new CryptographicException ("DigestMethod");
126                         if (digestValue == null)
127                                 throw new NullReferenceException ("DigestValue");
128
129                         XmlDocument document = new XmlDocument ();
130                         XmlElement xel = document.CreateElement (XmlSignature.ElementNames.Reference, XmlSignature.NamespaceURI);
131                         if (id != null)
132                                 xel.SetAttribute (XmlSignature.AttributeNames.Id, id);
133                         if (uri != null)
134                                 xel.SetAttribute (XmlSignature.AttributeNames.URI, uri);
135                         if (type != null)
136                                 xel.SetAttribute (XmlSignature.AttributeNames.Type, type);
137
138                         if (chain.Count > 0) {
139                                 XmlElement ts = document.CreateElement (XmlSignature.ElementNames.Transforms, XmlSignature.NamespaceURI);
140                                 foreach (Transform t in chain) {
141                                         XmlNode xn = t.GetXml ();
142                                         XmlNode newNode = document.ImportNode (xn, true);
143                                         ts.AppendChild (newNode);
144                                 }
145                                 xel.AppendChild (ts);
146                         }
147
148                         XmlElement dm = document.CreateElement (XmlSignature.ElementNames.DigestMethod, XmlSignature.NamespaceURI);
149                         dm.SetAttribute (XmlSignature.AttributeNames.Algorithm, digestMethod);
150                         xel.AppendChild (dm);
151
152                         XmlElement dv = document.CreateElement (XmlSignature.ElementNames.DigestValue, XmlSignature.NamespaceURI);
153                         dv.InnerText = Convert.ToBase64String (digestValue);
154                         xel.AppendChild (dv);
155
156                         return xel;
157                 }
158
159                 // note: we do NOT return null -on purpose- if attribute isn't found
160                 private string GetAttribute (XmlElement xel, string attribute) 
161                 {
162                         XmlAttribute xa = xel.Attributes [attribute];
163                         return ((xa != null) ? xa.InnerText : null);
164                 }
165
166                 public void LoadXml (XmlElement value) 
167                 {
168                         if (value == null)
169                                 throw new ArgumentNullException ("value");
170
171                         if ((value.LocalName != XmlSignature.ElementNames.Reference) || (value.NamespaceURI != XmlSignature.NamespaceURI))
172                                 throw new CryptographicException ();
173
174                         id = GetAttribute (value, XmlSignature.AttributeNames.Id);
175                         uri = GetAttribute (value, XmlSignature.AttributeNames.URI);
176                         type = GetAttribute (value, XmlSignature.AttributeNames.Type);
177                         // Note: order is important for validations
178                         XmlNodeList xnl = value.GetElementsByTagName (XmlSignature.ElementNames.Transform, XmlSignature.NamespaceURI);
179                         if ((xnl != null) && (xnl.Count > 0)) {
180                                 Transform t = null;
181                                 foreach (XmlNode xn in xnl) {
182                                         string a = GetAttribute ((XmlElement)xn, XmlSignature.AttributeNames.Algorithm);
183 /*      This code is useful for debugging in VS.NET because using CryptoConfig
184         (from MS mscorlib) would throw InvalidCastException because it's 
185         Transform would come from MS System.Security.dll not Mono's.
186                                         switch (a) {
187                                                 case "http://www.w3.org/2000/09/xmldsig#base64":
188                                                         t = new XmlDsigBase64Transform ();
189                                                         break;
190                                                 case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315":
191                                                         t = new XmlDsigC14NTransform ();
192                                                         break;
193                                                 case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments":
194                                                         t = new XmlDsigC14NWithCommentsTransform ();
195                                                         break;
196                                                 case "http://www.w3.org/2000/09/xmldsig#enveloped-signature":
197                                                         t = new XmlDsigEnvelopedSignatureTransform ();
198                                                         break;
199                                                 case "http://www.w3.org/TR/1999/REC-xpath-19991116":
200                                                         t = new XmlDsigXPathTransform ();
201                                                         break;
202                                                 case "http://www.w3.org/TR/1999/REC-xslt-19991116":
203                                                         t = new XmlDsigXsltTransform ();
204                                                         break;
205                                                 case "http://www.w3.org/2002/07/decrypt#XML":
206                                                         t = new XmlDecryptionTransform ();
207                                                         break;
208                                                 default:
209                                                         throw new NotSupportedException ();
210                                         }
211 */
212                                         t = (Transform) CryptoConfig.CreateFromName (a);
213                                         if (t == null)
214                                                 throw new CryptographicException ("Unknown transform {0}.", a);
215
216                                         if (xn.ChildNodes.Count > 0) {
217                                                 t.LoadInnerXml (xn.ChildNodes);
218                                         }
219                                         AddTransform (t);
220                                 }
221                         }
222                         // get DigestMethod
223                         DigestMethod = XmlSignature.GetAttributeFromElement (value, XmlSignature.AttributeNames.Algorithm, XmlSignature.ElementNames.DigestMethod);
224                         // get DigestValue
225                         XmlElement dig = XmlSignature.GetChildElement (value, XmlSignature.ElementNames.DigestValue, XmlSignature.NamespaceURI);
226                         if (dig != null)
227                                 DigestValue = Convert.FromBase64String (dig.InnerText);
228                         element = value;
229                 }
230         }
231 }