3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</OWNER>
9 namespace System.Security.Policy
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.Configuration.Assemblies;
15 using System.Diagnostics.Contracts;
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;
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.
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.
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.
50 public sealed class Evidence
51 #if FEATURE_CAS_POLICY
53 #endif // FEATURE_CAS_POLICY
55 #if !FEATURE_CORECLR && FEATURE_RWLOCK
56 #if FEATURE_SERIALIZATION
57 [OptionalField(VersionAdded = 4)]
58 private Dictionary<Type, EvidenceTypeDescriptor> m_evidence;
60 [OptionalField(VersionAdded = 4)]
61 private bool m_deserializedTargetEvidence;
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
74 private ReaderWriterLock m_evidenceLock;
77 private uint m_version;
80 private IRuntimeEvidenceFactory m_target;
82 private bool m_locked;
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
88 private WeakReference m_cloneOrigin;
90 private static volatile Type[] s_runtimeEvidenceTypes;
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.
96 private enum DuplicateEvidenceAction
98 Throw, // Throw an exception
99 Merge, // Create a list of all the evidence objects
100 SelectNewObject // The newly added object wins
103 #if FEATURE_CAS_POLICY
106 m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
107 m_evidenceLock = new ReaderWriterLock();
109 #endif // FEATURE_CAS_POLICY
112 /// Create a deep copy of an evidence object
114 public Evidence(Evidence evidence)
116 m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
118 if (evidence != null)
120 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(evidence, EvidenceLockHolder.LockType.Reader))
122 foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in evidence.m_evidence)
124 EvidenceTypeDescriptor cloneDescriptor = evidenceType.Value;
125 if (cloneDescriptor != null)
127 cloneDescriptor = cloneDescriptor.Clone();
130 m_evidence[evidenceType.Key] = cloneDescriptor;
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
139 // see code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence
140 if (evidence.Target != null)
142 m_cloneOrigin = new WeakReference(evidence);
147 // see code:System.Security.Policy.Evidence#EvidenceLock
148 m_evidenceLock = new ReaderWriterLock();
151 [Obsolete("This constructor is obsolete. Please use the constructor which takes arrays of EvidenceBase instead.")]
152 public Evidence(object[] hostEvidence, object[] assemblyEvidence)
154 m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
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)
161 foreach (object hostEvidenceObject in hostEvidence)
163 AddHost(hostEvidenceObject);
167 if (assemblyEvidence != null)
169 foreach (object assemblyEvidenceObject in assemblyEvidence)
171 AddAssembly(assemblyEvidenceObject);
174 #pragma warning restore 618
176 // see code:System.Security.Policy.Evidence#EvidenceLock
177 m_evidenceLock = new ReaderWriterLock();
180 public Evidence(EvidenceBase[] hostEvidence, EvidenceBase[] assemblyEvidence)
182 m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
184 if (hostEvidence != null)
186 foreach (EvidenceBase hostEvidenceObject in hostEvidence)
188 AddHostEvidence(hostEvidenceObject, GetEvidenceIndexType(hostEvidenceObject), DuplicateEvidenceAction.Throw);
192 if (assemblyEvidence != null)
194 foreach (EvidenceBase assemblyEvidenceObject in assemblyEvidence)
196 AddAssemblyEvidence(assemblyEvidenceObject, GetEvidenceIndexType(assemblyEvidenceObject), DuplicateEvidenceAction.Throw);
200 // see code:System.Security.Policy.Evidence#EvidenceLock
201 m_evidenceLock = new ReaderWriterLock();
205 /// Create an empty evidence collection which will contain evidence for a specific assembly or
208 [SecuritySafeCritical]
209 internal Evidence(IRuntimeEvidenceFactory target)
211 Contract.Assert(target != null);
213 m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
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)
219 BCLDebug.Assert(typeof(EvidenceBase).IsAssignableFrom(runtimeEvidenceType), "All runtime evidence types should be EvidenceBases");
220 m_evidence[runtimeEvidenceType] = null;
223 QueryHostForPossibleEvidenceTypes();
225 // see code:System.Security.Policy.Evidence#EvidenceLock
226 m_evidenceLock = new ReaderWriterLock();
229 internal static Type[] RuntimeEvidenceTypes
233 if (s_runtimeEvidenceTypes == null)
235 Type[] runtimeEvidenceTypes = new Type[]
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),
248 #endif // FEATURE_CAS_POLICY
255 #if FEATURE_CAS_POLICY
256 // We only supply permission request evidence in legacy CAS mode
257 if (AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled)
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
265 #endif // FEATURE_CAS_POLICY
267 s_runtimeEvidenceTypes = runtimeEvidenceTypes;
270 return s_runtimeEvidenceTypes;
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.
281 // The nested EvidenceLockHolder and EvidenceUpgradeLockHolder utility classes can be used to wrap
282 // these methods when acquiring and releasing the evidence lock.
285 // Millisecond timeout when waiting to acquire the evidence lock
286 private const int LockTimeout = 5000;
288 private bool IsReaderLockHeld
290 get { return m_evidenceLock == null || m_evidenceLock.IsReaderLockHeld; }
293 private bool IsWriterLockHeld
295 get { return m_evidenceLock == null || m_evidenceLock.IsWriterLockHeld; }
298 private void AcquireReaderLock()
300 Contract.Assert(m_evidenceLock == null || !IsReaderLockHeld);
302 if (m_evidenceLock != null)
304 m_evidenceLock.AcquireReaderLock(LockTimeout);
308 private void AcquireWriterlock()
310 Contract.Assert(m_evidenceLock == null || !IsWriterLockHeld);
312 if (m_evidenceLock != null)
314 m_evidenceLock.AcquireWriterLock(LockTimeout);
318 private void DowngradeFromWriterLock(ref LockCookie lockCookie)
320 Contract.Assert(IsWriterLockHeld);
321 if (m_evidenceLock != null)
323 m_evidenceLock.DowngradeFromWriterLock(ref lockCookie);
327 private LockCookie UpgradeToWriterLock()
329 Contract.Assert(IsReaderLockHeld);
330 return m_evidenceLock != null ? m_evidenceLock.UpgradeToWriterLock(LockTimeout) : new LockCookie();
333 private void ReleaseReaderLock()
335 Contract.Assert(IsReaderLockHeld);
337 if (m_evidenceLock != null)
339 m_evidenceLock.ReleaseReaderLock();
343 private void ReleaseWriterLock()
345 Contract.Assert(IsWriterLockHeld);
347 if (m_evidenceLock != null)
349 m_evidenceLock.ReleaseWriterLock();
353 [Obsolete("This method is obsolete. Please use AddHostEvidence instead.")]
354 [SecuritySafeCritical]
355 public void AddHost(object id)
358 throw new ArgumentNullException("id");
359 if (!id.GetType().IsSerializable)
360 throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id");
361 Contract.EndContractBlock();
365 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
368 EvidenceBase evidence = WrapLegacyEvidence(id);
369 Type evidenceIndex = GetEvidenceIndexType(evidence);
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);
376 [Obsolete("This method is obsolete. Please use AddAssemblyEvidence instead.")]
377 public void AddAssembly(object id)
380 throw new ArgumentNullException("id");
381 if (!id.GetType().IsSerializable)
382 throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id");
383 Contract.EndContractBlock();
385 EvidenceBase evidence = WrapLegacyEvidence(id);
386 Type evidenceIndex = GetEvidenceIndexType(evidence);
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);
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.
398 public void AddAssemblyEvidence<T>(T evidence) where T : EvidenceBase
400 if (evidence == null)
401 throw new ArgumentNullException("evidence");
402 Contract.EndContractBlock();
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)
410 evidenceType = GetEvidenceIndexType(evidence);
413 AddAssemblyEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
416 private void AddAssemblyEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
418 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
420 AddAssemblyEvidenceNoLock(evidence, evidenceType, duplicateAction);
424 private void AddAssemblyEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
426 Contract.Assert(IsWriterLockHeld);
427 Contract.Assert(evidence != null);
428 Contract.Assert(evidenceType != null);
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();
435 EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true);
438 if (descriptor.AssemblyEvidence == null)
440 descriptor.AssemblyEvidence = evidence;
444 descriptor.AssemblyEvidence = HandleDuplicateEvidence(descriptor.AssemblyEvidence,
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.
455 public void AddHostEvidence<T>(T evidence) where T : EvidenceBase
457 if (evidence == null)
458 throw new ArgumentNullException("evidence");
459 Contract.EndContractBlock();
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)
467 evidenceType = GetEvidenceIndexType(evidence);
470 AddHostEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
473 [SecuritySafeCritical]
474 private void AddHostEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
476 Contract.Assert(evidence != null);
477 Contract.Assert(evidenceType != null);
481 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
484 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
486 AddHostEvidenceNoLock(evidence, evidenceType, duplicateAction);
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.
494 private void AddHostEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
496 Contract.Assert(IsWriterLockHeld);
497 Contract.Assert(evidence != null);
498 Contract.Assert(evidenceType != null);
500 EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true);
503 if (descriptor.HostEvidence == null)
505 descriptor.HostEvidence = evidence;
509 descriptor.HostEvidence = HandleDuplicateEvidence(descriptor.HostEvidence,
516 /// Ask the host for the types of evidence that it might provide if it is asked.
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.
523 private void QueryHostForPossibleEvidenceTypes()
525 #if FEATURE_CAS_POLICY
526 Contract.Assert(IsWriterLockHeld);
528 // First check to see if we have a HostSecurityManager
529 if (AppDomain.CurrentDomain.DomainManager != null)
531 HostSecurityManager hsm = AppDomain.CurrentDomain.DomainManager.HostSecurityManager;
534 Type[] hostSuppliedTypes = null;
536 AppDomain targetDomain = m_target.Target as AppDomain;
537 Assembly targetAssembly = m_target.Target as Assembly;
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.
544 if (targetAssembly != null &&
545 (hsm.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) == HostSecurityManagerOptions.HostAssemblyEvidence)
547 hostSuppliedTypes = hsm.GetHostSuppliedAssemblyEvidenceTypes(targetAssembly);
549 else if (targetDomain != null &&
550 (hsm.Flags & HostSecurityManagerOptions.HostAppDomainEvidence) == HostSecurityManagerOptions.HostAppDomainEvidence)
552 hostSuppliedTypes = hsm.GetHostSuppliedAppDomainEvidenceTypes();
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.
560 if (hostSuppliedTypes != null)
562 foreach (Type hostEvidenceType in hostSuppliedTypes)
564 EvidenceTypeDescriptor evidenceDescriptor = GetEvidenceTypeDescriptor(hostEvidenceType, true);
565 evidenceDescriptor.HostCanGenerate = true;
570 #endif // FEATURE_CAS_POLICY
573 internal bool IsUnmodified
575 get { return m_version == 0; }
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.
583 /// This lock is not the same as the synchronization lock that gates access to the evidence collection.
592 [SecuritySafeCritical]
597 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
609 /// Target of any delay generated evidence objects
611 internal IRuntimeEvidenceFactory Target
613 get { return m_target; }
616 // There are two retargeting scenarios supported:
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.
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
634 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
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();
646 /// Get the type that would be used to index into the evidence dictionary for this object
648 private static Type GetEvidenceIndexType(EvidenceBase evidence)
650 Contract.Assert(evidence != null);
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.
657 ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter;
658 return adapter == null ? evidence.GetType() : adapter.EvidenceType;
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
666 internal EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType)
668 return GetEvidenceTypeDescriptor(evidenceType, false);
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
677 private EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType, bool addIfNotExist)
679 Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
680 Contract.Assert(evidenceType != null);
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)
689 // If we haven't yet created a descriptor for this type then create one now
690 if (descriptor == null)
692 descriptor = new EvidenceTypeDescriptor();
694 descriptor.SetEvidenceType(evidenceType);
697 bool upgradedLock = false;
698 LockCookie upgradeCookie = new LockCookie();
701 if (!IsWriterLockHeld)
703 upgradeCookie = UpgradeToWriterLock();
707 m_evidence[evidenceType] = descriptor;
712 DowngradeFromWriterLock(ref upgradeCookie);
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
724 private static EvidenceBase HandleDuplicateEvidence(EvidenceBase original,
725 EvidenceBase duplicate,
726 DuplicateEvidenceAction action)
728 Contract.Assert(original != null);
729 Contract.Assert(duplicate != null);
730 Contract.Assert(original.GetType() == duplicate.GetType() || original.GetType() == typeof(LegacyEvidenceList));
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));
738 // SelectNewObject - MergeWithNoDuplicates behavior - the duplicate object wins
739 case DuplicateEvidenceAction.SelectNewObject:
742 // Merge - compat behavior. Merge the old and new evidence into a list so that both may exist
743 case DuplicateEvidenceAction.Merge:
745 LegacyEvidenceList list = original as LegacyEvidenceList;
748 list = new LegacyEvidenceList();
756 BCLDebug.Assert(false, "Uknown DuplicateEvidenceAction");
762 /// Wrap evidence we recieved through a legacy API to ensure that it is stored in an EvidenceBase
764 private static EvidenceBase WrapLegacyEvidence(object evidence)
766 Contract.Assert(evidence != null);
768 EvidenceBase wrappedEvidence = evidence as EvidenceBase;
769 if (wrappedEvidence == null)
771 wrappedEvidence = new LegacyEvidenceWrapper(evidence);
774 return wrappedEvidence;
778 /// Upwrap evidence stored in a legacy adapter.
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.
785 private static object UnwrapEvidence(EvidenceBase evidence)
787 ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter;
788 return adapter == null ? evidence : adapter.EvidenceObject;
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.
796 [SecuritySafeCritical]
797 public void Merge(Evidence evidence)
799 if (evidence == null)
804 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
806 bool checkedLock = false;
807 IEnumerator hostEnumerator = evidence.GetHostEnumerator();
808 while (hostEnumerator.MoveNext())
810 if (Locked && !checkedLock)
812 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
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))
822 GetHostEvidenceNoLock(hostEvidenceType);
825 EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
826 AddHostEvidenceNoLock(hostEvidence,
827 GetEvidenceIndexType(hostEvidence),
828 DuplicateEvidenceAction.Merge);
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())
836 EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
837 AddAssemblyEvidenceNoLock(assemblyEvidence,
838 GetEvidenceIndexType(assemblyEvidence),
839 DuplicateEvidenceAction.Merge);
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
849 internal void MergeWithNoDuplicates(Evidence evidence)
851 if (evidence == null)
856 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
858 IEnumerator hostEnumerator = evidence.GetHostEnumerator();
859 while (hostEnumerator.MoveNext())
861 EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
862 AddHostEvidenceNoLock(hostEvidence,
863 GetEvidenceIndexType(hostEvidence),
864 DuplicateEvidenceAction.SelectNewObject);
867 IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator();
868 while (assemblyEnumerator.MoveNext())
870 EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
871 AddAssemblyEvidenceNoLock(assemblyEvidence,
872 GetEvidenceIndexType(assemblyEvidence),
873 DuplicateEvidenceAction.SelectNewObject);
878 #if FEATURE_SERIALIZATION
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.
886 [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
887 private void OnSerializing(StreamingContext context)
889 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
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))
894 GetHostEvidenceNoLock(evidenceType);
897 // Also ensure that all serialized assembly evidence has been created
898 DeserializeTargetEvidence();
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())
909 hostList.Add(hostEnumerator.Current);
911 m_hostList = hostList;
913 ArrayList assemblyList = new ArrayList();
914 IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
915 while (assemblyEnumerator.MoveNext())
917 assemblyList.Add(assemblyEnumerator.Current);
919 m_assemblyList = assemblyList;
923 /// Finish deserializing legacy evidence
928 private void OnDeserialized(StreamingContext context)
930 // Look at host and assembly evidence lists only if we serialized using Whidbey.
931 if (m_evidence == null)
933 m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>();
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)
940 foreach (object evidenceObject in m_hostList)
942 if (evidenceObject != null)
944 AddHost(evidenceObject);
951 if (m_assemblyList != null)
953 foreach (object evidenceObject in m_assemblyList)
955 if (evidenceObject != null)
957 AddAssembly(evidenceObject);
961 m_assemblyList = null;
963 #pragma warning restore 618
966 // see code:System.Security.Policy.Evidence#EvidenceLock
967 m_evidenceLock = new ReaderWriterLock();
969 #endif // FEATURE_SERIALIZATION
972 /// Load any serialized evidence out of the target assembly into our evidence collection.
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.
978 private void DeserializeTargetEvidence()
980 #if FEATURE_SERIALIZATION
981 Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
983 if (m_target != null && !m_deserializedTargetEvidence)
985 bool upgradedLock = false;
986 LockCookie lockCookie = new LockCookie();
989 if (!IsWriterLockHeld)
991 lockCookie = UpgradeToWriterLock();
995 // Set this to true here because AddAssemblyEvidenceNoLock will attempt to reenter this
996 // method creating possible infinite recursion.
997 m_deserializedTargetEvidence = true;
999 foreach (EvidenceBase targetEvidence in m_target.GetFactorySuppliedEvidence())
1001 AddAssemblyEvidenceNoLock(targetEvidence, GetEvidenceIndexType(targetEvidence), DuplicateEvidenceAction.Throw);
1007 DowngradeFromWriterLock(ref lockCookie);
1010 #endif // FEATURE_SERIALIZATION
1013 #if FEATURE_SERIALIZATION
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.
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.
1024 internal byte[] RawSerialize()
1028 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
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)
1034 if (evidenceType.Value != null && evidenceType.Value.HostEvidence != null)
1036 generatedEvidence[evidenceType.Key] = evidenceType.Value.HostEvidence;
1040 using (MemoryStream serializationStream = new MemoryStream())
1042 BinaryFormatter formatter = new BinaryFormatter();
1043 formatter.Serialize(serializationStream, generatedEvidence);
1044 return serializationStream.ToArray();
1048 catch (SecurityException)
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
1055 #endif // FEATURE_SERIALIZATION
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.
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)
1067 throw new ArgumentNullException("array");
1068 if (index < 0 || index > array.Length - Count)
1069 throw new ArgumentOutOfRangeException("index");
1070 Contract.EndContractBlock();
1072 int currentIndex = index;
1074 IEnumerator hostEnumerator = GetHostEnumerator();
1075 while (hostEnumerator.MoveNext())
1077 array.SetValue(hostEnumerator.Current, currentIndex);
1081 IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
1082 while (assemblyEnumerator.MoveNext())
1084 array.SetValue(assemblyEnumerator.Current, currentIndex);
1089 public IEnumerator GetHostEnumerator()
1091 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1093 return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host);
1097 public IEnumerator GetAssemblyEnumerator()
1099 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1101 DeserializeTargetEvidence();
1102 return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Assembly);
1107 /// Get an enumerator that can iterate over the raw evidence objects stored for the assembly
1109 internal RawEvidenceEnumerator GetRawAssemblyEvidenceEnumerator()
1111 Contract.Assert(IsReaderLockHeld);
1112 DeserializeTargetEvidence();
1113 return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), false);
1117 /// Get an enumerator that can iterate over the raw evidence objects stored for the host
1119 /// <returns></returns>
1120 internal RawEvidenceEnumerator GetRawHostEvidenceEnumerator()
1122 Contract.Assert(IsReaderLockHeld);
1123 return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), true);
1126 [Obsolete("GetEnumerator is obsolete. Please use GetAssemblyEnumerator and GetHostEnumerator instead.")]
1127 public IEnumerator GetEnumerator()
1129 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1131 return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host | EvidenceEnumerator.Category.Assembly);
1136 /// Get a specific type of assembly supplied evidence
1139 public T GetAssemblyEvidence<T>() where T : EvidenceBase
1141 return UnwrapEvidence(GetAssemblyEvidence(typeof(T))) as T;
1144 internal EvidenceBase GetAssemblyEvidence(Type type)
1146 Contract.Assert(type != null);
1148 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1150 return GetAssemblyEvidenceNoLock(type);
1154 private EvidenceBase GetAssemblyEvidenceNoLock(Type type)
1156 Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
1157 Contract.Assert(type != null);
1159 DeserializeTargetEvidence();
1160 EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type);
1161 if (descriptor != null)
1163 return descriptor.AssemblyEvidence;
1170 /// Get a specific type of host supplied evidence
1173 public T GetHostEvidence<T>() where T : EvidenceBase
1175 return UnwrapEvidence(GetHostEvidence(typeof(T))) as T;
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.
1182 internal T GetDelayEvaluatedHostEvidence<T>() where T : EvidenceBase, IDelayEvaluatedEvidence
1184 return UnwrapEvidence(GetHostEvidence(typeof(T), false)) as T;
1187 internal EvidenceBase GetHostEvidence(Type type)
1189 Contract.Assert(type != null);
1191 return GetHostEvidence(type, true);
1194 [SecuritySafeCritical]
1195 private EvidenceBase GetHostEvidence(Type type, bool markDelayEvaluatedEvidenceUsed)
1197 Contract.Assert(type != null);
1199 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1201 EvidenceBase evidence = GetHostEvidenceNoLock(type);
1203 if (markDelayEvaluatedEvidenceUsed)
1205 IDelayEvaluatedEvidence delayEvidence = evidence as IDelayEvaluatedEvidence;
1206 if (delayEvidence != null)
1208 delayEvidence.MarkUsed();
1217 /// Get host supplied evidence from the collection
1219 /// We attempt to find host evdience in the following order:
1221 /// 1. Already generated or explicitly supplied evidence
1222 /// 2. Evidence supplied by the CLR host
1223 /// 3. Evidence supplied by the CLR itself
1226 private EvidenceBase GetHostEvidenceNoLock(Type type)
1228 Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
1229 Contract.Assert(type != null);
1231 EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type);
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)
1240 // If the evidence has already been generated or if it was explicitly provided then return that
1241 if (descriptor.HostEvidence != null)
1243 return descriptor.HostEvidence;
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)
1250 using (EvidenceUpgradeLockHolder lockHolder = new EvidenceUpgradeLockHolder(this))
1252 // Make sure that we don't attempt to generate this type of evidencea again if we fail to
1254 descriptor.Generated = true;
1256 EvidenceBase generatedEvidence = GenerateHostEvidence(type, descriptor.HostCanGenerate);
1257 if (generatedEvidence != null)
1259 descriptor.HostEvidence = generatedEvidence;
1262 // #BackpatchGeneratedEvidence
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.
1272 Evidence cloneOrigin = m_cloneOrigin != null ? m_cloneOrigin.Target as Evidence : null;
1273 if (cloneOrigin != null)
1275 BCLDebug.Assert(cloneOrigin.Target != null && cloneOrigin.Target == Target,
1276 "Attempt to backpatch evidence to a collection with a different target.");
1278 using (EvidenceLockHolder cloneLockHolder = new EvidenceLockHolder(cloneOrigin, EvidenceLockHolder.LockType.Writer))
1280 EvidenceTypeDescriptor cloneDescriptor = cloneOrigin.GetEvidenceTypeDescriptor(type);
1281 if (cloneDescriptor != null && cloneDescriptor.HostEvidence == null)
1283 cloneDescriptor.HostEvidence = generatedEvidence.Clone() as EvidenceBase;
1290 return generatedEvidence;
1294 // The evidence could not be generated and was not found
1299 /// Attempt to generate host evidence on demand via calls to the runtime host or the evidence facotry
1302 private EvidenceBase GenerateHostEvidence(Type type, bool hostCanGenerate)
1304 Contract.Assert(type != null);
1305 Contract.Assert(IsWriterLockHeld);
1307 #if FEATURE_CAS_POLICY
1308 // First let the host generate the evidence if it can.
1309 if (hostCanGenerate)
1311 AppDomain targetDomain = m_target.Target as AppDomain;
1312 Assembly targetAssembly = m_target.Target as Assembly;
1314 EvidenceBase hostEvidence = null;
1315 if (targetDomain != null)
1317 hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAppDomainEvidence(type);
1319 else if (targetAssembly != null)
1321 hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAssemblyEvidence(type, targetAssembly);
1324 // If the host generated the evidence, verify that it generated the evidence we expected
1326 if (hostEvidence != null)
1328 if (!type.IsAssignableFrom(hostEvidence.GetType()))
1330 string hostType = AppDomain.CurrentDomain.HostSecurityManager.GetType().FullName;
1331 string recievedType = hostEvidence.GetType().FullName;
1332 string requestedType = type.FullName;
1334 throw new InvalidOperationException(Environment.GetResourceString("Policy_IncorrectHostEvidence", hostType, recievedType, requestedType));
1337 return hostEvidence;
1340 #endif // FEATURE_CAS_POLICY
1342 // Finally, check to see if the CLR can generate the evidence
1343 return m_target.GenerateEvidence(type);
1346 [Obsolete("Evidence should not be treated as an ICollection. Please use GetHostEnumerator and GetAssemblyEnumerator to iterate over the evidence to collect a count.")]
1353 IEnumerator hostEvidence = GetHostEnumerator();
1354 while (hostEvidence.MoveNext())
1359 IEnumerator assemblyEvidence = GetAssemblyEnumerator();
1360 while (assemblyEvidence.MoveNext())
1370 /// Get the number of pieces of evidence which are currently generated, without causing any
1371 /// lazily generated evidence to be created.
1374 internal int RawCount
1380 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1382 foreach (Type evidenceType in new List<Type>(m_evidence.Keys))
1384 EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType);
1386 if (descriptor != null)
1388 if (descriptor.AssemblyEvidence != null)
1392 if (descriptor.HostEvidence != null)
1404 public Object SyncRoot
1406 get { return this; }
1409 public bool IsSynchronized
1411 get { return true; }
1414 public bool IsReadOnly
1416 get { return false; }
1419 #if FEATURE_CAS_POLICY
1421 public Evidence Clone()
1423 return new Evidence(this);
1425 #endif // FEATURE_CAS_POLICY
1428 [SecuritySafeCritical]
1433 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
1436 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
1444 [SecuritySafeCritical]
1445 public void RemoveType(Type t)
1448 throw new ArgumentNullException("t");
1449 Contract.EndContractBlock();
1451 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
1453 EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(t);
1454 if (descriptor != null)
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))
1463 new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
1466 m_evidence.Remove(t);
1472 /// Mark all of the already generated evidence in the collection as having been used during a
1473 /// policy evaluation.
1475 internal void MarkAllEvidenceAsUsed()
1477 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1479 foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in m_evidence)
1481 if (evidenceType.Value != null)
1483 IDelayEvaluatedEvidence hostEvidence = evidenceType.Value.HostEvidence as IDelayEvaluatedEvidence;
1484 if (hostEvidence != null)
1486 hostEvidence.MarkUsed();
1489 IDelayEvaluatedEvidence assemblyEvidence = evidenceType.Value.AssemblyEvidence as IDelayEvaluatedEvidence;
1490 if (assemblyEvidence != null)
1492 assemblyEvidence.MarkUsed();
1499 #if FEATURE_CAS_POLICY
1501 /// Determine if delay evaluated strong name evidence is contained in this collection, and if so
1502 /// if it was used during policy evaluation.
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.
1509 private bool WasStrongNameEvidenceUsed()
1511 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
1513 EvidenceTypeDescriptor snTypeDescriptor = GetEvidenceTypeDescriptor(typeof(StrongName));
1514 if (snTypeDescriptor != null)
1516 IDelayEvaluatedEvidence snEvidence = snTypeDescriptor.HostEvidence as IDelayEvaluatedEvidence;
1517 return snEvidence != null && snEvidence.WasUsed;
1523 #endif // FEATURE_CAS_POLICY
1526 /// Utility class to wrap acquiring a lock onto the evidence collection
1528 private class EvidenceLockHolder : IDisposable
1530 private Evidence m_target;
1531 private LockType m_lockType;
1533 public enum LockType
1539 public EvidenceLockHolder(Evidence target, LockType lockType)
1541 Contract.Assert(target != null);
1542 Contract.Assert(lockType == LockType.Reader || lockType == LockType.Writer);
1545 m_lockType = lockType;
1547 if (m_lockType == LockType.Reader)
1549 m_target.AcquireReaderLock();
1553 m_target.AcquireWriterlock();
1557 public void Dispose()
1559 if (m_lockType == LockType.Reader && m_target.IsReaderLockHeld)
1561 m_target.ReleaseReaderLock();
1563 else if (m_lockType == LockType.Writer && m_target.IsWriterLockHeld)
1565 m_target.ReleaseWriterLock();
1571 /// Utility class to wrap upgrading an acquired reader lock to a writer lock and then
1572 /// downgrading it back to a reader lock.
1574 private class EvidenceUpgradeLockHolder : IDisposable
1576 private Evidence m_target;
1577 private LockCookie m_cookie;
1579 public EvidenceUpgradeLockHolder(Evidence target)
1581 Contract.Assert(target != null);
1584 m_cookie = m_target.UpgradeToWriterLock();
1587 public void Dispose()
1589 if (m_target.IsWriterLockHeld)
1591 m_target.DowngradeFromWriterLock(ref m_cookie);
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.
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.
1605 internal sealed class RawEvidenceEnumerator : IEnumerator<EvidenceBase>
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;
1611 private Type[] m_evidenceTypes;
1612 private int m_typeIndex;
1613 private EvidenceBase m_currentEvidence;
1615 private static volatile List<Type> s_expensiveEvidence;
1617 public RawEvidenceEnumerator(Evidence evidence, IEnumerable<Type> evidenceTypes, bool hostEnumerator)
1619 Contract.Assert(evidence != null);
1620 Contract.Assert(evidenceTypes != null);
1622 m_evidence = evidence;
1623 m_hostEnumerator = hostEnumerator;
1624 m_evidenceTypes = GenerateEvidenceTypes(evidence, evidenceTypes, hostEnumerator);
1625 m_evidenceVersion = evidence.m_version;
1630 public EvidenceBase Current
1634 if (m_evidence.m_version != m_evidenceVersion)
1635 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1637 return m_currentEvidence;
1641 object IEnumerator.Current
1645 if (m_evidence.m_version != m_evidenceVersion)
1646 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1648 return m_currentEvidence;
1653 /// List of types of evidence that we would like to avoid generating if possible
1655 private static List<Type> ExpensiveEvidence
1659 if (s_expensiveEvidence == null)
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;
1669 List<Type> runtimeTypes = new List<Type>(Evidence.RuntimeEvidenceTypes);
1670 foreach (Type expensiveType in s_expensiveEvidence)
1672 BCLDebug.Assert(runtimeTypes.Contains(expensiveType),
1673 "Evidence type not generated by the runtime found in expensive evidence type list");
1678 return s_expensiveEvidence;
1682 public void Dispose()
1688 /// Generate the array of types of evidence that could have values for
1690 private static Type[] GenerateEvidenceTypes(Evidence evidence,
1691 IEnumerable<Type> evidenceTypes,
1694 Contract.Assert(evidence != null);
1695 Contract.Assert(evidenceTypes != null);
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.
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.
1707 List<Type> alreadyGeneratedList = new List<Type>();
1708 List<Type> inexpensiveList = new List<Type>();
1709 List<Type> expensiveList = new List<Type>(ExpensiveEvidence.Count);
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)
1716 EvidenceTypeDescriptor descriptor = evidence.GetEvidenceTypeDescriptor(evidenceType);
1717 BCLDebug.Assert(descriptor != null, "descriptor != null");
1719 bool alreadyGenerated = (hostEvidence && descriptor.HostEvidence != null) ||
1720 (!hostEvidence && descriptor.AssemblyEvidence != null);
1722 if (alreadyGenerated)
1724 alreadyGeneratedList.Add(evidenceType);
1726 else if (ExpensiveEvidence.Contains(evidenceType))
1728 expensiveList.Add(evidenceType);
1732 inexpensiveList.Add(evidenceType);
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);
1741 return enumerationTypes;
1744 [SecuritySafeCritical]
1745 public bool MoveNext()
1747 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
1749 if (m_evidence.m_version != m_evidenceVersion)
1750 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1752 m_currentEvidence = null;
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.
1760 if (m_typeIndex < m_evidenceTypes.Length)
1762 if (m_hostEnumerator)
1764 m_currentEvidence = m_evidence.GetHostEvidenceNoLock(m_evidenceTypes[m_typeIndex]);
1768 m_currentEvidence = m_evidence.GetAssemblyEvidenceNoLock(m_evidenceTypes[m_typeIndex]);
1772 while (m_typeIndex < m_evidenceTypes.Length && m_currentEvidence == null);
1775 return m_currentEvidence != null;
1780 if (m_evidence.m_version != m_evidenceVersion)
1781 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
1784 m_currentEvidence = null;
1788 private sealed class EvidenceEnumerator : IEnumerator
1790 private Evidence m_evidence;
1791 private Category m_category;
1792 private Stack m_enumerators;
1794 private object m_currentEvidence;
1797 internal enum Category
1799 Host = 0x1, // Enumerate only host supplied evidence
1800 Assembly = 0x2 // Enumerate only assembly supplied evidence
1803 internal EvidenceEnumerator(Evidence evidence, Category category)
1805 Contract.Assert(evidence != null);
1806 Contract.Assert(evidence.IsReaderLockHeld);
1808 m_evidence = evidence;
1809 m_category = category;
1813 public bool MoveNext()
1815 IEnumerator currentEnumerator = CurrentEnumerator;
1817 // No more enumerators means we can't go any further
1818 if (currentEnumerator == null)
1820 m_currentEvidence = null;
1824 // See if the current enumerator can continue
1825 if (currentEnumerator.MoveNext())
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.
1833 LegacyEvidenceWrapper legacyWrapper = currentEnumerator.Current as LegacyEvidenceWrapper;
1834 LegacyEvidenceList legacyList = currentEnumerator.Current as LegacyEvidenceList;
1836 if (legacyWrapper != null)
1838 m_currentEvidence = legacyWrapper.EvidenceObject;
1840 else if (legacyList != null)
1842 IEnumerator legacyListEnumerator = legacyList.GetEnumerator();
1843 m_enumerators.Push(legacyListEnumerator);
1848 m_currentEvidence = currentEnumerator.Current;
1851 BCLDebug.Assert(m_currentEvidence != null, "m_currentEvidence != null");
1856 // If we've reached the end of the current enumerator, move to the next one and try again
1857 m_enumerators.Pop();
1862 public object Current
1864 get { return m_currentEvidence; }
1867 private IEnumerator CurrentEnumerator
1871 return m_enumerators.Count > 0 ? m_enumerators.Peek() as IEnumerator : null;
1877 using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
1883 private void ResetNoLock()
1885 Contract.Assert(m_evidence != null);
1886 Contract.Assert(m_evidence.IsReaderLockHeld);
1888 m_currentEvidence = null;
1889 m_enumerators = new Stack();
1891 if ((m_category & Category.Host) == Category.Host)
1893 m_enumerators.Push(m_evidence.GetRawHostEvidenceEnumerator());
1895 if ((m_category & Category.Assembly) == Category.Assembly)
1897 m_enumerators.Push(m_evidence.GetRawAssemblyEvidenceEnumerator());
1901 #endif //!FEATURE_CORECLR && FEATURE_RWLOCK