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