2004-05-13 Sebastien Pouliot <sebastien@ximian.com>
[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 using System.IO;
12 using System.Xml;
13
14 namespace System.Security.Cryptography.Xml { 
15
16         // http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/Overview.html#sec-Reference
17         public class Reference {
18
19                 private TransformChain chain;
20                 private string digestMethod;
21                 private byte[] digestValue;
22                 private string id;
23                 private string uri;
24                 private string type;
25                 private Stream stream;
26                 private XmlElement element;
27
28                 public Reference () 
29                 {
30                         chain = new TransformChain ();
31                         digestMethod = XmlSignature.NamespaceURI + "sha1";
32                 }
33
34                 [MonoTODO ("There is no description about how it is used.")]
35                 public Reference (Stream stream) : this () 
36                 {
37                         this.stream = stream;
38                 }
39
40                 public Reference (string uri) : this ()
41                 {
42                         this.uri = uri;
43                 }
44
45                 // default to SHA1
46                 public string DigestMethod {
47                         get { return digestMethod; }
48                         set {
49                                 element = null;
50                                 digestMethod = value;
51                         }
52                 }
53
54                 public byte[] DigestValue {
55                         get { return digestValue; }
56                         set {
57                                 element = null;
58                                 digestValue = value;
59                         }
60                 }
61
62                 public string Id {
63                         get { return id; }
64                         set {
65                                 element = null;
66                                 id = value;
67                         }
68                 }
69
70                 public TransformChain TransformChain {
71                         get { return chain; }
72                 }
73
74                 public string Type {
75                         get { return type; }
76                         set {
77                                 element = null;
78                                 type = value;
79                         }
80                 }
81
82                 public string Uri {
83                         get { return uri; }
84                         set {
85                                 element = null;
86                                 uri = value;
87                         }
88                 }
89
90                 public void AddTransform (Transform transform) 
91                 {
92                         chain.Add (transform);
93                 }
94
95                 public XmlElement GetXml () 
96                 {
97                         if (element != null)
98                                 return element;
99
100                         if (digestMethod == null)
101                                 throw new CryptographicException ("DigestMethod");
102                         if (digestValue == null)
103                                 throw new NullReferenceException ("DigestValue");
104
105                         XmlDocument document = new XmlDocument ();
106                         XmlElement xel = document.CreateElement (XmlSignature.ElementNames.Reference, XmlSignature.NamespaceURI);
107                         if (id != null)
108                                 xel.SetAttribute (XmlSignature.AttributeNames.Id, id);
109                         if (uri != null)
110                                 xel.SetAttribute (XmlSignature.AttributeNames.URI, uri);
111                         if (type != null)
112                                 xel.SetAttribute (XmlSignature.AttributeNames.Type, type);
113
114                         if (chain.Count > 0) {
115                                 XmlElement ts = document.CreateElement (XmlSignature.ElementNames.Transforms, XmlSignature.NamespaceURI);
116                                 foreach (Transform t in chain) {
117                                         XmlNode xn = t.GetXml ();
118                                         XmlNode newNode = document.ImportNode (xn, true);
119                                         ts.AppendChild (newNode);
120                                 }
121                                 xel.AppendChild (ts);
122                         }
123
124                         XmlElement dm = document.CreateElement (XmlSignature.ElementNames.DigestMethod, XmlSignature.NamespaceURI);
125                         dm.SetAttribute (XmlSignature.AttributeNames.Algorithm, digestMethod);
126                         xel.AppendChild (dm);
127
128                         XmlElement dv = document.CreateElement (XmlSignature.ElementNames.DigestValue, XmlSignature.NamespaceURI);
129                         dv.InnerText = Convert.ToBase64String (digestValue);
130                         xel.AppendChild (dv);
131
132                         return xel;
133                 }
134
135                 // note: we do NOT return null -on purpose- if attribute isn't found
136                 private string GetAttribute (XmlElement xel, string attribute) 
137                 {
138                         XmlAttribute xa = xel.Attributes [attribute];
139                         return ((xa != null) ? xa.InnerText : null);
140                 }
141
142                 public void LoadXml (XmlElement value) 
143                 {
144                         if (value == null)
145                                 throw new ArgumentNullException ("value");
146
147                         if ((value.LocalName != XmlSignature.ElementNames.Reference) || (value.NamespaceURI != XmlSignature.NamespaceURI))
148                                 throw new CryptographicException ();
149
150                         id = GetAttribute (value, XmlSignature.AttributeNames.Id);
151                         uri = GetAttribute (value, XmlSignature.AttributeNames.URI);
152                         type = GetAttribute (value, XmlSignature.AttributeNames.Type);
153                         // Note: order is important for validations
154                         XmlNodeList xnl = value.GetElementsByTagName (XmlSignature.ElementNames.Transform, XmlSignature.NamespaceURI);
155                         if ((xnl != null) && (xnl.Count > 0)) {
156                                 Transform t = null;
157                                 foreach (XmlNode xn in xnl) {
158                                         string a = GetAttribute ((XmlElement)xn, XmlSignature.AttributeNames.Algorithm);
159 /*      This code is useful for debugging in VS.NET because using CryptoConfig
160         (from MS mscorlib) would throw InvalidCastException because it's 
161         Transform would come from MS System.Security.dll not Mono's.
162                                         switch (a) {
163                                                 case "http://www.w3.org/2000/09/xmldsig#base64":
164                                                         t = new XmlDsigBase64Transform ();
165                                                         break;
166                                                 case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315":
167                                                         t = new XmlDsigC14NTransform ();
168                                                         break;
169                                                 case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments":
170                                                         t = new XmlDsigC14NWithCommentsTransform ();
171                                                         break;
172                                                 case "http://www.w3.org/2000/09/xmldsig#enveloped-signature":
173                                                         t = new XmlDsigEnvelopedSignatureTransform ();
174                                                         break;
175                                                 case "http://www.w3.org/TR/1999/REC-xpath-19991116":
176                                                         t = new XmlDsigXPathTransform ();
177                                                         break;
178                                                 case "http://www.w3.org/TR/1999/REC-xslt-19991116":
179                                                         t = new XmlDsigXsltTransform ();
180                                                         break;
181                                                 default:
182                                                         throw new NotSupportedException ();
183                                         }
184 */
185                                         t = (Transform) CryptoConfig.CreateFromName (a);
186                                         if (t == null)
187                                                 throw new CryptographicException ("Unknown transform {0}.", a);
188
189                                         if (xn.ChildNodes.Count > 0) {
190                                                 t.LoadInnerXml (xn.ChildNodes);
191                                         }
192                                         AddTransform (t);
193                                 }
194                         }
195                         // get DigestMethod
196                         DigestMethod = XmlSignature.GetAttributeFromElement (value, XmlSignature.AttributeNames.Algorithm, XmlSignature.ElementNames.DigestMethod);
197                         // get DigestValue
198                         XmlElement dig = XmlSignature.GetChildElement (value, XmlSignature.ElementNames.DigestValue, XmlSignature.NamespaceURI);
199                         if (dig != null)
200                                 DigestValue = Convert.FromBase64String (dig.InnerText);
201                         element = value;
202                 }
203         }
204 }