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