New tests.
[mono.git] / mcs / class / corlib / System.Security.Policy / Evidence.cs
index b3c2721a76f71254b100db190fc818a8d28d9b0a..5d932f5259d0fec1b475152154acaa88b9129246 100644 (file)
@@ -5,14 +5,11 @@
 //     Sean MacIsaac (macisaac@ximian.com)
 //     Nick Drochak (ndrochak@gol.com)
 //     Jackson Harper (Jackson@LatitudeGeo.com)
-//     Sebastien Pouliot (spouliot@motus.com)
+//     Sebastien Pouliot  <sebastien@ximian.com>
 //
 // (C) 2001 Ximian, Inc.
 // Portions (C) 2003, 2004 Motus Technologies Inc. (http://www.motus.com)
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// 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
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.Collections;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Security.Permissions;
+using System.Security.Cryptography.X509Certificates;
+
+#if !MOONLIGHT
+using Mono.Security.Authenticode;
+#endif
 
 namespace System.Security.Policy {
 
        [Serializable]
-       [MonoTODO ("Fix serialization compatibility with MS.NET")]
+       [MonoTODO ("Serialization format not compatible with .NET")]
+       [ComVisible (true)]
        public sealed class Evidence : ICollection, IEnumerable {
        
                private bool _locked;
                private ArrayList hostEvidenceList;     
                private ArrayList assemblyEvidenceList;
-               
+               private int _hashCode;
+
                public Evidence () 
                {
-                       hostEvidenceList = ArrayList.Synchronized (new ArrayList ());
-                       assemblyEvidenceList = ArrayList.Synchronized (new ArrayList ());
                }
 
-               public Evidence (Evidence evidence) : this ()
+               public Evidence (Evidence evidence)
                {
                        if (evidence != null)
                                Merge (evidence);       
                }
 
-               public Evidence (object[] hostEvidence, object[] assemblyEvidence) : this ()
+#if NET_4_0
+               [Obsolete]
+#endif
+               public Evidence (object[] hostEvidence, object[] assemblyEvidence)
                {
                        if (null != hostEvidence)
-                               hostEvidenceList.AddRange (hostEvidence);
+                               HostEvidenceList.AddRange (hostEvidence);
                        if (null != assemblyEvidence)
-                               assemblyEvidenceList.AddRange (assemblyEvidence);
+                               AssemblyEvidenceList.AddRange (assemblyEvidence);
                }
                
                //
                // Public Properties
                //
        
+#if NET_4_0
+               [Obsolete]
+#endif
                public int Count {
                        get {
-                               return (hostEvidenceList.Count + assemblyEvidenceList.Count);
+                               int count = 0;
+                               if (hostEvidenceList != null)
+                                       count += hostEvidenceList.Count;
+                               if (assemblyEvidenceList!= null)
+                                       count += assemblyEvidenceList.Count;
+                               return count;
                        }
                }
 
@@ -82,15 +98,14 @@ namespace System.Security.Policy {
                        get{ return false; }
                }
                
-               // LAMESPEC: Always TRUE (not FALSE)
                public bool IsSynchronized {
-                       get { return true; }
+                       get { return false; }
                }
 
                public bool Locked {
                        get { return _locked; }
+                       [SecurityPermission (SecurityAction.Demand, ControlEvidence = true)]
                        set { 
-                               new SecurityPermission (SecurityPermissionFlag.ControlEvidence).Demand ();
                                _locked = value; 
                        }
                }       
@@ -99,62 +114,253 @@ namespace System.Security.Policy {
                        get { return this; }
                }
 
+               internal ArrayList HostEvidenceList {
+                       get {
+                               if (hostEvidenceList == null)
+                                       hostEvidenceList = ArrayList.Synchronized (new ArrayList ());
+                               return hostEvidenceList;
+                       }
+               }
+
+               internal ArrayList AssemblyEvidenceList {
+                       get {
+                               if (assemblyEvidenceList == null)
+                                       assemblyEvidenceList = ArrayList.Synchronized (new ArrayList ());
+                               return assemblyEvidenceList;
+                       }
+               }
+
                //
                // Public Methods
                //
 
+#if NET_4_0
+               [Obsolete]
+#endif
                public void AddAssembly (object id) 
                {
-                       assemblyEvidenceList.Add (id);
+                       AssemblyEvidenceList.Add (id);
+                       _hashCode = 0;
                }
 
+#if NET_4_0
+               [Obsolete]
+#endif
                public void AddHost (object id) 
                {
-                       if (_locked) {
+                       if (_locked && SecurityManager.SecurityEnabled) {
                                new SecurityPermission (SecurityPermissionFlag.ControlEvidence).Demand ();
                        }
-                       hostEvidenceList.Add (id);
+                       HostEvidenceList.Add (id);
+                       _hashCode = 0;
+               }
+
+               [ComVisible (false)]
+               public void Clear ()
+               {
+                       if (hostEvidenceList != null)
+                               hostEvidenceList.Clear ();
+                       if (assemblyEvidenceList != null)
+                               assemblyEvidenceList.Clear ();
+                       _hashCode = 0;
                }
 
+#if NET_4_0
+               [Obsolete]
+#endif
                public void CopyTo (Array array, int index) 
                {
-                       if (hostEvidenceList.Count > 0) 
-                               hostEvidenceList.CopyTo (array, index);
-                       if (assemblyEvidenceList.Count > 0) 
-                               assemblyEvidenceList.CopyTo (array, index + hostEvidenceList.Count);
+                       int hc = 0;
+                       if (hostEvidenceList != null) {
+                               hc = hostEvidenceList.Count;
+                               if (hc > 0)
+                                       hostEvidenceList.CopyTo (array, index);
+                       }
+                       if ((assemblyEvidenceList != null) && (assemblyEvidenceList.Count > 0))
+                               assemblyEvidenceList.CopyTo (array, index + hc);
                }
 
+               [ComVisible (false)]
+               public override bool Equals (object obj)
+               {
+                       if (obj == null)
+                               return false;
+                       Evidence e = (obj as Evidence);
+                       if (e == null)
+                               return false;
+
+                       if (HostEvidenceList.Count != e.HostEvidenceList.Count)
+                               return false;
+                       if (AssemblyEvidenceList.Count != e.AssemblyEvidenceList.Count)
+                               return false;
+
+                       for (int i = 0; i < hostEvidenceList.Count; i++) {
+                               bool found = false;
+                               for (int j = 0; j < e.hostEvidenceList.Count; i++) {
+                                       if (hostEvidenceList [i].Equals (e.hostEvidenceList [j])) {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               if (!found)
+                                       return false;
+                       }
+                       for (int i = 0; i < assemblyEvidenceList.Count; i++) {
+                               bool found = false;
+                               for (int j = 0; j < e.assemblyEvidenceList.Count; i++) {
+                                       if (assemblyEvidenceList [i].Equals (e.assemblyEvidenceList [j])) {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               if (!found)
+                                       return false;
+                       }
+                       
+                       return true;
+               }
+
+#if NET_4_0
+               [Obsolete]
+#endif
                public IEnumerator GetEnumerator () 
                {
-                       return new EvidenceEnumerator (hostEvidenceList.GetEnumerator (), 
-                               assemblyEvidenceList.GetEnumerator ());
+                       IEnumerator he = null;
+                       if (hostEvidenceList != null)
+                               he = hostEvidenceList.GetEnumerator ();
+                       IEnumerator ae = null;
+                       if (assemblyEvidenceList != null)
+                               ae = assemblyEvidenceList.GetEnumerator ();
+                       return new EvidenceEnumerator (he, ae);
                }
 
                public IEnumerator GetAssemblyEnumerator () 
                {
-                       return assemblyEvidenceList.GetEnumerator ();
+                       return AssemblyEvidenceList.GetEnumerator ();
+               }
+
+               [ComVisible (false)]
+               public override int GetHashCode ()
+               {
+                       // kind of long so we cache it
+                       if (_hashCode == 0) {
+                               if (hostEvidenceList != null) {
+                                       for (int i = 0; i < hostEvidenceList.Count; i++)
+                                               _hashCode ^= hostEvidenceList [i].GetHashCode ();
+                               }
+                               if (assemblyEvidenceList != null) {
+                                       for (int i = 0; i < assemblyEvidenceList.Count; i++)
+                                               _hashCode ^= assemblyEvidenceList [i].GetHashCode ();
+                               }
+                       }
+                       return _hashCode;
                }
 
                public IEnumerator GetHostEnumerator () 
                {
-                       return hostEvidenceList.GetEnumerator ();
+                       return HostEvidenceList.GetEnumerator ();
                }
 
                public void Merge (Evidence evidence) 
                {
-                       IEnumerator hostenum, assemblyenum;
-                       
-                       hostenum = evidence.GetHostEnumerator ();
-                       while( hostenum.MoveNext () ) {
-                               AddHost (hostenum.Current);
+                       if ((evidence != null) && (evidence.Count > 0)) {
+                               if (evidence.hostEvidenceList != null) {
+                                       foreach (object o in evidence.hostEvidenceList)
+                                               AddHost (o);
+                               }
+                               if (evidence.assemblyEvidenceList != null) {
+                                       foreach (object o in evidence.assemblyEvidenceList)
+                                               AddAssembly (o);
+                               }
+                               _hashCode = 0;
                        }
+               }
 
-                       assemblyenum = evidence.GetAssemblyEnumerator ();
-                       while( assemblyenum.MoveNext () ) {
-                               AddAssembly (assemblyenum.Current);
+               [ComVisible (false)]
+               public void RemoveType (Type t)
+               {
+                       for (int i = hostEvidenceList.Count; i >= 0; i--) {
+                               if (hostEvidenceList.GetType () == t) {
+                                       hostEvidenceList.RemoveAt (i);
+                                       _hashCode = 0;
+                               }
+                       }
+                       for (int i = assemblyEvidenceList.Count; i >= 0; i--) {
+                               if (assemblyEvidenceList.GetType () == t) {
+                                       assemblyEvidenceList.RemoveAt (i);
+                                       _hashCode = 0;
+                               }
                        }
                }
-       
+
+               // Use an icall to avoid multiple file i/o to detect the 
+               // "possible" presence of an Authenticode signature
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               static extern bool IsAuthenticodePresent (Assembly a);
+#if NET_2_1
+               static internal Evidence GetDefaultHostEvidence (Assembly a)
+               {
+                       return new Evidence ();
+               }
+#else
+               // this avoid us to build all evidences from the runtime
+               // (i.e. multiple unmanaged->managed calls) and also allows
+               // to delay their creation until (if) needed
+               [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
+               static internal Evidence GetDefaultHostEvidence (Assembly a) 
+               {
+                       Evidence e = new Evidence ();
+                       string aname = a.EscapedCodeBase;
+
+                       // by default all assembly have the Zone, Url and Hash evidences
+                       e.AddHost (Zone.CreateFromUrl (aname));
+                       e.AddHost (new Url (aname));
+                       e.AddHost (new Hash (a));
+
+                       // non local files (e.g. http://) also get a Site evidence
+                       if (String.Compare ("FILE://", 0, aname, 0, 7, true, CultureInfo.InvariantCulture) != 0) {
+                               e.AddHost (Site.CreateFromUrl (aname));
+                       }
+
+                       // strongnamed assemblies gets a StrongName evidence
+                       AssemblyName an = a.UnprotectedGetName ();
+                       byte[] pk = an.GetPublicKey ();
+                       if ((pk != null) && (pk.Length > 0)) {
+                               StrongNamePublicKeyBlob blob = new StrongNamePublicKeyBlob (pk);
+                               e.AddHost (new StrongName (blob, an.Name, an.Version));
+                       }
+
+                       // Authenticode(r) signed assemblies get a Publisher evidence
+                       if (IsAuthenticodePresent (a)) {
+                               // Note: The certificate is part of the evidences even if it is not trusted!
+                               // so we can't call X509Certificate.CreateFromSignedFile
+                               AuthenticodeDeformatter ad = new AuthenticodeDeformatter (a.Location);
+                               if (ad.SigningCertificate != null) {
+                                       X509Certificate x509 = new X509Certificate (ad.SigningCertificate.RawData);
+                                       if (x509.GetHashCode () != 0) {
+                                               e.AddHost (new Publisher (x509));
+                                       }
+                               }
+                       }
+                       // assemblies loaded from the GAC also get a Gac evidence (new in Fx 2.0)
+                       if (a.GlobalAssemblyCache) {
+                               e.AddHost (new GacInstalled ());
+                       }
+
+                       // the current HostSecurityManager may add/remove some evidence
+                       AppDomainManager dommgr = AppDomain.CurrentDomain.DomainManager;
+                       if (dommgr != null) {
+                               if ((dommgr.HostSecurityManager.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) ==
+                                       HostSecurityManagerOptions.HostAssemblyEvidence) {
+                                       e = dommgr.HostSecurityManager.ProvideAssemblyEvidence (a, e);
+                               }
+                       }
+
+                       return e;
+               }
+
+#endif // NET_2_1
+
                private class EvidenceEnumerator : IEnumerator {
                        
                        private IEnumerator currentEnum, hostEnum, assemblyEnum;                
@@ -163,14 +369,17 @@ namespace System.Security.Policy {
                        {
                                this.hostEnum = hostenum;
                                this.assemblyEnum = assemblyenum;
-                               currentEnum = hostEnum;                 
+                               currentEnum = hostEnum;         
                        }
 
                        public bool MoveNext () 
                        {
+                               if (currentEnum == null)
+                                       return false;
+
                                bool ret = currentEnum.MoveNext ();
                                
-                               if ( !ret && hostEnum == currentEnum ) {
+                               if (!ret && (hostEnum == currentEnum) && (assemblyEnum != null)) {
                                        currentEnum = assemblyEnum;
                                        ret = assemblyEnum.MoveNext ();
                                }
@@ -180,9 +389,14 @@ namespace System.Security.Policy {
 
                        public void Reset () 
                        {
-                               hostEnum.Reset ();
-                               assemblyEnum.Reset ();
-                               currentEnum = hostEnum;
+                               if (hostEnum != null) {
+                                       hostEnum.Reset ();
+                                       currentEnum = hostEnum;
+                               } else {
+                                       currentEnum = assemblyEnum;
+                               }
+                               if (assemblyEnum != null)
+                                       assemblyEnum.Reset ();
                        }
 
                        public object Current {