New test.
[mono.git] / mcs / class / System.Security / System.Security.Cryptography.Xml / SignedXml.cs
index 3efcd5efef0a2ff356fd29c143f7686b6d02fbb7..4d30baa407f58959b45003717ba4fc06b8704c5f 100644 (file)
@@ -4,11 +4,11 @@
 // Author:
 //     Sebastien Pouliot  <sebastien@ximian.com>
 //     Atsushi Enomoto <atsushi@ximian.com>
+//      Tim Coleman <tim@timcoleman.com>
 //
 // (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
-//
-
+// Copyright (C) Tim Coleman, 2004
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -39,10 +39,38 @@ using System.Net;
 using System.Text;
 using System.Xml;
 
+#if NET_2_0
+using System.Security.Cryptography.X509Certificates;
+#endif
+
 namespace System.Security.Cryptography.Xml {
 
        public class SignedXml {
 
+               public const string XmlDsigCanonicalizationUrl                  = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
+               public const string XmlDsigCanonicalizationWithCommentsUrl      = XmlDsigCanonicalizationUrl + "#WithComments";
+               public const string XmlDsigDSAUrl                               = XmlDsigNamespaceUrl + "dsa-sha1";
+               public const string XmlDsigHMACSHA1Url                          = XmlDsigNamespaceUrl + "hmac-sha1";
+               public const string XmlDsigMinimalCanonicalizationUrl           = XmlDsigNamespaceUrl + "minimal";
+               public const string XmlDsigNamespaceUrl                         = "http://www.w3.org/2000/09/xmldsig#";
+               public const string XmlDsigRSASHA1Url                           = XmlDsigNamespaceUrl + "rsa-sha1";
+               public const string XmlDsigSHA1Url                              = XmlDsigNamespaceUrl + "sha1";
+
+#if NET_2_0
+               public const string XmlDecryptionTransformUrl                   = "http://www.w3.org/2002/07/decrypt#XML";
+               public const string XmlDsigBase64TransformUrl                   = XmlDsigNamespaceUrl + "base64";
+               public const string XmlDsigC14NTransformUrl                     = XmlDsigCanonicalizationUrl;
+               public const string XmlDsigC14NWithCommentsTransformUrl         = XmlDsigCanonicalizationWithCommentsUrl;
+               public const string XmlDsigEnvelopedSignatureTransformUrl       = XmlDsigNamespaceUrl + "enveloped-signature";
+               public const string XmlDsigExcC14NTransformUrl                  = "http://www.w3.org/2001/10/xml-exc-c14n#";
+               public const string XmlDsigExcC14NWithCommentsTransformUrl      = XmlDsigExcC14NTransformUrl + "WithComments";
+               public const string XmlDsigXPathTransformUrl                    = "http://www.w3.org/TR/1999/REC-xpath-19991116";
+               public const string XmlDsigXsltTransformUrl                     = "http://www.w3.org/TR/1999/REC-xslt-19991116";
+               public const string XmlLicenseTransformUrl                      = "urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform";
+
+               private EncryptedXml encryptedXml;
+#endif
+
                protected Signature m_signature;
                private AsymmetricAlgorithm key;
                protected string m_strSigningKeyName;
@@ -57,7 +85,10 @@ namespace System.Security.Cryptography.Xml {
                private XmlResolver xmlResolver = new XmlUrlResolver ();
 #endif
                private ArrayList manifests;
-               
+#if NET_2_0
+               private IEnumerator _x509Enumerator;
+#endif
+
                private static readonly char [] whitespaceChars = new char [] {' ', '\r', '\n', '\t'};
 
                public SignedXml () 
@@ -82,17 +113,22 @@ namespace System.Security.Cryptography.Xml {
                        envdoc.LoadXml (elem.OuterXml);
                }
 
-               public const string XmlDsigCanonicalizationUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
-               public const string XmlDsigCanonicalizationWithCommentsUrl = XmlDsigCanonicalizationUrl + "#WithComments";
-               public const string XmlDsigNamespaceUrl = "http://www.w3.org/2000/09/xmldsig#";
-               public const string XmlDsigDSAUrl = XmlDsigNamespaceUrl + "dsa-sha1";
-               public const string XmlDsigHMACSHA1Url = XmlDsigNamespaceUrl + "hmac-sha1";
-               public const string XmlDsigMinimalCanonicalizationUrl = XmlDsigNamespaceUrl + "minimal";
-               public const string XmlDsigRSASHA1Url = XmlDsigNamespaceUrl + "rsa-sha1";
-               public const string XmlDsigSHA1Url = XmlDsigNamespaceUrl + "sha1";
+#if NET_2_0
+               [ComVisible (false)]
+               public EncryptedXml EncryptedXml {
+                       get { return encryptedXml; }
+                       set { encryptedXml = value; }
+               }
+#endif
 
                public KeyInfo KeyInfo {
-                       get { return m_signature.KeyInfo; }
+                       get {
+#if NET_2_0
+                               if (m_signature.KeyInfo == null)
+                                       m_signature.KeyInfo = new KeyInfo ();
+#endif
+                               return m_signature.KeyInfo;
+                       }
                        set { m_signature.KeyInfo = value; }
                }
 
@@ -134,6 +170,10 @@ namespace System.Security.Cryptography.Xml {
 
                public void AddReference (Reference reference) 
                {
+#if NET_2_0
+                       if (reference == null)
+                               throw new ArgumentNullException ("reference");
+#endif
                        m_signature.SignedInfo.AddReference (reference);
                }
 
@@ -141,8 +181,12 @@ namespace System.Security.Cryptography.Xml {
                {
                        // These transformer modify input document, which should
                        // not affect to the input itself.
-                       if (t is XmlDsigXPathTransform ||
-                               t is XmlDsigEnvelopedSignatureTransform)
+                       if (t is XmlDsigXPathTransform 
+                               || t is XmlDsigEnvelopedSignatureTransform
+#if NET_2_0
+                               || t is XmlDecryptionTransform
+#endif
+                       )
                                input = (XmlDocument) input.Clone ();
 
                        t.LoadInput (input);
@@ -158,6 +202,11 @@ namespace System.Security.Cryptography.Xml {
                                MemoryStream ms = new MemoryStream ();
                                XmlTextWriter xtw = new XmlTextWriter (ms, Encoding.UTF8);
                                ((XmlDocument) obj).WriteTo (xtw);
+
+                               xtw.Flush ();
+
+                               // Rewind to the start of the stream
+                               ms.Position = 0;
                                return ms;
                        }
                        else if (obj == null) {
@@ -257,7 +306,7 @@ namespace System.Security.Cryptography.Xml {
                                        try {
                                                // no way to know if valid without throwing an exception
                                                Uri uri = new Uri (r.Uri);
-                                               s = (Stream) xmlResolver.GetEntity (new Uri (r.Uri), null, typeof (Stream));
+                                               s = (Stream) xmlResolver.GetEntity (uri, null, typeof (Stream));
                                        }
                                        catch {
                                                // may still be a local file (and maybe not xml)
@@ -436,10 +485,14 @@ namespace System.Security.Cryptography.Xml {
                                // check with supplied key
                                if (!CheckSignatureWithKey (key))
                                        return null;
-                       }
-                       else {
+                       } else {
+#if NET_2_0
+                               if (Signature.KeyInfo == null)
+                                       return null;
+#else
                                if (Signature.KeyInfo == null)
                                        throw new CryptographicException ("At least one KeyInfo is required.");
+#endif
                                // no supplied key, iterates all KeyInfo
                                while ((key = GetPublicKey ()) != null) {
                                        if (CheckSignatureWithKey (key)) {
@@ -552,6 +605,15 @@ namespace System.Security.Cryptography.Xml {
                        return false;
                }
 
+#if NET_2_0
+               [MonoTODO]
+               [ComVisible (false)]
+               public bool CheckSignature (X509Certificate2 certificate, bool verifySignatureOnly)
+               {
+                       throw new NotImplementedException ();
+               }
+#endif
+
                public bool CheckSignatureReturningKey (out AsymmetricAlgorithm signingKey) 
                {
                        signingKey = CheckSignatureInternal (null);
@@ -621,8 +683,18 @@ namespace System.Security.Cryptography.Xml {
                        if (pkEnumerator == null) {
                                pkEnumerator = m_signature.KeyInfo.GetEnumerator ();
                        }
-
-                       if (pkEnumerator.MoveNext ()) {
+                       
+#if NET_2_0
+                       if (_x509Enumerator != null) {
+                               if (_x509Enumerator.MoveNext ()) {
+                                       X509Certificate cert = (X509Certificate) _x509Enumerator.Current;
+                                       return new X509Certificate2 (cert.GetRawCertData ()).PublicKey.Key;
+                               } else {
+                                       _x509Enumerator = null;
+                               }
+                       }
+#endif
+                       while (pkEnumerator.MoveNext ()) {
                                AsymmetricAlgorithm key = null;
                                KeyInfoClause kic = (KeyInfoClause) pkEnumerator.Current;
 
@@ -635,13 +707,23 @@ namespace System.Security.Cryptography.Xml {
                                        key.FromXmlString (kic.GetXml ().InnerXml);
                                        return key;
                                }
+
+#if NET_2_0
+                               if (kic is KeyInfoX509Data) {
+                                       _x509Enumerator = ((KeyInfoX509Data) kic).Certificates.GetEnumerator ();
+                                       if (_x509Enumerator.MoveNext ()) {
+                                               X509Certificate cert = (X509Certificate) _x509Enumerator.Current;
+                                               return new X509Certificate2 (cert.GetRawCertData ()).PublicKey.Key;
+                                       }
+                               }
+#endif
                        }
                        return null;
                }
 
                public XmlElement GetXml () 
                {
-                       return m_signature.GetXml ();
+                       return m_signature.GetXml (envdoc);
                }
 
                public void LoadXml (XmlElement value) 
@@ -651,6 +733,17 @@ namespace System.Security.Cryptography.Xml {
 
                        signatureElement = value;
                        m_signature.LoadXml (value);
+#if NET_2_0
+                       // Need to give the EncryptedXml object to the 
+                       // XmlDecryptionTransform to give it a fighting 
+                       // chance at decrypting the document.
+                       foreach (Reference r in m_signature.SignedInfo.References) {
+                               foreach (Transform t in r.TransformChain) {
+                                       if (t is XmlDecryptionTransform) 
+                                               ((XmlDecryptionTransform) t).EncryptedXml = EncryptedXml;
+                               }
+                       }
+#endif
                }
 
 #if NET_1_1