2 // xmldsig.cs: XML Digital Signature Tests
5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Sebastien Pouliot <sebastien@ximian.com>
8 // (C) 2004 Novell (http://www.novell.com)
12 using System.Collections;
14 using System.Reflection;
15 using System.Runtime.InteropServices;
16 using System.Security.Cryptography;
17 using System.Security.Cryptography.X509Certificates;
18 using System.Security.Cryptography.Xml;
23 using Mono.Security.X509;
25 public class MyClass {
27 static int invalid = 0;
34 static bool useDecentReader;
36 public static void Main(string [] args)
38 foreach (string arg in args)
39 if (arg == "--decent-reader")
40 useDecentReader = true;
42 // automagically ajust tests to run depending on system config
43 exc14n = (CryptoConfig.CreateFromName ("http://www.w3.org/2001/10/xml-exc-c14n#WithComments") != null);
44 hmacmd5 = (CryptoConfig.CreateFromName ("HMACMD5") != null);
46 Console.WriteLine ("MERLIN");
49 // Non working on MS runtime;
50 // they have insufficient support for namespaces.
51 Console.WriteLine ("PHAOS");
54 catch (Exception ex) {
55 Console.WriteLine (ex);
59 Console.WriteLine ("TOTAL VALID {0}", valid);
60 Console.WriteLine ("TOTAL INVALID {0}", invalid);
61 Console.WriteLine ("TOTAL ERROR {0}", error);
62 Console.WriteLine ("TOTAL SKIP {0}", skip);
64 Console.WriteLine ("Finished.");
68 static Mono.Security.X509.X509Certificate LoadCertificate (string filename)
70 Mono.Security.X509.X509Certificate mx = null;
71 if (File.Exists (filename)) {
72 using (FileStream fs = File.OpenRead (filename)) {
73 byte[] data = new byte [fs.Length];
74 fs.Read (data, 0, data.Length);
75 mx = new Mono.Security.X509.X509Certificate (data);
81 static string GetPath (string dir, string name)
83 string path = Path.GetDirectoryName (dir);
84 path = Path.Combine (path, "certs");
85 path = Path.Combine (path, name);
89 static TextReader GetReader (string filename)
91 XmlResolver resolver = new XmlUrlResolver ();
92 Stream stream = resolver.GetEntity (resolver.ResolveUri (null, filename), null, typeof (Stream)) as Stream;
94 return new XmlSignatureStreamReader (
95 new StreamReader (stream));
97 return new StreamReader (stream);
100 static void Symmetric (string filename, byte[] key)
102 string shortName = Path.GetFileName (filename);
104 XmlDocument doc = new XmlDocument ();
105 doc.PreserveWhitespace = true;
106 XmlTextReader xtr = new XmlTextReader (GetReader (filename));
107 XmlValidatingReader xvr = new XmlValidatingReader (xtr);
108 xtr.Normalization = true;
112 XmlNodeList nodeList = doc.GetElementsByTagName ("Signature", SignedXml.XmlDsigNamespaceUrl);
113 XmlElement signature = (XmlElement) nodeList [0];
115 SignedXml s = new SignedXml ();
116 s.LoadXml (signature);
118 HMACSHA1 mac = new HMACSHA1 (key);
119 if (s.CheckSignature (mac)) {
120 Console.WriteLine ("valid {0}", shortName);
124 Console.WriteLine ("INVALID {0}", shortName);
128 catch (Exception ex) {
129 Console.WriteLine ("EXCEPTION " + shortName + " " + ex);
134 static void Asymmetric (string filename)
136 string shortName = Path.GetFileName (filename);
138 XmlDocument doc = new XmlDocument ();
139 XmlTextReader xtr = new XmlTextReader (GetReader (filename));
140 XmlValidatingReader xvr = new XmlValidatingReader (xtr);
141 xtr.Normalization = true;
142 doc.PreserveWhitespace = true;
147 if (filename.IndexOf ("enveloped") >= 0)
148 s = new SignedXml (doc);
149 else if (filename.IndexOf ("signature-big") >= 0)
150 s = new SignedXml (doc);
152 s = new SignedXml ();
154 XmlNodeList nodeList = doc.GetElementsByTagName ("Signature", "http://www.w3.org/2000/09/xmldsig#");
155 s.LoadXml ((XmlElement) nodeList [0]);
157 #if false // wanna dump?
158 Console.WriteLine ("\n\nFilename : " + fi.Name);
161 // MS doesn't extract the public key out of the certificates
162 // http://www.dotnet247.com/247reference/a.aspx?u=http://www.kbalertz.com/Feedback_320602.aspx
163 Mono.Security.X509.X509Certificate mx = null;
164 foreach (KeyInfoClause kic in s.KeyInfo) {
165 if (kic is KeyInfoX509Data) {
166 KeyInfoX509Data kix = (kic as KeyInfoX509Data);
167 if ((kix.Certificates != null) && (kix.Certificates.Count > 0)) {
168 System.Security.Cryptography.X509Certificates.X509Certificate x509 = (System.Security.Cryptography.X509Certificates.X509Certificate) kix.Certificates [0];
169 byte[] data = x509.GetRawCertData ();
170 mx = new Mono.Security.X509.X509Certificate (data);
176 // 1- Merlin's certificate resolution (manual)
177 // 2- Phaos (because Fx doesn't support RetrievalMethod
179 case "signature-keyname.xml":
180 mx = LoadCertificate (GetPath (filename, "lugh.crt"));
182 case "signature-retrievalmethod-rawx509crt.xml":
183 mx = LoadCertificate (GetPath (filename, "balor.crt"));
185 case "signature-x509-is.xml":
186 mx = LoadCertificate (GetPath (filename, "macha.crt"));
188 case "signature-x509-ski.xml":
189 mx = LoadCertificate (GetPath (filename, "nemain.crt"));
191 case "signature-x509-sn.xml":
192 mx = LoadCertificate (GetPath (filename, "badb.crt"));
195 case "signature-big.xml":
196 case "signature-rsa-manifest-x509-data-issuer-serial.xml":
197 case "signature-rsa-manifest-x509-data-ski.xml":
198 case "signature-rsa-manifest-x509-data-subject-name.xml":
199 case "signature-rsa-detached-xslt-transform-retrieval-method.xml":
200 mx = LoadCertificate (GetPath (filename, "rsa-cert.der"));
202 case "signature-rsa-detached-xslt-transform-bad-retrieval-method.xml":
203 mx = LoadCertificate (GetPath (filename, "dsa-ca-cert.der"));
211 if (mx.RSA != null) {
212 result = s.CheckSignature (mx.RSA);
214 else if (mx.DSA != null) {
215 result = s.CheckSignature (mx.DSA);
219 // use a key existing in the document
220 result = s.CheckSignature ();
224 Console.WriteLine ("valid " + shortName);
228 Console.WriteLine ("INVALID {0}", shortName);
232 catch (Exception ex) {
233 Console.WriteLine ("EXCEPTION " + shortName + " " + ex);
238 static void Merlin ()
241 byte[] key = Encoding.ASCII.GetBytes ("secret");
243 foreach (FileInfo fi in new DirectoryInfo ("merlin-xmldsig-twenty-three").GetFiles ("signature-*.xml")) {
244 if (fi.Name.IndexOf ("hmac") >= 0) {
245 Symmetric (fi.FullName, key);
248 Asymmetric (fi.FullName);
256 byte[] key = Encoding.ASCII.GetBytes ("test");
258 // some documents references other documents in the directory
259 Directory.SetCurrentDirectory ("phaos-xmldsig-three");
260 foreach (FileInfo fi in new DirectoryInfo (".").GetFiles ("signature-*.xml")) {
261 if ((fi.Name.IndexOf ("md5") >= 0) && (!hmacmd5)) {
262 Console.WriteLine ("NOT RUN: " + fi.Name + " : System.Security.dll doesn't support HMAC-MD5.");
266 if (fi.Name.IndexOf ("hmac") >= 0) {
267 Symmetric (fi.FullName, key);
270 Asymmetric (fi.FullName);
273 // return home before next tests
274 Directory.SetCurrentDirectory ("..");
277 // dump methods under construction ;-)
279 static void DumpSignedXml (SignedXml s)
281 Console.WriteLine ("*** SignedXml ***");
282 Console.WriteLine (s.SigningKeyName);
283 Console.WriteLine (s.SigningKey);
284 if (s.Signature != null)
285 DumpSignature (s.Signature);
286 if (s.SignedInfo != null)
287 DumpSignedInfo (s.SignedInfo);
288 Console.WriteLine (s.SignatureMethod);
289 Console.WriteLine (s.SignatureLength);
290 Console.WriteLine (s.SignatureValue);
291 if (s.KeyInfo != null)
292 DumpKeyInfo (s.KeyInfo);
295 static void DumpSignature (Signature s)
297 Console.WriteLine ("*** Signature ***");
298 Console.WriteLine ("Id: " + s.Id);
299 if (s.KeyInfo != null)
300 DumpKeyInfo (s.KeyInfo);
301 Console.WriteLine ("ObjectList: " + s.ObjectList);
302 Console.WriteLine ("SignatureValue: " + s.SignatureValue);
303 if (s.SignedInfo != null)
304 DumpSignedInfo (s.SignedInfo);
307 static void DumpSignedInfo (SignedInfo s)
309 Console.WriteLine ("*** SignedInfo ***");
310 Console.WriteLine ("CanonicalizationMethod: " + s.CanonicalizationMethod);
311 Console.WriteLine ("Id: " + s.Id);
312 Console.WriteLine ("References: " + s.References);
313 Console.WriteLine ("SignatureLength: " + s.SignatureLength);
314 Console.WriteLine ("SignatureMethod: " + s.SignatureMethod);
317 static void DumpKeyInfo (KeyInfo ki)
319 Console.WriteLine ("*** KeyInfo ***" + ki);
320 Console.WriteLine ("Id: " + ki.Id);
321 Console.WriteLine ("Count: " + ki.Count);
322 foreach (KeyInfoClause kic in ki)
323 DumpKeyInfoClause (kic);
326 static void DumpKeyInfoClause (KeyInfoClause kic)
328 KeyInfoName kn = kic as KeyInfoName;
330 Console.WriteLine ("*** KeyInfoName ***");
331 Console.WriteLine ("Value: " + kn.Value);
334 KeyInfoX509Data k509 = kic as KeyInfoX509Data;
336 Console.WriteLine ("*** KeyInfoX509Data ***");
337 Console.WriteLine ("Certificates : " + k509.Certificates);
338 Console.WriteLine ("CRL : " + k509.CRL);
339 Console.WriteLine ("IssuerSerials : " + k509.IssuerSerials);
340 Console.WriteLine ("SubjectKeyIds : " + k509.SubjectKeyIds);
341 Console.WriteLine ("SubjectNames : " + k509.SubjectNames);
347 class MySignedXml : SignedXml
349 public void TestKey ()
351 Console.WriteLine (GetPublicKey () == null);
355 // below is a copy from our System.Security.dll source.
356 internal class XmlSignatureStreamReader : TextReader
359 int cache = int.MinValue;
361 public XmlSignatureStreamReader (TextReader input)
366 public override void Close ()
371 public override int Peek ()
373 if (cache != int.MinValue)
375 cache = source.Read ();
378 // cache must be '\r' here.
379 if (source.Peek () != '\n')
381 // Now Peek() returns '\n', so clear cache.
382 cache = int.MinValue;
386 public override int Read ()
388 if (cache != int.MinValue) {
390 cache = int.MinValue;
393 int i = source.Read ();
396 // read one more char (after '\r')
397 cache = source.Read ();
400 cache = int.MinValue;
404 public override int ReadBlock (
405 [In, Out] char [] buffer, int index, int count)
407 char [] tmp = new char [count];
408 source.ReadBlock (tmp, 0, count);
410 for (int i = 0; i < count; j++) {
411 if (tmp [i] == '\r') {
412 if (++i < tmp.Length && tmp [i] == '\n')
413 buffer [j] = tmp [i++];
418 buffer [j] = tmp [i];
424 buffer [j++] = (char) d;
429 public override string ReadLine ()
431 return source.ReadLine ().Replace ("\r\n", "\n");
434 public override string ReadToEnd ()
436 return source.ReadToEnd ().Replace ("\r\n", "\n");