Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / security / policy / evidence.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 namespace System.Security.Policy
10 {
11     using System;
12     using System.Collections;
13     using System.Collections.Generic;
14     using System.Configuration.Assemblies;
15     using System.Diagnostics.Contracts;
16     using System.IO;
17     using System.Reflection;
18     using System.Runtime.CompilerServices;
19     using System.Runtime.InteropServices;
20     using System.Runtime.Remoting;
21 #if FEATURE_SERIALIZATION
22     using System.Runtime.Serialization;
23     using System.Runtime.Serialization.Formatters.Binary;
24 #endif // FEATURE_SERIALIZATION
25     using System.Security.Permissions;
26     using System.Security.Util;
27     using System.Threading;
28     using Microsoft.Win32.SafeHandles;
29
30     /// <summary>
31     ///     The Evidence class keeps track of information that can be used to make security decisions about
32     ///     an assembly or an AppDomain.  There are two types of evidence, one is supplied by the CLR or a
33     ///     host, the other supplied by the assembly itself.
34     ///     
35     ///     We keep a dictionary that maps each type of possbile evidence to an EvidenceTypeDescriptor which
36     ///     contains the evidence objects themselves if they exist as well as some extra metadata about that
37     ///     type of evidence.  This dictionary is fully populated with keys for host evidence at all times and
38     ///     for assembly evidence the first time the application evidence is touched.  This means that if a
39     ///     Type key does not exist in the dictionary, then that particular type of evidence will never be
40     ///     given to the assembly or AppDomain in question as host evidence.  The only exception is if the
41     ///     user later manually adds host evidence via the AddHostEvidence API.
42     ///     
43     ///     Assembly supplied evidence is created up front, however host supplied evidence may be lazily
44     ///     created.  In the lazy creation case, the Type will map to either an EvidenceTypeDescriptor that does
45     ///     not contain any evidence data or null.  As requests come in for that evidence, we'll populate the
46     ///     EvidenceTypeDescriptor appropriately.
47     /// </summary>
48     [Serializable]
49     [ComVisible(true)]
50     public sealed class Evidence
51 #if FEATURE_CAS_POLICY
52  : ICollection
53 #endif // FEATURE_CAS_POLICY
54     {
55 #if !FEATURE_CORECLR && FEATURE_RWLOCK
56 #if FEATURE_SERIALIZATION
57         [OptionalField(VersionAdded = 4)]
58         private Dictionary<Type, EvidenceTypeDescriptor> m_evidence;
59
60         [OptionalField(VersionAdded = 4)]
61         private bool m_deserializedTargetEvidence;
62
63         // These fields are only used to deserialize v2.0 serialized versions of Evidence. It will be null
64         // after the seriailzation process is complete, and should not be used.
65 #pragma warning disable 414
66         private volatile ArrayList m_hostList;
67         private volatile ArrayList m_assemblyList;
68 #pragma warning restore 414
69 #else // !FEATURE_SERIALIZATION
70         private Dictionary<Type, EvidenceTypeDescriptor> m_evidence;
71 #endif // FEATURE_SERIALIZATION
72
73         [NonSerialized]
74         private ReaderWriterLock m_evidenceLock;
75
76         [NonSerialized]
77         private uint m_version;
78
79         [NonSerialized]
80         private IRuntimeEvidenceFactory m_target;
81
82         private bool m_locked;
83
84         // If this evidence collection is a clone where we may need to backpatch to the original, this will
85         // reference the collection it was cloned from.  See
86         // code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence 
87         [NonSerialized]
88         private WeakReference m_cloneOrigin;
89
90         private static volatile Type[] s_runtimeEvidenceTypes;
91
92         /// <summary>
93         ///     Set of actions that we could perform if we detect that we are attempting to add evidence
94         ///     when we already have evidence of that type stored.
95         /// </summary>
96         private enum DuplicateEvidenceAction
97         {
98             Throw,                  // Throw an exception
99             Merge,                  // Create a list of all the evidence objects
100             SelectNewObject         // The newly added object wins
101         }
102
103 #if FEATURE_CAS_POLICY
104         public Evidence()
105         {
106             m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
107             m_evidenceLock = new ReaderWriterLock();
108         }
109 #endif // FEATURE_CAS_POLICY
110
111         /// <summary>
112         ///     Create a deep copy of an evidence object
113         /// </summary>
114         public Evidence(Evidence evidence)
115         {
116             m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
117
118             if (evidence != null)
119             {
120                 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(evidence, EvidenceLockHolder.LockType.Reader))
121                 {
122                     foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in evidence.m_evidence)
123                     {
124                         EvidenceTypeDescriptor cloneDescriptor = evidenceType.Value;
125                         if (cloneDescriptor != null)
126                         {
127                             cloneDescriptor = cloneDescriptor.Clone();
128                         }
129
130                         m_evidence[evidenceType.Key] = cloneDescriptor;
131                     }
132
133                     m_target = evidence.m_target;
134                     m_locked = evidence.m_locked;
135 #if FEATURE_SERIALIZATION
136                     m_deserializedTargetEvidence = evidence.m_deserializedTargetEvidence;
137 #endif // FEATURE_SERIALIZATION
138
139                     // see code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence
140                     if (evidence.Target != null)
141                     {
142                         m_cloneOrigin = new WeakReference(evidence);
143                     }
144                 }
145             }
146
147             // see code:System.Security.Policy.Evidence#EvidenceLock
148             m_evidenceLock = new ReaderWriterLock();
149         }
150
151         [Obsolete("This constructor is obsolete. Please use the constructor which takes arrays of EvidenceBase instead.")]
152         public Evidence(object[] hostEvidence, object[] assemblyEvidence)
153         {
154             m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
155
156             // This is a legacy evidence entry point, so we add through the legacy add APIs in order to get
157             // proper legacy wrapping and merge behavior.
158 #pragma warning disable 618
159             if (hostEvidence != null)
160             {
161                 foreach (object hostEvidenceObject in hostEvidence)
162                 {
163                     AddHost(hostEvidenceObject);
164                 }
165             }
166
167             if (assemblyEvidence != null)
168             {
169                 foreach (object assemblyEvidenceObject in assemblyEvidence)
170                 {
171                     AddAssembly(assemblyEvidenceObject);
172                 }
173             }
174 #pragma warning restore 618
175
176             // see code:System.Security.Policy.Evidence#EvidenceLock
177             m_evidenceLock = new ReaderWriterLock();
178         }
179
180         public Evidence(EvidenceBase[] hostEvidence, EvidenceBase[] assemblyEvidence)
181         {
182             m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
183
184             if (hostEvidence != null)
185             {
186                 foreach (EvidenceBase hostEvidenceObject in hostEvidence)
187                 {
188                     AddHostEvidence(hostEvidenceObject, GetEvidenceIndexType(hostEvidenceObject), DuplicateEvidenceAction.Throw);
189                 }
190             }
191
192             if (assemblyEvidence != null)
193             {
194                 foreach (EvidenceBase assemblyEvidenceObject in assemblyEvidence)
195                 {
196                     AddAssemblyEvidence(assemblyEvidenceObject, GetEvidenceIndexType(assemblyEvidenceObject), DuplicateEvidenceAction.Throw);
197                 }
198             }
199
200             // see code:System.Security.Policy.Evidence#EvidenceLock
201             m_evidenceLock = new ReaderWriterLock();
202         }
203
204         /// <summary>
205         ///     Create an empty evidence collection which will contain evidence for a specific assembly or
206         ///     AppDomain
207         /// </summary>
208         [SecuritySafeCritical]
209         internal Evidence(IRuntimeEvidenceFactory target)
210         {
211             Contract.Assert(target != null);
212
213             m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
214             m_target = target;
215
216             // Setup the types of evidence that the CLR can generate for a target as keys in the dictionary
217             foreach (Type runtimeEvidenceType in RuntimeEvidenceTypes)
218             {
219                 BCLDebug.Assert(typeof(EvidenceBase).IsAssignableFrom(runtimeEvidenceType), "All runtime evidence types should be EvidenceBases");
220                 m_evidence[runtimeEvidenceType] = null;
221             }
222
223             QueryHostForPossibleEvidenceTypes();
224
225             // see code:System.Security.Policy.Evidence#EvidenceLock
226             m_evidenceLock = new ReaderWriterLock();
227         }
228
229         internal static Type[] RuntimeEvidenceTypes
230         {
231             get
232             {
233                 if (s_runtimeEvidenceTypes == null)
234                 {
235                     Type[] runtimeEvidenceTypes = new Type[]
236                     {
237 #if FEATURE_CLICKONCE
238                         typeof(System.Runtime.Hosting.ActivationArguments),
239 #endif // FEATURE_CLICKONCE
240 #if FEATURE_CAS_POLICY
241                         typeof(ApplicationDirectory),
242 #endif // FEATURE_CAS_POLICY
243                         typeof(ApplicationTrust),
244 #if FEATURE_CAS_POLICY
245                         typeof(GacInstalled),
246                         typeof(Hash),
247                         typeof(Publisher),
248 #endif // FEATURE_CAS_POLICY
249                         typeof(Site),
250                         typeof(StrongName),
251                         typeof(Url),
252                         typeof(Zone)
253                     };
254
255 #if FEATURE_CAS_POLICY
256                     // We only supply permission request evidence in legacy CAS mode
257                     if (AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled)
258                     {
259 #pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode
260                         int l = runtimeEvidenceTypes.Length;
261                         Array.Resize(ref runtimeEvidenceTypes, l+1);
262                         runtimeEvidenceTypes[l] = typeof(PermissionRequestEvidence);
263 #pragma warning restore 618
264                     }
265 #endif // FEATURE_CAS_POLICY
266
267                     s_runtimeEvidenceTypes = runtimeEvidenceTypes;
268                 }
269
270                 return s_runtimeEvidenceTypes;
271             }
272         }
273
274         //
275         // #EvidenceLock
276         // 
277         // Evidence synchronization locking wrappers. In the case where the lock has not yet been created,
278         // we know that we're in the process of constructing the evidence collection and therefore we can
279         // act as though the evidence is locked.  If there is a lock in place, then just delegate back to it.
280         //
281         // The nested EvidenceLockHolder and EvidenceUpgradeLockHolder utility classes can be used to wrap
282         // these methods when acquiring and releasing the evidence lock.
283         //
284
285         // Millisecond timeout when waiting to acquire the evidence lock
286         private const int LockTimeout = 5000;
287
288         private bool IsReaderLockHeld
289         {
290             get { return m_evidenceLock == null || m_evidenceLock.IsReaderLockHeld; }
291         }
292
293         private bool IsWriterLockHeld
294         {
295             get { return m_evidenceLock == null || m_evidenceLock.IsWriterLockHeld; }
296         }
297
298         private void AcquireReaderLock()
299         {
300             Contract.Assert(m_evidenceLock == null || !IsReaderLockHeld);
301
302             if (m_evidenceLock != null)
303             {
304                 m_evidenceLock.AcquireReaderLock(LockTimeout);
305             }
306         }
307
308         private void AcquireWriterlock()
309         {
310             Contract.Assert(m_evidenceLock == null || !IsWriterLockHeld);
311
312             if (m_evidenceLock != null)
313             {
314                 m_evidenceLock.AcquireWriterLock(LockTimeout);
315             }
316         }
317
318         private void DowngradeFromWriterLock(ref LockCookie lockCookie)
319         {
320             Contract.Assert(IsWriterLockHeld);
321             if (m_evidenceLock != null)
322             {
323                 m_evidenceLock.DowngradeFromWriterLock(ref lockCookie);
324             }
325         }
326
327         private LockCookie UpgradeToWriterLock()
328         {
329             Contract.Assert(IsReaderLockHeld);
330             return m_evidenceLock != null ? m_evidenceLock.UpgradeToWriterLock(LockTimeout) : new LockCookie();
331         }
332
333         private void ReleaseReaderLock()
334         {
335             Contract.Assert(IsReaderLockHeld);
336
337             if (m_evidenceLock != null)
338             {
339                 m_evidenceLock.ReleaseReaderLock();
340             }
341         }
342
343         private void ReleaseWriterLock()
344         {
345             Contract.Assert(IsWriterLockHeld);
346
347             if (m_evidenceLock != null)
348             {
349                 m_evidenceLock.ReleaseWriterLock();
350             }
351         }
352
353         [Obsolete("This method is obsolete. Please use AddHostEvidence instead.")]
354         [SecuritySafeCritical]
355         public void AddHost(object id)
356         {
357             if (id == null)
358                 throw new ArgumentNullException("id");
359             if (!id.GetType().IsSerializable)
360                 throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id");
361             Contract.EndContractBlock();
362
363             if (m_locked)
364             {
365                 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
366             }
367
368             EvidenceBase evidence = WrapLegacyEvidence(id);
369             Type evidenceIndex = GetEvidenceIndexType(evidence);
370
371             // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey
372             // APIs, then allow the evidences to merge together.
373             AddHostEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge);
374         }
375
376         [Obsolete("This method is obsolete. Please use AddAssemblyEvidence instead.")]
377         public void AddAssembly(object id)
378         {
379             if (id == null)
380                 throw new ArgumentNullException("id");
381             if (!id.GetType().IsSerializable)
382                 throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id");
383             Contract.EndContractBlock();
384
385             EvidenceBase evidence = WrapLegacyEvidence(id);
386             Type evidenceIndex = GetEvidenceIndexType(evidence);
387
388             // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey
389             // APIs, then allow the evidences to merge together.
390             AddAssemblyEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge);
391         }
392
393         /// <summary>
394         ///     Add a piece of evidence to the assembly supplied evidence list. This method will disallow adding
395         ///     evidence if there is already evidence of that type in the assembly list.
396         /// </summary>
397         [ComVisible(false)]
398         public void AddAssemblyEvidence<T>(T evidence) where T : EvidenceBase
399         {
400             if (evidence == null)
401                 throw new ArgumentNullException("evidence");
402             Contract.EndContractBlock();
403
404             // Index the evidence under the type that the Add function was called with, unless we were given
405             // a plain EvidenceBase or a wrapped legacy evidence.  In that case, we need to index under a
406             // more specific type.
407             Type evidenceType = typeof(T);
408             if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter)
409             {
410                 evidenceType = GetEvidenceIndexType(evidence);
411             }
412
413             AddAssemblyEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
414         }
415
416         private void AddAssemblyEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
417         {
418             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
419             {
420                 AddAssemblyEvidenceNoLock(evidence, evidenceType, duplicateAction);
421             }
422         }
423
424         private void AddAssemblyEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
425         {
426             Contract.Assert(IsWriterLockHeld);
427             Contract.Assert(evidence != null);
428             Contract.Assert(evidenceType != null);
429
430             // We need to make sure that any target supplied evidence is deserialized before adding to the
431             // Assembly collection in order to preserve the semantics that the evidence objects supplied by
432             // the target are the original versions and evidence objects added via the APIs are the duplicates.
433             DeserializeTargetEvidence();
434
435             EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true);
436
437             ++m_version;
438             if (descriptor.AssemblyEvidence == null)
439             {
440                 descriptor.AssemblyEvidence = evidence;
441             }
442             else
443             {
444                 descriptor.AssemblyEvidence = HandleDuplicateEvidence(descriptor.AssemblyEvidence,
445                                                                       evidence,
446                                                                       duplicateAction);
447             }
448         }
449
450         /// <summary>
451         ///     Add a piece of evidence to the host supplied evidence list. This method will disallow adding
452         ///     evidence if there is already evidence of that type in the host list.
453         /// </summary>
454         [ComVisible(false)]
455         public void AddHostEvidence<T>(T evidence) where T : EvidenceBase
456         {
457             if (evidence == null)
458                 throw new ArgumentNullException("evidence");
459             Contract.EndContractBlock();
460
461             // Index the evidence under the type that the Add function was called with, unless we were given
462             // a plain EvidenceBase or a wrapped legacy evidence.  In that case, we need to index under a
463             // more specific type.
464             Type evidenceType = typeof(T);
465             if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter)
466             {
467                 evidenceType = GetEvidenceIndexType(evidence);
468             }
469
470             AddHostEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
471         }
472
473         [SecuritySafeCritical]
474         private void AddHostEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
475         {
476             Contract.Assert(evidence != null);
477             Contract.Assert(evidenceType != null);
478
479             if (Locked)
480             {
481                 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
482             }
483
484             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
485             {
486                 AddHostEvidenceNoLock(evidence, evidenceType, duplicateAction);
487             }
488         }
489
490         /// <summary>
491         ///     Add evidence to the host supplied evidence collection without acquiring the evidence lock or
492         ///     checking to make sure that the caller has permission to bypass locked evidence.
493         /// </summary>
494         private void AddHostEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
495         {
496             Contract.Assert(IsWriterLockHeld);
497             Contract.Assert(evidence != null);
498             Contract.Assert(evidenceType != null);
499
500             EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true);
501
502             ++m_version;
503             if (descriptor.HostEvidence == null)
504             {
505                 descriptor.HostEvidence = evidence;
506             }
507             else
508             {
509                 descriptor.HostEvidence = HandleDuplicateEvidence(descriptor.HostEvidence,
510                                                                   evidence,
511                                                                   duplicateAction);
512             }
513         }
514
515         /// <summary>
516         ///     Ask the host for the types of evidence that it might provide if it is asked.
517         ///     
518         ///     This should only be called when setting up the Evidence collection to interact with the
519         ///     host, and should not be used once that connection is established and the evidence has been
520         ///     made available to user code.
521         /// </summary>
522         [SecurityCritical]
523         private void QueryHostForPossibleEvidenceTypes()
524         {
525 #if FEATURE_CAS_POLICY
526             Contract.Assert(IsWriterLockHeld);
527
528             // First check to see if we have a HostSecurityManager
529             if (AppDomain.CurrentDomain.DomainManager != null)
530             {
531                 HostSecurityManager hsm = AppDomain.CurrentDomain.DomainManager.HostSecurityManager;
532                 if (hsm != null)
533                 {
534                     Type[] hostSuppliedTypes = null;
535
536                     AppDomain targetDomain = m_target.Target as AppDomain;
537                     Assembly targetAssembly = m_target.Target as Assembly;
538
539                     //
540                     // If the HostSecurityManager wants to supply evidence for the type of target that we have,
541                     // then ask it what types of evidence it might supply.
542                     //
543
544                     if (targetAssembly != null &&
545                         (hsm.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) == HostSecurityManagerOptions.HostAssemblyEvidence)
546                     {
547                         hostSuppliedTypes = hsm.GetHostSuppliedAssemblyEvidenceTypes(targetAssembly);
548                     }
549                     else if (targetDomain != null &&
550                              (hsm.Flags & HostSecurityManagerOptions.HostAppDomainEvidence) == HostSecurityManagerOptions.HostAppDomainEvidence)
551                     {
552                         hostSuppliedTypes = hsm.GetHostSuppliedAppDomainEvidenceTypes();
553                     }
554
555                     //
556                     // Finally, mark the descriptor for each of the types that the host can supply to indicate
557                     // we should ask the host to generate them if we're asked.
558                     // 
559
560                     if (hostSuppliedTypes != null)
561                     {
562                         foreach (Type hostEvidenceType in hostSuppliedTypes)
563                         {
564                             EvidenceTypeDescriptor evidenceDescriptor = GetEvidenceTypeDescriptor(hostEvidenceType, true);
565                             evidenceDescriptor.HostCanGenerate = true;
566                         }
567                     }
568                 }
569             }
570 #endif // FEATURE_CAS_POLICY
571         }
572
573         internal bool IsUnmodified
574         {
575             get { return m_version == 0; }
576         }
577
578         /// <summary>
579         ///     Set or check to see if the evidence is locked.  Locked evidence cannot have its host supplied
580         ///     evidence list be modified without a successful demand for ControlEvidence.  Any code can lock
581         ///     evidence, but only code with ControlEvidence may unlock it.
582         ///     
583         ///     This lock is not the same as the synchronization lock that gates access to the evidence collection.
584         /// </summary>
585         public bool Locked
586         {
587             get
588             {
589                 return m_locked;
590             }
591
592             [SecuritySafeCritical]
593             set
594             {
595                 if (!value)
596                 {
597                     new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
598
599                     m_locked = false;
600                 }
601                 else
602                 {
603                     m_locked = true;
604                 }
605             }
606         }
607
608         /// <summary>
609         ///     Target of any delay generated evidence objects
610         /// </summary>
611         internal IRuntimeEvidenceFactory Target
612         {
613             get { return m_target; }
614
615             //
616             // There are two retargeting scenarios supported:
617             // 
618             //   1. A PEFileEvidenceFactory is being upgraded to an AssemblyEvidenceFactory and we don't want
619             //      to throw away any already generated evidence.
620             //   2. A detached evidence collection is being applied to an AppDomain and that domain has a
621             //      HostSecurityManager. In that case, we want to attach the target to the AppDomain to
622             //      allow the HostSecurityManager to get callbacks for delay generated evidence.
623             // 
624
625             [SecurityCritical]
626             set
627             {
628 #if FEATURE_CAS_POLICY
629                 Contract.Assert((m_target != null && m_target is PEFileEvidenceFactory && value != null && value is AssemblyEvidenceFactory) ||
630                                 (m_target == null && value != null && value is AppDomainEvidenceFactory),
631                                 "Evidence retargeting should only be from PEFile -> Assembly or detached -> AppDomain.");
632 #endif // FEATURE_CAS_POLICY
633
634                 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
635                 {
636                     m_target = value;
637
638                     // Since we've updated what we're pointing at, we need to query the host to determine what
639                     // types of evidence that it can generate for this new target.
640                     QueryHostForPossibleEvidenceTypes();
641                 }
642             }
643         }
644
645         /// <summary>
646         ///     Get the type that would be used to index into the evidence dictionary for this object
647         /// </summary>
648         private static Type GetEvidenceIndexType(EvidenceBase evidence)
649         {
650             Contract.Assert(evidence != null);
651
652             //
653             // Legacy wrapper evidence types should be indexed via the type of evidence that they're wrapping
654             // so check to see if we have one of those; otherwise just return the type itself.
655             //
656
657             ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter;
658             return adapter == null ? evidence.GetType() : adapter.EvidenceType;
659         }
660
661         /// <summary>
662         ///     Get the type descriptor for a specific type of evidence.  This method should be used instead
663         ///     of accessing the dictionary directly as it will handle the case where a new descriptor needs
664         ///     to be created.
665         /// </summary>
666         internal EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType)
667         {
668             return GetEvidenceTypeDescriptor(evidenceType, false);
669         }
670
671         /// <summary>
672         ///     Get the type descriptor for a specific type of evidence, optionally creating a descriptor if
673         ///     we did not yet know about this type of evidence.  This method should be used instead of
674         ///     accessing the dictionary directly as it will handle the case where a new descriptor needs
675         ///     to be created.
676         /// </summary>
677         private EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType, bool addIfNotExist)
678         {
679             Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
680             Contract.Assert(evidenceType != null);
681
682             // If we don't know about the type being indexed and we don't want to add it then exit out
683             EvidenceTypeDescriptor descriptor = null;
684             if (!m_evidence.TryGetValue(evidenceType, out descriptor) && !addIfNotExist)
685             {
686                 return null;
687             }
688
689             // If we haven't yet created a descriptor for this type then create one now
690             if (descriptor == null)
691             {
692                 descriptor = new EvidenceTypeDescriptor();
693 #if _DEBUG
694                 descriptor.SetEvidenceType(evidenceType);
695 #endif // _DEBUG
696
697                 bool upgradedLock = false;
698                 LockCookie upgradeCookie = new LockCookie();
699                 try
700                 {
701                     if (!IsWriterLockHeld)
702                     {
703                         upgradeCookie = UpgradeToWriterLock();
704                         upgradedLock = true;
705                     }
706
707                     m_evidence[evidenceType] = descriptor;
708                 }
709                 finally
710                 {
711                     if (upgradedLock)
712                         DowngradeFromWriterLock(ref upgradeCookie);
713                 }
714             }
715
716             return descriptor;
717         }
718
719         /// <summary>
720         ///     This method is called if a piece of evidence is added but another piece of evidence of the same
721         ///     type already existed.  We have different strategies depending on compatibility concerns of the
722         ///     calling code.
723         /// </summary>
724         private static EvidenceBase HandleDuplicateEvidence(EvidenceBase original,
725                                                             EvidenceBase duplicate,
726                                                             DuplicateEvidenceAction action)
727         {
728             Contract.Assert(original != null);
729             Contract.Assert(duplicate != null);
730             Contract.Assert(original.GetType() == duplicate.GetType() || original.GetType() == typeof(LegacyEvidenceList));
731
732             switch (action)
733             {
734                 // Throw - duplicate evidence is not allowed (Arrowhead behavior), so throw an exception
735                 case DuplicateEvidenceAction.Throw:
736                     throw new InvalidOperationException(Environment.GetResourceString("Policy_DuplicateEvidence", duplicate.GetType().FullName));
737
738                 // SelectNewObject - MergeWithNoDuplicates behavior - the duplicate object wins
739                 case DuplicateEvidenceAction.SelectNewObject:
740                     return duplicate;
741
742                 // Merge - compat behavior. Merge the old and new evidence into a list so that both may exist
743                 case DuplicateEvidenceAction.Merge:
744
745                     LegacyEvidenceList list = original as LegacyEvidenceList;
746                     if (list == null)
747                     {
748                         list = new LegacyEvidenceList();
749                         list.Add(original);
750                     }
751
752                     list.Add(duplicate);
753                     return list;
754
755                 default:
756                     BCLDebug.Assert(false, "Uknown DuplicateEvidenceAction");
757                     return null;
758             }
759         }
760
761         /// <summary>
762         ///     Wrap evidence we recieved through a legacy API to ensure that it is stored in an EvidenceBase
763         /// </summary>
764         private static EvidenceBase WrapLegacyEvidence(object evidence)
765         {
766             Contract.Assert(evidence != null);
767
768             EvidenceBase wrappedEvidence = evidence as EvidenceBase;
769             if (wrappedEvidence == null)
770             {
771                 wrappedEvidence = new LegacyEvidenceWrapper(evidence);
772             }
773
774             return wrappedEvidence;
775         }
776
777         /// <summary>
778         ///     Upwrap evidence stored in a legacy adapter.
779         ///     
780         ///     This is only necessary for the case where multiple objects derived from EvidenceBase is
781         ///     are added via the legacy APIs and are then retrieved via GetHostEvidence. This may occur if
782         ///     a legacy application adds CLR supplied evidence types via the old APIs and a new application
783         ///     consumes the resulting evidence.
784         /// </summary>
785         private static object UnwrapEvidence(EvidenceBase evidence)
786         {
787             ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter;
788             return adapter == null ? evidence : adapter.EvidenceObject;
789         }
790
791         /// <summary>
792         ///     Merge two evidence collections together.  Note that this will cause all of the lazily
793         ///     generated evidence for the input collection to be generated, as well as causing any lazily
794         ///     generated evidence that both collections share to be generated in the target.
795         /// </summary>
796         [SecuritySafeCritical]
797         public void Merge(Evidence evidence)
798         {
799             if (evidence == null)
800             {
801                 return;
802             }
803
804             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
805             {
806                 bool checkedLock = false;
807                 IEnumerator hostEnumerator = evidence.GetHostEnumerator();
808                 while (hostEnumerator.MoveNext())
809                 {
810                     if (Locked && !checkedLock)
811                     {
812                         new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
813                         checkedLock = true;
814                     }
815
816                     // If we could potentially have evidence of the type about to be merged into our host list,
817                     // then make sure that we generate that evidence before merging.  This will prevent the
818                     // newly merged evidence from masking the value that we would have generated on our own.
819                     Type hostEvidenceType = hostEnumerator.Current.GetType();
820                     if (m_evidence.ContainsKey(hostEvidenceType))
821                     {
822                         GetHostEvidenceNoLock(hostEvidenceType);
823                     }
824
825                     EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
826                     AddHostEvidenceNoLock(hostEvidence,
827                                           GetEvidenceIndexType(hostEvidence),
828                                           DuplicateEvidenceAction.Merge);
829                 }
830
831                 // Add each piece of assembly evidence. We don't need to deserialize our copy of the
832                 // evidence because AddAssemblyEvidenceNoLock will do this for us.
833                 IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator();
834                 while (assemblyEnumerator.MoveNext())
835                 {
836                     EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
837                     AddAssemblyEvidenceNoLock(assemblyEvidence,
838                                               GetEvidenceIndexType(assemblyEvidence),
839                                               DuplicateEvidenceAction.Merge);
840                 }
841             }
842         }
843
844         /// <summary>
845         ///     Same as merge, except only one instance of any one evidence type is allowed. When duplicates
846         ///     are found, the evidence in the input argument will have priority. Note this will force the
847         ///     entire input evidence to be generated, and does not check for locked evidence
848         /// </summary>
849         internal void MergeWithNoDuplicates(Evidence evidence)
850         {
851             if (evidence == null)
852             {
853                 return;
854             }
855
856             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
857             {
858                 IEnumerator hostEnumerator = evidence.GetHostEnumerator();
859                 while (hostEnumerator.MoveNext())
860                 {
861                     EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
862                     AddHostEvidenceNoLock(hostEvidence,
863                                           GetEvidenceIndexType(hostEvidence),
864                                           DuplicateEvidenceAction.SelectNewObject);
865                 }
866
867                 IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator();
868                 while (assemblyEnumerator.MoveNext())
869                 {
870                     EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
871                     AddAssemblyEvidenceNoLock(assemblyEvidence,
872                                               GetEvidenceIndexType(assemblyEvidence),
873                                               DuplicateEvidenceAction.SelectNewObject);
874                 }
875             }
876         }
877
878 #if FEATURE_SERIALIZATION
879         /// <summary>
880         ///     Do a full serialization of the evidence, which requires that we generate all of the evidence
881         ///     we can and disconnect ourselves from the host and source assembly.
882         /// </summary>
883         [ComVisible(false)]
884         [OnSerializing]
885         [SecurityCritical]
886         [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
887         private void OnSerializing(StreamingContext context)
888         {
889             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
890             {
891                 // First, force all of the host evidence that might be lazily generated to be created
892                 foreach (Type evidenceType in new List<Type>(m_evidence.Keys))
893                 {
894                     GetHostEvidenceNoLock(evidenceType);
895                 }
896
897                 // Also ensure that all serialized assembly evidence has been created
898                 DeserializeTargetEvidence();
899             }
900
901             // Fill in legacy evidence lists. We can't guarantee thread-safety here using locks
902             // because we can't put a lock in the serialization code that will read the lists.
903             // The best we can do is prevent another thread from seeing a half-populated list.
904             // Therefore, we assign the lists after we've populated them fully (and declare them volatile.)
905             ArrayList hostList = new ArrayList();
906             IEnumerator hostEnumerator = GetHostEnumerator();
907             while (hostEnumerator.MoveNext())
908             {
909                 hostList.Add(hostEnumerator.Current);
910             }
911             m_hostList = hostList;
912
913             ArrayList assemblyList = new ArrayList();
914             IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
915             while (assemblyEnumerator.MoveNext())
916             {
917                 assemblyList.Add(assemblyEnumerator.Current);
918             }
919             m_assemblyList = assemblyList;
920         }
921
922         /// <summary>
923         ///     Finish deserializing legacy evidence
924         /// </summary>
925         [ComVisible(false)]
926         [OnDeserialized]
927         [SecurityCritical]
928         private void OnDeserialized(StreamingContext context)
929         {
930             // Look at host and assembly evidence lists only if we serialized using Whidbey.
931             if (m_evidence == null)
932             {
933                 m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
934
935                 // Whidbey evidence may need to be wrapped or added to a LegacyEvidenceList, so we go
936                 // through the legacy APIs to add them.
937 #pragma warning disable 618
938                 if (m_hostList != null)
939                 {
940                     foreach (object evidenceObject in m_hostList)
941                     {
942                         if (evidenceObject != null)
943                         {
944                             AddHost(evidenceObject);
945                         }
946                     }
947
948                     m_hostList = null;
949                 }
950
951                 if (m_assemblyList != null)
952                 {
953                     foreach (object evidenceObject in m_assemblyList)
954                     {
955                         if (evidenceObject != null)
956                         {
957                             AddAssembly(evidenceObject);
958                         }
959                     }
960
961                     m_assemblyList = null;
962                 }
963 #pragma warning restore 618
964             }
965
966             // see code:System.Security.Policy.Evidence#EvidenceLock
967             m_evidenceLock = new ReaderWriterLock();
968         }
969 #endif // FEATURE_SERIALIZATION
970
971         /// <summary>
972         ///     Load any serialized evidence out of the target assembly into our evidence collection.
973         ///     
974         ///     We allow entry to this method with only a reader lock held, since most of the time we will
975         ///     not need to write to the evidence dictionary. If we haven't yet deserialized the target
976         ///     evidence, then we will upgrade to a writer lock at that point.
977         /// </summary>
978         private void DeserializeTargetEvidence()
979         {
980 #if FEATURE_SERIALIZATION
981             Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
982
983             if (m_target != null && !m_deserializedTargetEvidence)
984             {
985                 bool upgradedLock = false;
986                 LockCookie lockCookie = new LockCookie();
987                 try
988                 {
989                     if (!IsWriterLockHeld)
990                     {
991                         lockCookie = UpgradeToWriterLock();
992                         upgradedLock = true;
993                     }
994
995                     // Set this to true here because AddAssemblyEvidenceNoLock will attempt to reenter this
996                     // method creating possible infinite recursion.
997                     m_deserializedTargetEvidence = true;
998
999                     foreach (EvidenceBase targetEvidence in m_target.GetFactorySuppliedEvidence())
1000                     {
1001                         AddAssemblyEvidenceNoLock(targetEvidence, GetEvidenceIndexType(targetEvidence), DuplicateEvidenceAction.Throw);
1002                     }
1003                 }
1004                 finally
1005                 {
1006                     if (upgradedLock)
1007                         DowngradeFromWriterLock(ref lockCookie);
1008                 }
1009             }
1010 #endif // FEATURE_SERIALIZATION
1011         }
1012
1013 #if FEATURE_SERIALIZATION
1014         /// <summary>
1015         ///     Serialize out raw evidence objects which have already been generated, ignoring any evidence
1016         ///     which might be present but has not yet been created for this assembly.
1017         ///     
1018         ///     This is used for indexing into the security policy cache, since we know that once policy is
1019         ///     resolved, the relevent membership conditions will have checked for any applicable evidence
1020         ///     and therefore after poliyc resolution this evidence collection will contain any evidence
1021         ///     objects necessary to arrive at its grant set.
1022         /// </summary>
1023         [SecurityCritical]
1024         internal byte[] RawSerialize()
1025         {
1026             try
1027             {
1028                 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1029                 {
1030                     // Filter out any evidence which is not yet generated
1031                     Dictionary<Type, EvidenceBase> generatedEvidence = new Dictionary<Type, EvidenceBase>();
1032                     foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in m_evidence)
1033                     {
1034                         if (evidenceType.Value != null && evidenceType.Value.HostEvidence != null)
1035                         {
1036                             generatedEvidence[evidenceType.Key] = evidenceType.Value.HostEvidence;
1037                         }
1038                     }
1039
1040                     using (MemoryStream serializationStream = new MemoryStream())
1041                     {
1042                         BinaryFormatter formatter = new BinaryFormatter();
1043                         formatter.Serialize(serializationStream, generatedEvidence);
1044                         return serializationStream.ToArray();
1045                     }
1046                 }
1047             }
1048             catch (SecurityException)
1049             {
1050                 // We're running in a context where it's not safe to serialize the evidence out.  In this case
1051                 // Simply decline to cache the result of the policy evaluation
1052                 return null;
1053             }
1054         }
1055 #endif // FEATURE_SERIALIZATION
1056
1057         //
1058         // ICollection implementation.  All ICollection interface members are potentially much more
1059         // expensive in Arrowhead then they were downlevel.  They should not be used if the standard Get and
1060         // Add methods will work instead.
1061         // 
1062
1063         [Obsolete("Evidence should not be treated as an ICollection. Please use the GetHostEnumerator and GetAssemblyEnumerator methods rather than using CopyTo.")]
1064         public void CopyTo(Array array, int index)
1065         {
1066             if (array == null)
1067                 throw new ArgumentNullException("array");
1068             if (index < 0 || index > array.Length - Count)
1069                 throw new ArgumentOutOfRangeException("index");
1070             Contract.EndContractBlock();
1071
1072             int currentIndex = index;
1073
1074             IEnumerator hostEnumerator = GetHostEnumerator();
1075             while (hostEnumerator.MoveNext())
1076             {
1077                 array.SetValue(hostEnumerator.Current, currentIndex);
1078                 ++currentIndex;
1079             }
1080
1081             IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
1082             while (assemblyEnumerator.MoveNext())
1083             {
1084                 array.SetValue(assemblyEnumerator.Current, currentIndex);
1085                 ++currentIndex;
1086             }
1087         }
1088
1089         public IEnumerator GetHostEnumerator()
1090         {
1091             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1092             {
1093                 return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host);
1094             }
1095         }
1096
1097         public IEnumerator GetAssemblyEnumerator()
1098         {
1099             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1100             {
1101                 DeserializeTargetEvidence();
1102                 return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Assembly);
1103             }
1104         }
1105
1106         /// <summary>
1107         ///     Get an enumerator that can iterate over the raw evidence objects stored for the assembly
1108         /// </summary>
1109         internal RawEvidenceEnumerator GetRawAssemblyEvidenceEnumerator()
1110         {
1111             Contract.Assert(IsReaderLockHeld);
1112             DeserializeTargetEvidence();
1113             return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), false);
1114         }
1115
1116         /// <summary>
1117         ///     Get an enumerator that can iterate over the raw evidence objects stored for the host
1118         /// </summary>
1119         /// <returns></returns>
1120         internal RawEvidenceEnumerator GetRawHostEvidenceEnumerator()
1121         {
1122             Contract.Assert(IsReaderLockHeld);
1123             return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), true);
1124         }
1125
1126         [Obsolete("GetEnumerator is obsolete. Please use GetAssemblyEnumerator and GetHostEnumerator instead.")]
1127         public IEnumerator GetEnumerator()
1128         {
1129             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1130             {
1131                 return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host | EvidenceEnumerator.Category.Assembly);
1132             }
1133         }
1134
1135         /// <summary>
1136         ///     Get a specific type of assembly supplied evidence
1137         /// </summary>
1138         [ComVisible(false)]
1139         public T GetAssemblyEvidence<T>() where T : EvidenceBase
1140         {
1141             return UnwrapEvidence(GetAssemblyEvidence(typeof(T))) as T;
1142         }
1143
1144         internal EvidenceBase GetAssemblyEvidence(Type type)
1145         {
1146             Contract.Assert(type != null);
1147
1148             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1149             {
1150                 return GetAssemblyEvidenceNoLock(type);
1151             }
1152         }
1153
1154         private EvidenceBase GetAssemblyEvidenceNoLock(Type type)
1155         {
1156             Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
1157             Contract.Assert(type != null);
1158
1159             DeserializeTargetEvidence();
1160             EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type);
1161             if (descriptor != null)
1162             {
1163                 return descriptor.AssemblyEvidence;
1164             }
1165
1166             return null;
1167         }
1168
1169         /// <summary>
1170         ///     Get a specific type of host supplied evidence
1171         /// </summary>
1172         [ComVisible(false)]
1173         public T GetHostEvidence<T>() where T : EvidenceBase
1174         {
1175             return UnwrapEvidence(GetHostEvidence(typeof(T))) as T;
1176         }
1177
1178         /// <summary>
1179         ///     Get a specific type of evidence from the host which may not have been verified yet.  If the
1180         ///     evidence was not verified, then don't mark it as being used yet.
1181         /// </summary>
1182         internal T GetDelayEvaluatedHostEvidence<T>() where T : EvidenceBase, IDelayEvaluatedEvidence
1183         {
1184             return UnwrapEvidence(GetHostEvidence(typeof(T), false)) as T;
1185         }
1186
1187         internal EvidenceBase GetHostEvidence(Type type)
1188         {
1189             Contract.Assert(type != null);
1190
1191             return GetHostEvidence(type, true);
1192         }
1193
1194         [SecuritySafeCritical]
1195         private EvidenceBase GetHostEvidence(Type type, bool markDelayEvaluatedEvidenceUsed)
1196         {
1197             Contract.Assert(type != null);
1198
1199             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1200             {
1201                 EvidenceBase evidence = GetHostEvidenceNoLock(type);
1202
1203                 if (markDelayEvaluatedEvidenceUsed)
1204                 {
1205                     IDelayEvaluatedEvidence delayEvidence = evidence as IDelayEvaluatedEvidence;
1206                     if (delayEvidence != null)
1207                     {
1208                         delayEvidence.MarkUsed();
1209                     }
1210                 }
1211
1212                 return evidence;
1213             }
1214         }
1215
1216         /// <summary>
1217         ///     Get host supplied evidence from the collection
1218         ///
1219         ///     We attempt to find host evdience in the following order:
1220         ///     
1221         ///       1. Already generated or explicitly supplied evidence
1222         ///       2. Evidence supplied by the CLR host
1223         ///       3. Evidence supplied by the CLR itself
1224         /// </summary>
1225         [SecurityCritical]
1226         private EvidenceBase GetHostEvidenceNoLock(Type type)
1227         {
1228             Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
1229             Contract.Assert(type != null);
1230
1231             EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type);
1232
1233             // If the evidence descriptor doesn't exist for the host evidence type than the evidence doesn't
1234             // exist and neither the host nor the runtime can produce it.
1235             if (descriptor == null)
1236             {
1237                 return null;
1238             }
1239
1240             // If the evidence has already been generated or if it was explicitly provided then return that
1241             if (descriptor.HostEvidence != null)
1242             {
1243                 return descriptor.HostEvidence;
1244             }
1245
1246             // If we have a target, then the host or the runtime might be able to generate this type of
1247             // evidence on demand.
1248             if (m_target != null && !descriptor.Generated)
1249             {
1250                 using (EvidenceUpgradeLockHolder lockHolder = new EvidenceUpgradeLockHolder(this))
1251                 {
1252                     // Make sure that we don't attempt to generate this type of evidencea again if we fail to
1253                     // generate it now.
1254                     descriptor.Generated = true;
1255
1256                     EvidenceBase generatedEvidence = GenerateHostEvidence(type, descriptor.HostCanGenerate);
1257                     if (generatedEvidence != null)
1258                     {
1259                         descriptor.HostEvidence = generatedEvidence;
1260
1261                         //
1262                         // #BackpatchGeneratedEvidence
1263                         // 
1264                         // If we were cloned from another evidence collection propigate any generated evidence
1265                         // back to the original collection.  Since Assembly and AppDomain both clone their
1266                         // evidence before giving it to users, this prevents us from having to regenerate
1267                         // evidence types on each clone that gets created.  Note that we do not want to do this
1268                         // backpatching if the origin already has evidence of this type or if it has had
1269                         // this type of evidence removed from its collection.
1270                         //
1271
1272                         Evidence cloneOrigin = m_cloneOrigin != null ? m_cloneOrigin.Target as Evidence : null;
1273                         if (cloneOrigin != null)
1274                         {
1275                             BCLDebug.Assert(cloneOrigin.Target != null && cloneOrigin.Target == Target,
1276                                             "Attempt to backpatch evidence to a collection with a different target.");
1277
1278                             using (EvidenceLockHolder cloneLockHolder = new EvidenceLockHolder(cloneOrigin, EvidenceLockHolder.LockType.Writer))
1279                             {
1280                                 EvidenceTypeDescriptor cloneDescriptor = cloneOrigin.GetEvidenceTypeDescriptor(type);
1281                                 if (cloneDescriptor != null && cloneDescriptor.HostEvidence == null)
1282                                 {
1283                                     cloneDescriptor.HostEvidence = generatedEvidence.Clone() as EvidenceBase;
1284                                 }
1285                             }
1286                         }
1287
1288                     }
1289
1290                     return generatedEvidence;
1291                 }
1292             }
1293
1294             // The evidence could not be generated and was not found
1295             return null;
1296         }
1297
1298         /// <summary>
1299         ///     Attempt to generate host evidence on demand via calls to the runtime host or the evidence facotry
1300         /// </summary>
1301         [SecurityCritical]
1302         private EvidenceBase GenerateHostEvidence(Type type, bool hostCanGenerate)
1303         {
1304             Contract.Assert(type != null);
1305             Contract.Assert(IsWriterLockHeld);
1306
1307 #if FEATURE_CAS_POLICY
1308             // First let the host generate the evidence if it can.
1309             if (hostCanGenerate)
1310             {
1311                 AppDomain targetDomain = m_target.Target as AppDomain;
1312                 Assembly targetAssembly = m_target.Target as Assembly;
1313
1314                 EvidenceBase hostEvidence = null;
1315                 if (targetDomain != null)
1316                 {
1317                     hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAppDomainEvidence(type);
1318                 }
1319                 else if (targetAssembly != null)
1320                 {
1321                     hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAssemblyEvidence(type, targetAssembly);
1322                 }
1323
1324                 // If the host generated the evidence, verify that it generated the evidence we expected
1325                 // and use that.
1326                 if (hostEvidence != null)
1327                 {
1328                     if (!type.IsAssignableFrom(hostEvidence.GetType()))
1329                     {
1330                         string hostType = AppDomain.CurrentDomain.HostSecurityManager.GetType().FullName;
1331                         string recievedType = hostEvidence.GetType().FullName;
1332                         string requestedType = type.FullName;
1333
1334                         throw new InvalidOperationException(Environment.GetResourceString("Policy_IncorrectHostEvidence", hostType, recievedType, requestedType));
1335                     }
1336
1337                     return hostEvidence;
1338                 }
1339             }
1340 #endif // FEATURE_CAS_POLICY
1341
1342             // Finally, check to see if the CLR can generate the evidence
1343             return m_target.GenerateEvidence(type);
1344         }
1345
1346         [Obsolete("Evidence should not be treated as an ICollection. Please use GetHostEnumerator and GetAssemblyEnumerator to iterate over the evidence to collect a count.")]
1347         public int Count
1348         {
1349             get
1350             {
1351                 int count = 0;
1352
1353                 IEnumerator hostEvidence = GetHostEnumerator();
1354                 while (hostEvidence.MoveNext())
1355                 {
1356                     ++count;
1357                 }
1358
1359                 IEnumerator assemblyEvidence = GetAssemblyEnumerator();
1360                 while (assemblyEvidence.MoveNext())
1361                 {
1362                     ++count;
1363                 }
1364
1365                 return count;
1366             }
1367         }
1368
1369         /// <summary>
1370         ///     Get the number of pieces of evidence which are currently generated, without causing any
1371         ///     lazily generated evidence to be created.
1372         /// </summary>
1373         [ComVisible(false)]
1374         internal int RawCount
1375         {
1376             get
1377             {
1378                 int count = 0;
1379
1380                 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1381                 {
1382                     foreach (Type evidenceType in new List<Type>(m_evidence.Keys))
1383                     {
1384                         EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType);
1385
1386                         if (descriptor != null)
1387                         {
1388                             if (descriptor.AssemblyEvidence != null)
1389                             {
1390                                 ++count;
1391                             }
1392                             if (descriptor.HostEvidence != null)
1393                             {
1394                                 ++count;
1395                             }
1396                         }
1397                     }
1398                 }
1399
1400                 return count;
1401             }
1402         }
1403
1404         public Object SyncRoot
1405         {
1406             get { return this; }
1407         }
1408
1409         public bool IsSynchronized
1410         {
1411             get { return true; }
1412         }
1413
1414         public bool IsReadOnly
1415         {
1416             get { return false; }
1417         }
1418
1419 #if FEATURE_CAS_POLICY
1420         [ComVisible(false)]
1421         public Evidence Clone()
1422         {
1423             return new Evidence(this);
1424         }
1425 #endif // FEATURE_CAS_POLICY
1426
1427         [ComVisible(false)]
1428         [SecuritySafeCritical]
1429         public void Clear()
1430         {
1431             if (Locked)
1432             {
1433                 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
1434             }
1435
1436             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
1437             {
1438                 ++m_version;
1439                 m_evidence.Clear();
1440             }
1441         }
1442
1443         [ComVisible(false)]
1444         [SecuritySafeCritical]
1445         public void RemoveType(Type t)
1446         {
1447             if (t == null)
1448                 throw new ArgumentNullException("t");
1449             Contract.EndContractBlock();
1450
1451             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
1452             {
1453                 EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(t);
1454                 if (descriptor != null)
1455                 {
1456                     ++m_version;
1457
1458                     // If we've locked this evidence collection, we need to do the lock check in the case that 
1459                     // either we have host evidence, or that the host might generate it, since removing the
1460                     // evidence will cause us to bypass the host's ability to ever generate the evidence.
1461                     if (Locked && (descriptor.HostEvidence != null || descriptor.HostCanGenerate))
1462                     {
1463                         new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
1464                     }
1465
1466                     m_evidence.Remove(t);
1467                 }
1468             }
1469         }
1470
1471         /// <summary>
1472         ///     Mark all of the already generated evidence in the collection as having been used during a
1473         ///     policy evaluation.
1474         /// </summary>
1475         internal void MarkAllEvidenceAsUsed()
1476         {
1477             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1478             {
1479                 foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in m_evidence)
1480                 {
1481                     if (evidenceType.Value != null)
1482                     {
1483                         IDelayEvaluatedEvidence hostEvidence = evidenceType.Value.HostEvidence as IDelayEvaluatedEvidence;
1484                         if (hostEvidence != null)
1485                         {
1486                             hostEvidence.MarkUsed();
1487                         }
1488
1489                         IDelayEvaluatedEvidence assemblyEvidence = evidenceType.Value.AssemblyEvidence as IDelayEvaluatedEvidence;
1490                         if (assemblyEvidence != null)
1491                         {
1492                             assemblyEvidence.MarkUsed();
1493                         }
1494                     }
1495                 }
1496             }
1497         }
1498
1499 #if FEATURE_CAS_POLICY
1500         /// <summary>
1501         ///     Determine if delay evaluated strong name evidence is contained in this collection, and if so
1502         ///     if it was used during policy evaluation.
1503         ///     
1504         ///     This method is called from the VM in SecurityPolicy::WasStrongNameEvidenceUsed
1505         ///     This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to
1506         ///     be able to get the evidence values out of an Evidence class.  It is tightly coupled with the
1507         ///     internal data structures holding the evidence objects in the Evidence class.
1508         /// </summary>
1509         private bool WasStrongNameEvidenceUsed()
1510         {
1511             using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1512             {
1513                 EvidenceTypeDescriptor snTypeDescriptor = GetEvidenceTypeDescriptor(typeof(StrongName));
1514                 if (snTypeDescriptor != null)
1515                 {
1516                     IDelayEvaluatedEvidence snEvidence = snTypeDescriptor.HostEvidence as IDelayEvaluatedEvidence;
1517                     return snEvidence != null && snEvidence.WasUsed;
1518                 }
1519
1520                 return false;
1521             }
1522         }
1523 #endif // FEATURE_CAS_POLICY
1524
1525         /// <summary>
1526         ///     Utility class to wrap acquiring a lock onto the evidence collection
1527         /// </summary>
1528         private class EvidenceLockHolder : IDisposable
1529         {
1530             private Evidence m_target;
1531             private LockType m_lockType;
1532
1533             public enum LockType
1534             {
1535                 Reader,
1536                 Writer
1537             }
1538
1539             public EvidenceLockHolder(Evidence target, LockType lockType)
1540             {
1541                 Contract.Assert(target != null);
1542                 Contract.Assert(lockType == LockType.Reader || lockType == LockType.Writer);
1543
1544                 m_target = target;
1545                 m_lockType = lockType;
1546
1547                 if (m_lockType == LockType.Reader)
1548                 {
1549                     m_target.AcquireReaderLock();
1550                 }
1551                 else
1552                 {
1553                     m_target.AcquireWriterlock();
1554                 }
1555             }
1556
1557             public void Dispose()
1558             {
1559                 if (m_lockType == LockType.Reader && m_target.IsReaderLockHeld)
1560                 {
1561                     m_target.ReleaseReaderLock();
1562                 }
1563                 else if (m_lockType == LockType.Writer && m_target.IsWriterLockHeld)
1564                 {
1565                     m_target.ReleaseWriterLock();
1566                 }
1567             }
1568         }
1569
1570         /// <summary>
1571         ///     Utility class to wrap upgrading an acquired reader lock to a writer lock and then
1572         ///     downgrading it back to a reader lock.
1573         /// </summary>
1574         private class EvidenceUpgradeLockHolder : IDisposable
1575         {
1576             private Evidence m_target;
1577             private LockCookie m_cookie;
1578
1579             public EvidenceUpgradeLockHolder(Evidence target)
1580             {
1581                 Contract.Assert(target != null);
1582
1583                 m_target = target;
1584                 m_cookie = m_target.UpgradeToWriterLock();
1585             }
1586
1587             public void Dispose()
1588             {
1589                 if (m_target.IsWriterLockHeld)
1590                 {
1591                     m_target.DowngradeFromWriterLock(ref m_cookie);
1592                 }
1593             }
1594         }
1595
1596         /// <summary>
1597         ///     Enumerator that iterates directly over the evidence type map, returning back the evidence objects
1598         ///     that are contained in it.  This enumerator will generate any lazy evaluated evidence it finds,
1599         ///     but it does not attempt to deal with legacy evidence adapters.
1600         ///     
1601         ///     This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to
1602         ///     be able to get the evidence values out of an Evidence class.  It is tightly coupled with the
1603         ///     internal data structures holding the evidence objects in the Evidence class.
1604         /// </summary>
1605         internal sealed class RawEvidenceEnumerator : IEnumerator<EvidenceBase>
1606         {
1607             private Evidence m_evidence;
1608             private bool m_hostEnumerator;      // true to enumerate host evidence, false to enumerate assembly evidence
1609             private uint m_evidenceVersion;
1610
1611             private Type[] m_evidenceTypes;
1612             private int m_typeIndex;
1613             private EvidenceBase m_currentEvidence;
1614
1615             private static volatile List<Type> s_expensiveEvidence;
1616
1617             public RawEvidenceEnumerator(Evidence evidence, IEnumerable<Type> evidenceTypes, bool hostEnumerator)
1618             {
1619                 Contract.Assert(evidence != null);
1620                 Contract.Assert(evidenceTypes != null);
1621
1622                 m_evidence = evidence;
1623                 m_hostEnumerator = hostEnumerator;
1624                 m_evidenceTypes = GenerateEvidenceTypes(evidence, evidenceTypes, hostEnumerator);
1625                 m_evidenceVersion = evidence.m_version;
1626
1627                 Reset();
1628             }
1629
1630             public EvidenceBase Current
1631             {
1632                 get
1633                 {
1634                     if (m_evidence.m_version != m_evidenceVersion)
1635                         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1636
1637                     return m_currentEvidence;
1638                 }
1639             }
1640
1641             object IEnumerator.Current
1642             {
1643                 get
1644                 {
1645                     if (m_evidence.m_version != m_evidenceVersion)
1646                         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1647
1648                     return m_currentEvidence;
1649                 }
1650             }
1651
1652             /// <summary>
1653             ///     List of types of evidence that we would like to avoid generating if possible
1654             /// </summary>
1655             private static List<Type> ExpensiveEvidence
1656             {
1657                 get
1658                 {
1659                     if (s_expensiveEvidence == null)
1660                     {
1661                         List<Type> expensiveEvidence = new List<Type>();
1662 #if FEATURE_CAS_POLICY
1663                         expensiveEvidence.Add(typeof(Hash));
1664                         expensiveEvidence.Add(typeof(Publisher));
1665 #endif // FEATURE_CAS_POLICY
1666                         s_expensiveEvidence = expensiveEvidence;
1667
1668 #if _DEBUG
1669                         List<Type> runtimeTypes = new List<Type>(Evidence.RuntimeEvidenceTypes);
1670                         foreach (Type expensiveType in s_expensiveEvidence)
1671                         {
1672                             BCLDebug.Assert(runtimeTypes.Contains(expensiveType),
1673                                             "Evidence type not generated by the runtime found in expensive evidence type list");
1674                         }
1675 #endif // _DEBUG
1676                     }
1677
1678                     return s_expensiveEvidence;
1679                 }
1680             }
1681
1682             public void Dispose()
1683             {
1684                 return;
1685             }
1686
1687             /// <summary>
1688             ///     Generate the array of types of evidence that could have values for
1689             /// </summary>
1690             private static Type[] GenerateEvidenceTypes(Evidence evidence,
1691                                                         IEnumerable<Type> evidenceTypes,
1692                                                         bool hostEvidence)
1693             {
1694                 Contract.Assert(evidence != null);
1695                 Contract.Assert(evidenceTypes != null);
1696
1697                 //
1698                 // Sort the evidence being generated into three categories, which we enumerate in order:
1699                 //   1. Evidence which has already been generated
1700                 //   2. Evidence which is relatively inexpensive to generate
1701                 //   3. Evidence which is expensive to generate.
1702                 //   
1703                 // This allows us to be as efficient as possible in case the user of the enumerator stops the
1704                 // enumeration before we step up to the next more expensive category.
1705                 //
1706
1707                 List<Type> alreadyGeneratedList = new List<Type>();
1708                 List<Type> inexpensiveList = new List<Type>();
1709                 List<Type> expensiveList = new List<Type>(ExpensiveEvidence.Count);
1710
1711                 // Iterate over the evidence types classifying into the three groups.  We need to copy the list
1712                 // here since GetEvidenceTypeDescriptor will potentially update the evidence dictionary, which
1713                 // evidenceTypes iterates over.
1714                 foreach (Type evidenceType in evidenceTypes)
1715                 {
1716                     EvidenceTypeDescriptor descriptor = evidence.GetEvidenceTypeDescriptor(evidenceType);
1717                     BCLDebug.Assert(descriptor != null, "descriptor != null");
1718
1719                     bool alreadyGenerated = (hostEvidence && descriptor.HostEvidence != null) ||
1720                                             (!hostEvidence && descriptor.AssemblyEvidence != null);
1721
1722                     if (alreadyGenerated)
1723                     {
1724                         alreadyGeneratedList.Add(evidenceType);
1725                     }
1726                     else if (ExpensiveEvidence.Contains(evidenceType))
1727                     {
1728                         expensiveList.Add(evidenceType);
1729                     }
1730                     else
1731                     {
1732                         inexpensiveList.Add(evidenceType);
1733                     }
1734                 }
1735
1736                 Type[] enumerationTypes = new Type[alreadyGeneratedList.Count + inexpensiveList.Count + expensiveList.Count];
1737                 alreadyGeneratedList.CopyTo(enumerationTypes, 0);
1738                 inexpensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count);
1739                 expensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count + inexpensiveList.Count);
1740
1741                 return enumerationTypes;
1742             }
1743
1744             [SecuritySafeCritical]
1745             public bool MoveNext()
1746             {
1747                 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
1748                 {
1749                     if (m_evidence.m_version != m_evidenceVersion)
1750                         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1751
1752                     m_currentEvidence = null;
1753
1754                     // Iterate over the possible types of evidence that we could have until we find one that
1755                     // really exists, or we run out of posibilities.
1756                     do
1757                     {
1758                         ++m_typeIndex;
1759
1760                         if (m_typeIndex < m_evidenceTypes.Length)
1761                         {
1762                             if (m_hostEnumerator)
1763                             {
1764                                 m_currentEvidence = m_evidence.GetHostEvidenceNoLock(m_evidenceTypes[m_typeIndex]);
1765                             }
1766                             else
1767                             {
1768                                 m_currentEvidence = m_evidence.GetAssemblyEvidenceNoLock(m_evidenceTypes[m_typeIndex]);
1769                             }
1770                         }
1771                     }
1772                     while (m_typeIndex < m_evidenceTypes.Length && m_currentEvidence == null);
1773                 }
1774
1775                 return m_currentEvidence != null;
1776             }
1777
1778             public void Reset()
1779             {
1780                 if (m_evidence.m_version != m_evidenceVersion)
1781                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1782
1783                 m_typeIndex = -1;
1784                 m_currentEvidence = null;
1785             }
1786         }
1787
1788         private sealed class EvidenceEnumerator : IEnumerator
1789         {
1790             private Evidence m_evidence;
1791             private Category m_category;
1792             private Stack m_enumerators;
1793
1794             private object m_currentEvidence;
1795
1796             [Flags]
1797             internal enum Category
1798             {
1799                 Host = 0x1,     // Enumerate only host supplied evidence
1800                 Assembly = 0x2      // Enumerate only assembly supplied evidence
1801             }
1802
1803             internal EvidenceEnumerator(Evidence evidence, Category category)
1804             {
1805                 Contract.Assert(evidence != null);
1806                 Contract.Assert(evidence.IsReaderLockHeld);
1807
1808                 m_evidence = evidence;
1809                 m_category = category;
1810                 ResetNoLock();
1811             }
1812
1813             public bool MoveNext()
1814             {
1815                 IEnumerator currentEnumerator = CurrentEnumerator;
1816
1817                 // No more enumerators means we can't go any further
1818                 if (currentEnumerator == null)
1819                 {
1820                     m_currentEvidence = null;
1821                     return false;
1822                 }
1823
1824                 // See if the current enumerator can continue
1825                 if (currentEnumerator.MoveNext())
1826                 {
1827                     //
1828                     // If we've found an adapter for legacy evidence, we need to unwrap it for it to be the
1829                     // current enumerator's value.  For wrapped evidence, this is a simple unwrap, for a list of
1830                     // evidence, we need to make that the current enumerator and get its first value.
1831                     // 
1832
1833                     LegacyEvidenceWrapper legacyWrapper = currentEnumerator.Current as LegacyEvidenceWrapper;
1834                     LegacyEvidenceList legacyList = currentEnumerator.Current as LegacyEvidenceList;
1835
1836                     if (legacyWrapper != null)
1837                     {
1838                         m_currentEvidence = legacyWrapper.EvidenceObject;
1839                     }
1840                     else if (legacyList != null)
1841                     {
1842                         IEnumerator legacyListEnumerator = legacyList.GetEnumerator();
1843                         m_enumerators.Push(legacyListEnumerator);
1844                         MoveNext();
1845                     }
1846                     else
1847                     {
1848                         m_currentEvidence = currentEnumerator.Current;
1849                     }
1850
1851                     BCLDebug.Assert(m_currentEvidence != null, "m_currentEvidence != null");
1852                     return true;
1853                 }
1854                 else
1855                 {
1856                     // If we've reached the end of the current enumerator, move to the next one and try again
1857                     m_enumerators.Pop();
1858                     return MoveNext();
1859                 }
1860             }
1861
1862             public object Current
1863             {
1864                 get { return m_currentEvidence; }
1865             }
1866
1867             private IEnumerator CurrentEnumerator
1868             {
1869                 get
1870                 {
1871                     return m_enumerators.Count > 0 ? m_enumerators.Peek() as IEnumerator : null;
1872                 }
1873             }
1874
1875             public void Reset()
1876             {
1877                 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
1878                 {
1879                     ResetNoLock();
1880                 }
1881             }
1882
1883             private void ResetNoLock()
1884             {
1885                 Contract.Assert(m_evidence != null);
1886                 Contract.Assert(m_evidence.IsReaderLockHeld);
1887
1888                 m_currentEvidence = null;
1889                 m_enumerators = new Stack();
1890
1891                 if ((m_category & Category.Host) == Category.Host)
1892                 {
1893                     m_enumerators.Push(m_evidence.GetRawHostEvidenceEnumerator());
1894                 }
1895                 if ((m_category & Category.Assembly) == Category.Assembly)
1896                 {
1897                     m_enumerators.Push(m_evidence.GetRawAssemblyEvidenceEnumerator());
1898                 }
1899             }
1900         }
1901 #endif //!FEATURE_CORECLR && FEATURE_RWLOCK
1902     }
1903 }