updating to the latest module.
[mono.git] / mcs / class / corlib / System.Security.Policy / Evidence.cs
1 //
2 // System.Security.Policy.Evidence
3 //
4 // Authors:
5 //      Sean MacIsaac (macisaac@ximian.com)
6 //      Nick Drochak (ndrochak@gol.com)
7 //      Jackson Harper (Jackson@LatitudeGeo.com)
8 //      Sebastien Pouliot  <sebastien@ximian.com>
9 //
10 // (C) 2001 Ximian, Inc.
11 // Portions (C) 2003, 2004 Motus Technologies Inc. (http://www.motus.com)
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Collections;
35 using System.Globalization;
36 using System.Reflection;
37 using System.Runtime.CompilerServices;
38 using System.Runtime.InteropServices;
39 using System.Security.Permissions;
40 using System.Security.Cryptography.X509Certificates;
41
42 using Mono.Security.Authenticode;
43
44 namespace System.Security.Policy {
45
46         [Serializable]
47         [MonoTODO ("Fix serialization compatibility with MS.NET")]
48         public sealed class Evidence : ICollection, IEnumerable {
49         
50                 private bool _locked;
51                 private ArrayList hostEvidenceList;     
52                 private ArrayList assemblyEvidenceList;
53                 private int _hashCode;
54
55                 public Evidence () 
56                 {
57                         hostEvidenceList = ArrayList.Synchronized (new ArrayList ());
58                         assemblyEvidenceList = ArrayList.Synchronized (new ArrayList ());
59                 }
60
61                 public Evidence (Evidence evidence) : this ()
62                 {
63                         if (evidence != null)
64                                 Merge (evidence);       
65                 }
66
67                 public Evidence (object[] hostEvidence, object[] assemblyEvidence) : this ()
68                 {
69                         if (null != hostEvidence)
70                                 hostEvidenceList.AddRange (hostEvidence);
71                         if (null != assemblyEvidence)
72                                 assemblyEvidenceList.AddRange (assemblyEvidence);
73                 }
74                 
75                 //
76                 // Public Properties
77                 //
78         
79                 public int Count {
80                         get {
81                                 return (hostEvidenceList.Count + assemblyEvidenceList.Count);
82                         }
83                 }
84
85                 public bool IsReadOnly {
86                         get{ return false; }
87                 }
88                 
89                 public bool IsSynchronized {
90 #if NET_2_0
91                         get { return false; }
92 #else
93                         // LAMESPEC: Always TRUE (not FALSE)
94                         get { return true; }
95 #endif
96                 }
97
98                 public bool Locked {
99                         get { return _locked; }
100                         set { 
101                                 new SecurityPermission (SecurityPermissionFlag.ControlEvidence).Demand ();
102                                 _locked = value; 
103                         }
104                 }       
105
106                 public object SyncRoot {
107                         get { return this; }
108                 }
109
110                 //
111                 // Public Methods
112                 //
113
114                 public void AddAssembly (object id) 
115                 {
116                         assemblyEvidenceList.Add (id);
117                         _hashCode = 0;
118                 }
119
120                 public void AddHost (object id) 
121                 {
122                         if (_locked) {
123                                 new SecurityPermission (SecurityPermissionFlag.ControlEvidence).Demand ();
124                         }
125                         hostEvidenceList.Add (id);
126                         _hashCode = 0;
127                 }
128
129 #if NET_2_0
130                 [ComVisible (false)]
131                 public void Clear ()
132                 {
133                         hostEvidenceList.Clear ();
134                         assemblyEvidenceList.Clear ();
135                         _hashCode = 0;
136                 }
137 #endif
138
139                 public void CopyTo (Array array, int index) 
140                 {
141                         if (hostEvidenceList.Count > 0) 
142                                 hostEvidenceList.CopyTo (array, index);
143                         if (assemblyEvidenceList.Count > 0) 
144                                 assemblyEvidenceList.CopyTo (array, index + hostEvidenceList.Count);
145                 }
146
147 #if NET_2_0
148                 [ComVisible (false)]
149                 public override bool Equals (object obj)
150                 {
151                         if (obj == null)
152                                 return false;
153                         Evidence e = (obj as Evidence);
154                         if (e == null)
155                                 return false;
156
157                         if (hostEvidenceList.Count != e.hostEvidenceList.Count)
158                                 return false;
159                         if (assemblyEvidenceList.Count != e.assemblyEvidenceList.Count)
160                                 return false;
161
162                         for (int i = 0; i < hostEvidenceList.Count; i++) {
163                                 bool found = false;
164                                 for (int j = 0; j < e.hostEvidenceList.Count; i++) {
165                                         if (hostEvidenceList [i].Equals (e.hostEvidenceList [j])) {
166                                                 found = true;
167                                                 break;
168                                         }
169                                 }
170                                 if (!found)
171                                         return false;
172                         }
173                         for (int i = 0; i < assemblyEvidenceList.Count; i++) {
174                                 bool found = false;
175                                 for (int j = 0; j < e.assemblyEvidenceList.Count; i++) {
176                                         if (assemblyEvidenceList [i].Equals (e.assemblyEvidenceList [j])) {
177                                                 found = true;
178                                                 break;
179                                         }
180                                 }
181                                 if (!found)
182                                         return false;
183                         }
184                         
185                         return true;
186                 }
187 #endif
188
189                 public IEnumerator GetEnumerator () 
190                 {
191                         return new EvidenceEnumerator (hostEvidenceList.GetEnumerator (), 
192                                 assemblyEvidenceList.GetEnumerator ());
193                 }
194
195                 public IEnumerator GetAssemblyEnumerator () 
196                 {
197                         return assemblyEvidenceList.GetEnumerator ();
198                 }
199
200 #if NET_2_0
201                 [ComVisible (false)]
202                 public override int GetHashCode ()
203                 {
204                         // kind of long so we cache it
205                         if (_hashCode == 0) {
206                                 for (int i = 0; i < hostEvidenceList.Count; i++)
207                                         _hashCode ^= hostEvidenceList [i].GetHashCode ();
208                                 for (int i = 0; i < assemblyEvidenceList.Count; i++)
209                                         _hashCode ^= assemblyEvidenceList [i].GetHashCode ();
210                         }
211                         return _hashCode;
212                 }
213 #endif
214
215                 public IEnumerator GetHostEnumerator () 
216                 {
217                         return hostEvidenceList.GetEnumerator ();
218                 }
219
220                 public void Merge (Evidence evidence) 
221                 {
222                         if ((evidence != null) && (evidence.Count > 0)) {
223                                 IEnumerator hostenum = evidence.GetHostEnumerator ();
224                                 while (hostenum.MoveNext ()) {
225                                         AddHost (hostenum.Current);
226                                 }
227
228                                 IEnumerator assemblyenum = evidence.GetAssemblyEnumerator ();
229                                 while (assemblyenum.MoveNext ()) {
230                                         AddAssembly (assemblyenum.Current);
231                                 }
232                                 _hashCode = 0;
233                         }
234                 }
235
236 #if NET_2_0
237                 [ComVisible (false)]
238                 public void RemoveType (Type t)
239                 {
240                         for (int i = hostEvidenceList.Count; i >= 0; i--) {
241                                 if (hostEvidenceList.GetType () == t) {
242                                         hostEvidenceList.RemoveAt (i);
243                                         _hashCode = 0;
244                                 }
245                         }
246                         for (int i = assemblyEvidenceList.Count; i >= 0; i--) {
247                                 if (assemblyEvidenceList.GetType () == t) {
248                                         assemblyEvidenceList.RemoveAt (i);
249                                         _hashCode = 0;
250                                 }
251                         }
252                 }
253 #endif
254
255                 // Use an icall to avoid multiple file i/o to detect the 
256                 // "possible" presence of an Authenticode signature
257                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
258                 static extern bool IsAuthenticodePresent (Assembly a);
259
260                 // this avoid us to build all evidences from the runtime
261                 // (i.e. multiple unmanaged->managed calls) and also allows
262                 // to delay their creation until (if) needed
263                 [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
264                 static internal Evidence GetDefaultHostEvidence (Assembly a) 
265                 {
266                         Evidence e = new Evidence ();
267                         string aname = a.CodeBase;
268
269                         // by default all assembly have the Zone, Url and Hash evidences
270                         e.AddHost (Zone.CreateFromUrl (aname));
271                         e.AddHost (new Url (aname));
272                         e.AddHost (new Hash (a));
273
274                         // non local files (e.g. http://) also get a Site evidence
275                         if (String.Compare ("FILE://", 0, aname, 0, 7, true, CultureInfo.InvariantCulture) != 0) {
276                                 e.AddHost (Site.CreateFromUrl (aname));
277                         }
278
279                         // strongnamed assemblies gets a StrongName evidence
280                         AssemblyName an = a.GetName ();
281                         byte[] pk = an.GetPublicKey ();
282                         if ((pk != null) && (pk.Length > 0)) {
283                                 StrongNamePublicKeyBlob blob = new StrongNamePublicKeyBlob (pk);
284                                 e.AddHost (new StrongName (blob, an.Name, an.Version));
285                         }
286
287                         // Authenticode(r) signed assemblies get a Publisher evidence
288                         if (IsAuthenticodePresent (a)) {
289                                 // Note: The certificate is part of the evidences even if it is not trusted!
290                                 // so we can't call X509Certificate.CreateFromSignedFile
291                                 AuthenticodeDeformatter ad = new AuthenticodeDeformatter (a.Location);
292                                 if (ad.SigningCertificate != null) {
293                                         X509Certificate x509 = new X509Certificate (ad.SigningCertificate.RawData);
294                                         if (x509.GetHashCode () != 0) {
295                                                 e.AddHost (new Publisher (x509));
296                                         }
297                                 }
298                         }
299 #if NET_2_0
300                         // assemblies loaded from the GAC also get a Gac evidence (new in Fx 2.0)
301                         if (a.GlobalAssemblyCache) {
302                                 e.AddHost (new Gac ());
303                         }
304
305                         // the current HostSecurityManager may add/remove some evidence
306                         AppDomainManager dommgr = AppDomain.CurrentDomain.DomainManager;
307                         if (dommgr != null) {
308                                 if ((dommgr.HostSecurityManager.Flags & HostSecurityManagerFlags.HostAssemblyEvidence) ==
309                                         HostSecurityManagerFlags.HostAssemblyEvidence) {
310                                         e = dommgr.HostSecurityManager.ProvideAssemblyEvidence (a, e);
311                                 }
312                         }
313 #endif
314                         return e;
315                 }
316         
317                 private class EvidenceEnumerator : IEnumerator {
318                         
319                         private IEnumerator currentEnum, hostEnum, assemblyEnum;                
320         
321                         public EvidenceEnumerator (IEnumerator hostenum, IEnumerator assemblyenum) 
322                         {
323                                 this.hostEnum = hostenum;
324                                 this.assemblyEnum = assemblyenum;
325                                 currentEnum = hostEnum;                 
326                         }
327
328                         public bool MoveNext () 
329                         {
330                                 bool ret = currentEnum.MoveNext ();
331                                 
332                                 if ( !ret && hostEnum == currentEnum ) {
333                                         currentEnum = assemblyEnum;
334                                         ret = assemblyEnum.MoveNext ();
335                                 }
336
337                                 return ret;
338                         }
339
340                         public void Reset () 
341                         {
342                                 hostEnum.Reset ();
343                                 assemblyEnum.Reset ();
344                                 currentEnum = hostEnum;
345                         }
346
347                         public object Current {
348                                 get {
349                                         return currentEnum.Current;
350                                 }
351                         }
352                 }
353         }
354 }
355