Evidence.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Security / Policy / Evidence.cs / 1305376 / Evidence.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
// [....]
// 
 
namespace System.Security.Policy
{ 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Configuration.Assemblies; 
    using System.Diagnostics.Contracts;
    using System.IO; 
    using System.Reflection; 
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices; 
    using System.Runtime.Remoting;
#if FEATURE_SERIALIZATION
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary; 
#endif // FEATURE_SERIALIZATION
    using System.Security.Permissions; 
    using System.Security.Util; 
    using System.Threading;
    using Microsoft.Win32.SafeHandles; 

    /// 
    ///     The Evidence class keeps track of information that can be used to make security decisions about
    ///     an assembly or an AppDomain.  There are two types of evidence, one is supplied by the CLR or a 
    ///     host, the other supplied by the assembly itself.
    /// 
    ///     We keep a dictionary that maps each type of possbile evidence to an EvidenceTypeDescriptor which 
    ///     contains the evidence objects themselves if they exist as well as some extra metadata about that
    ///     type of evidence.  This dictionary is fully populated with keys for host evidence at all times and 
    ///     for assembly evidence the first time the application evidence is touched.  This means that if a
    ///     Type key does not exist in the dictionary, then that particular type of evidence will never be
    ///     given to the assembly or AppDomain in question as host evidence.  The only exception is if the
    ///     user later manually adds host evidence via the AddHostEvidence API. 
    ///
    ///     Assembly supplied evidence is created up front, however host supplied evidence may be lazily 
    ///     created.  In the lazy creation case, the Type will map to either an EvidenceTypeDescriptor that does 
    ///     not contain any evidence data or null.  As requests come in for that evidence, we'll populate the
    ///     EvidenceTypeDescriptor appropriately. 
    /// 
    [Serializable]
    [ComVisible(true)]
    public sealed class Evidence 
#if FEATURE_CAS_POLICY
 : ICollection 
#endif // FEATURE_CAS_POLICY 
    {
#if !FEATURE_CORECLR && FEATURE_RWLOCK 
#if FEATURE_SERIALIZATION
        [OptionalField(VersionAdded = 4)]
        private Dictionary m_evidence;
 
        [OptionalField(VersionAdded = 4)]
        private bool m_deserializedTargetEvidence; 
 
        // These fields are only used to deserialize v2.0 serialized versions of Evidence. It will be null
        // after the seriailzation process is complete, and should not be used. 
#pragma warning disable 414
        private volatile ArrayList m_hostList;
        private volatile ArrayList m_assemblyList;
#pragma warning restore 414 
#else // !FEATURE_SERIALIZATION
        private Dictionary m_evidence; 
#endif // FEATURE_SERIALIZATION 

        [NonSerialized] 
        private ReaderWriterLock m_evidenceLock;

        [NonSerialized]
        private uint m_version; 

        [NonSerialized] 
        private IRuntimeEvidenceFactory m_target; 

        private bool m_locked; 

        // If this evidence collection is a clone where we may need to backpatch to the original, this will
        // reference the collection it was cloned from.  See
        // code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence 
        [NonSerialized]
        private WeakReference m_cloneOrigin; 
 
        private static Type[] s_runtimeEvidenceTypes;
 
        /// 
        ///     Set of actions that we could perform if we detect that we are attempting to add evidence
        ///     when we already have evidence of that type stored.
        ///  
        private enum DuplicateEvidenceAction
        { 
            Throw,                  // Throw an exception 
            Merge,                  // Create a list of all the evidence objects
            SelectNewObject         // The newly added object wins 
        }

#if FEATURE_CAS_POLICY
        public Evidence() 
        {
            m_evidence = new Dictionary(); 
            m_evidenceLock = new ReaderWriterLock(); 
        }
#endif // FEATURE_CAS_POLICY 

        /// 
        ///     Create a deep copy of an evidence object
        ///  
        public Evidence(Evidence evidence)
        { 
            m_evidence = new Dictionary(); 

            if (evidence != null) 
            {
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(evidence, EvidenceLockHolder.LockType.Reader))
                {
                    foreach (KeyValuePair evidenceType in evidence.m_evidence) 
                    {
                        EvidenceTypeDescriptor cloneDescriptor = evidenceType.Value; 
                        if (cloneDescriptor != null) 
                        {
                            cloneDescriptor = cloneDescriptor.Clone(); 
                        }

                        m_evidence[evidenceType.Key] = cloneDescriptor;
                    } 

                    m_target = evidence.m_target; 
                    m_locked = evidence.m_locked; 
#if FEATURE_SERIALIZATION
                    m_deserializedTargetEvidence = evidence.m_deserializedTargetEvidence; 
#endif // FEATURE_SERIALIZATION

                    // see code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence
                    if (evidence.Target != null) 
                    {
                        m_cloneOrigin = new WeakReference(evidence); 
                    } 
                }
            } 

            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock();
        } 

        [Obsolete("This constructor is obsolete. Please use the constructor which takes arrays of EvidenceBase instead.")] 
        public Evidence(object[] hostEvidence, object[] assemblyEvidence) 
        {
            m_evidence = new Dictionary(); 

            // This is a legacy evidence entry point, so we add through the legacy add APIs in order to get
            // proper legacy wrapping and merge behavior.
#pragma warning disable 618 
            if (hostEvidence != null)
            { 
                foreach (object hostEvidenceObject in hostEvidence) 
                {
                    AddHost(hostEvidenceObject); 
                }
            }

            if (assemblyEvidence != null) 
            {
                foreach (object assemblyEvidenceObject in assemblyEvidence) 
                { 
                    AddAssembly(assemblyEvidenceObject);
                } 
            }
#pragma warning restore 618

            // see code:System.Security.Policy.Evidence#EvidenceLock 
            m_evidenceLock = new ReaderWriterLock();
        } 
 
        public Evidence(EvidenceBase[] hostEvidence, EvidenceBase[] assemblyEvidence)
        { 
            m_evidence = new Dictionary();

            if (hostEvidence != null)
            { 
                foreach (EvidenceBase hostEvidenceObject in hostEvidence)
                { 
                    AddHostEvidence(hostEvidenceObject, GetEvidenceIndexType(hostEvidenceObject), DuplicateEvidenceAction.Throw); 
                }
            } 

            if (assemblyEvidence != null)
            {
                foreach (EvidenceBase assemblyEvidenceObject in assemblyEvidence) 
                {
                    AddAssemblyEvidence(assemblyEvidenceObject, GetEvidenceIndexType(assemblyEvidenceObject), DuplicateEvidenceAction.Throw); 
                } 
            }
 
            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock();
        }
 
        /// 
        ///     Create an empty evidence collection which will contain evidence for a specific assembly or 
        ///     AppDomain 
        /// 
        [SecuritySafeCritical] 
        internal Evidence(IRuntimeEvidenceFactory target)
        {
            Contract.Assert(target != null);
 
            m_evidence = new Dictionary();
            m_target = target; 
 
            // Setup the types of evidence that the CLR can generate for a target as keys in the dictionary
            foreach (Type runtimeEvidenceType in RuntimeEvidenceTypes) 
            {
                BCLDebug.Assert(typeof(EvidenceBase).IsAssignableFrom(runtimeEvidenceType), "All runtime evidence types should be EvidenceBases");
                m_evidence[runtimeEvidenceType] = null;
            } 

            QueryHostForPossibleEvidenceTypes(); 
 
            // see code:System.Security.Policy.Evidence#EvidenceLock
            m_evidenceLock = new ReaderWriterLock(); 
        }

        internal static Type[] RuntimeEvidenceTypes
        { 
            get
            { 
                if (s_runtimeEvidenceTypes == null) 
                {
                    List runtimeEvidenceTypes = new List(new Type[] 
                    {
#if FEATURE_CLICKONCE
                        typeof(System.Runtime.Hosting.ActivationArguments),
#endif // FEATURE_CLICKONCE 
#if FEATURE_CAS_POLICY
                        typeof(ApplicationDirectory), 
#endif // FEATURE_CAS_POLICY 
                        typeof(ApplicationTrust),
#if FEATURE_CAS_POLICY 
                        typeof(GacInstalled),
                        typeof(Hash),
                        typeof(Publisher),
#endif // FEATURE_CAS_POLICY 
                        typeof(Site),
                        typeof(StrongName), 
                        typeof(Url), 
                        typeof(Zone)
                    }); 

#if FEATURE_CAS_POLICY
                    // We only supply permission request evidence in legacy CAS mode
                    if (AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled) 
                    {
#pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode 
                        runtimeEvidenceTypes.Add(typeof(PermissionRequestEvidence)); 
#pragma warning restore 618
                    } 
#endif // FEATURE_CAS_POLICY

                    s_runtimeEvidenceTypes = runtimeEvidenceTypes.ToArray();
                } 

                return s_runtimeEvidenceTypes; 
            } 
        }
 
        //
        // #EvidenceLock
        //
        // Evidence synchronization locking wrappers. In the case where the lock has not yet been created, 
        // we know that we're in the process of constructing the evidence collection and therefore we can
        // act as though the evidence is locked.  If there is a lock in place, then just delegate back to it. 
        // 
        // The nested EvidenceLockHolder and EvidenceUpgradeLockHolder utility classes can be used to wrap
        // these methods when acquiring and releasing the evidence lock. 
        //

        // Millisecond timeout when waiting to acquire the evidence lock
        private const int LockTimeout = 5000; 

        private bool IsReaderLockHeld 
        { 
            get { return m_evidenceLock == null || m_evidenceLock.IsReaderLockHeld; }
        } 

        private bool IsWriterLockHeld
        {
            get { return m_evidenceLock == null || m_evidenceLock.IsWriterLockHeld; } 
        }
 
        private void AcquireReaderLock() 
        {
            Contract.Assert(m_evidenceLock == null || !IsReaderLockHeld); 

            if (m_evidenceLock != null)
            {
                m_evidenceLock.AcquireReaderLock(LockTimeout); 
            }
        } 
 
        private void AcquireWriterlock()
        { 
            Contract.Assert(m_evidenceLock == null || !IsWriterLockHeld);

            if (m_evidenceLock != null)
            { 
                m_evidenceLock.AcquireWriterLock(LockTimeout);
            } 
        } 

        private void DowngradeFromWriterLock(ref LockCookie lockCookie) 
        {
            Contract.Assert(IsWriterLockHeld);
            if (m_evidenceLock != null)
            { 
                m_evidenceLock.DowngradeFromWriterLock(ref lockCookie);
            } 
        } 

        private LockCookie UpgradeToWriterLock() 
        {
            Contract.Assert(IsReaderLockHeld);
            return m_evidenceLock != null ? m_evidenceLock.UpgradeToWriterLock(LockTimeout) : new LockCookie();
        } 

        private void ReleaseReaderLock() 
        { 
            Contract.Assert(IsReaderLockHeld);
 
            if (m_evidenceLock != null)
            {
                m_evidenceLock.ReleaseReaderLock();
            } 
        }
 
        private void ReleaseWriterLock() 
        {
            Contract.Assert(IsWriterLockHeld); 

            if (m_evidenceLock != null)
            {
                m_evidenceLock.ReleaseWriterLock(); 
            }
        } 
 
        [Obsolete("This method is obsolete. Please use AddHostEvidence instead.")]
        [SecuritySafeCritical] 
        public void AddHost(object id)
        {
            if (id == null)
                throw new ArgumentNullException("id"); 
            if (!id.GetType().IsSerializable)
                throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id"); 
            Contract.EndContractBlock(); 

            if (m_locked) 
            {
                new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
            }
 
            EvidenceBase evidence = WrapLegacyEvidence(id);
            Type evidenceIndex = GetEvidenceIndexType(evidence); 
 
            // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey
            // APIs, then allow the evidences to merge together. 
            AddHostEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge);
        }

        [Obsolete("This method is obsolete. Please use AddAssemblyEvidence instead.")] 
        public void AddAssembly(object id)
        { 
            if (id == null) 
                throw new ArgumentNullException("id");
            if (!id.GetType().IsSerializable) 
                throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id");
            Contract.EndContractBlock();

            EvidenceBase evidence = WrapLegacyEvidence(id); 
            Type evidenceIndex = GetEvidenceIndexType(evidence);
 
            // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey 
            // APIs, then allow the evidences to merge together.
            AddAssemblyEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge); 
        }

        /// 
        ///     Add a piece of evidence to the assembly supplied evidence list. This method will disallow adding 
        ///     evidence if there is already evidence of that type in the assembly list.
        ///  
        [ComVisible(false)] 
        public void AddAssemblyEvidence(T evidence) where T : EvidenceBase
        { 
            if (evidence == null)
                throw new ArgumentNullException("evidence");
            Contract.EndContractBlock();
 
            // Index the evidence under the type that the Add function was called with, unless we were given
            // a plain EvidenceBase or a wrapped legacy evidence.  In that case, we need to index under a 
            // more specific type. 
            Type evidenceType = typeof(T);
            if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter) 
            {
                evidenceType = GetEvidenceIndexType(evidence);
            }
 
            AddAssemblyEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
        } 
 
        private void AddAssemblyEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
        { 
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            {
                AddAssemblyEvidenceNoLock(evidence, evidenceType, duplicateAction);
            } 
        }
 
        private void AddAssemblyEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction) 
        {
            Contract.Assert(IsWriterLockHeld); 
            Contract.Assert(evidence != null);
            Contract.Assert(evidenceType != null);

            // We need to make sure that any target supplied evidence is deserialized before adding to the 
            // Assembly collection in order to preserve the semantics that the evidence objects supplied by
            // the target are the original versions and evidence objects added via the APIs are the duplicates. 
            DeserializeTargetEvidence(); 

            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true); 

            ++m_version;
            if (descriptor.AssemblyEvidence == null)
            { 
                descriptor.AssemblyEvidence = evidence;
            } 
            else 
            {
                descriptor.AssemblyEvidence = HandleDuplicateEvidence(descriptor.AssemblyEvidence, 
                                                                      evidence,
                                                                      duplicateAction);
            }
        } 

        ///  
        ///     Add a piece of evidence to the host supplied evidence list. This method will disallow adding 
        ///     evidence if there is already evidence of that type in the host list.
        ///  
        [ComVisible(false)]
        public void AddHostEvidence(T evidence) where T : EvidenceBase
        {
            if (evidence == null) 
                throw new ArgumentNullException("evidence");
            Contract.EndContractBlock(); 
 
            // Index the evidence under the type that the Add function was called with, unless we were given
            // a plain EvidenceBase or a wrapped legacy evidence.  In that case, we need to index under a 
            // more specific type.
            Type evidenceType = typeof(T);
            if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter)
            { 
                evidenceType = GetEvidenceIndexType(evidence);
            } 
 
            AddHostEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw);
        } 

        [SecuritySafeCritical]
        private void AddHostEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
        { 
            Contract.Assert(evidence != null);
            Contract.Assert(evidenceType != null); 
 
            if (Locked)
            { 
                new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
            }

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) 
            {
                AddHostEvidenceNoLock(evidence, evidenceType, duplicateAction); 
            } 
        }
 
        /// 
        ///     Add evidence to the host supplied evidence collection without acquiring the evidence lock or
        ///     checking to make sure that the caller has permission to bypass locked evidence.
        ///  
        private void AddHostEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction)
        { 
            Contract.Assert(IsWriterLockHeld); 
            Contract.Assert(evidence != null);
            Contract.Assert(evidenceType != null); 

            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true);

            ++m_version; 
            if (descriptor.HostEvidence == null)
            { 
                descriptor.HostEvidence = evidence; 
            }
            else 
            {
                descriptor.HostEvidence = HandleDuplicateEvidence(descriptor.HostEvidence,
                                                                  evidence,
                                                                  duplicateAction); 
            }
        } 
 
        /// 
        ///     Ask the host for the types of evidence that it might provide if it is asked. 
        ///
        ///     This should only be called when setting up the Evidence collection to interact with the
        ///     host, and should not be used once that connection is established and the evidence has been
        ///     made available to user code. 
        /// 
        [SecurityCritical] 
        private void QueryHostForPossibleEvidenceTypes() 
        {
#if FEATURE_CAS_POLICY 
            Contract.Assert(IsWriterLockHeld);

            // First check to see if we have a HostSecurityManager
            if (AppDomain.CurrentDomain.DomainManager != null) 
            {
                HostSecurityManager hsm = AppDomain.CurrentDomain.DomainManager.HostSecurityManager; 
                if (hsm != null) 
                {
                    Type[] hostSuppliedTypes = null; 

                    AppDomain targetDomain = m_target.Target as AppDomain;
                    Assembly targetAssembly = m_target.Target as Assembly;
 
                    //
                    // If the HostSecurityManager wants to supply evidence for the type of target that we have, 
                    // then ask it what types of evidence it might supply. 
                    //
 
                    if (targetAssembly != null &&
                        (hsm.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) == HostSecurityManagerOptions.HostAssemblyEvidence)
                    {
                        hostSuppliedTypes = hsm.GetHostSuppliedAssemblyEvidenceTypes(targetAssembly); 
                    }
                    else if (targetDomain != null && 
                             (hsm.Flags & HostSecurityManagerOptions.HostAppDomainEvidence) == HostSecurityManagerOptions.HostAppDomainEvidence) 
                    {
                        hostSuppliedTypes = hsm.GetHostSuppliedAppDomainEvidenceTypes(); 
                    }

                    //
                    // Finally, mark the descriptor for each of the types that the host can supply to indicate 
                    // we should ask the host to generate them if we're asked.
                    // 
 
                    if (hostSuppliedTypes != null)
                    { 
                        foreach (Type hostEvidenceType in hostSuppliedTypes)
                        {
                            EvidenceTypeDescriptor evidenceDescriptor = GetEvidenceTypeDescriptor(hostEvidenceType, true);
                            evidenceDescriptor.HostCanGenerate = true; 
                        }
                    } 
                } 
            }
#endif // FEATURE_CAS_POLICY 
        }

        internal bool IsUnmodified
        { 
            get { return m_version == 0; }
        } 
 
        /// 
        ///     Set or check to see if the evidence is locked.  Locked evidence cannot have its host supplied 
        ///     evidence list be modified without a successful demand for ControlEvidence.  Any code can lock
        ///     evidence, but only code with ControlEvidence may unlock it.
        ///
        ///     This lock is not the same as the synchronization lock that gates access to the evidence collection. 
        /// 
        public bool Locked 
        { 
            get
            { 
                return m_locked;
            }

            [SecuritySafeCritical] 
            set
            { 
                if (!value) 
                {
                    new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); 

                    m_locked = false;
                }
                else 
                {
                    m_locked = true; 
                } 
            }
        } 

        /// 
        ///     Target of any delay generated evidence objects
        ///  
        internal IRuntimeEvidenceFactory Target
        { 
            get { return m_target; } 

            // 
            // There are two retargeting scenarios supported:
            //
            //   1. A PEFileEvidenceFactory is being upgraded to an AssemblyEvidenceFactory and we don't want
            //      to throw away any already generated evidence. 
            //   2. A detached evidence collection is being applied to an AppDomain and that domain has a
            //      HostSecurityManager. In that case, we want to attach the target to the AppDomain to 
            //      allow the HostSecurityManager to get callbacks for delay generated evidence. 
            //
 
            [SecurityCritical]
            set
            {
#if FEATURE_CAS_POLICY 
                Contract.Assert((m_target != null && m_target is PEFileEvidenceFactory && value != null && value is AssemblyEvidenceFactory) ||
                                (m_target == null && value != null && value is AppDomainEvidenceFactory), 
                                "Evidence retargeting should only be from PEFile -> Assembly or detached -> AppDomain."); 
#endif // FEATURE_CAS_POLICY
 
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
                {
                    m_target = value;
 
                    // Since we've updated what we're pointing at, we need to query the host to determine what
                    // types of evidence that it can generate for this new target. 
                    QueryHostForPossibleEvidenceTypes(); 
                }
            } 
        }

        /// 
        ///     Get the type that would be used to index into the evidence dictionary for this object 
        /// 
        private static Type GetEvidenceIndexType(EvidenceBase evidence) 
        { 
            Contract.Assert(evidence != null);
 
            //
            // Legacy wrapper evidence types should be indexed via the type of evidence that they're wrapping
            // so check to see if we have one of those; otherwise just return the type itself.
            // 

            ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter; 
            return adapter == null ? evidence.GetType() : adapter.EvidenceType; 
        }
 
        /// 
        ///     Get the type descriptor for a specific type of evidence.  This method should be used instead
        ///     of accessing the dictionary directly as it will handle the case where a new descriptor needs
        ///     to be created. 
        /// 
        internal EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType) 
        { 
            return GetEvidenceTypeDescriptor(evidenceType, false);
        } 

        /// 
        ///     Get the type descriptor for a specific type of evidence, optionally creating a descriptor if
        ///     we did not yet know about this type of evidence.  This method should be used instead of 
        ///     accessing the dictionary directly as it will handle the case where a new descriptor needs
        ///     to be created. 
        ///  
        private EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType, bool addIfNotExist)
        { 
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
            Contract.Assert(evidenceType != null);

            // If we don't know about the type being indexed and we don't want to add it then exit out 
            EvidenceTypeDescriptor descriptor = null;
            if (!m_evidence.TryGetValue(evidenceType, out descriptor) && !addIfNotExist) 
            { 
                return null;
            } 

            // If we haven't yet created a descriptor for this type then create one now
            if (descriptor == null)
            { 
                descriptor = new EvidenceTypeDescriptor();
#if _DEBUG 
                descriptor.SetEvidenceType(evidenceType); 
#endif // _DEBUG
 
                bool upgradedLock = false;
                LockCookie upgradeCookie = new LockCookie();
                try
                { 
                    if (!IsWriterLockHeld)
                    { 
                        upgradeCookie = UpgradeToWriterLock(); 
                        upgradedLock = true;
                    } 

                    m_evidence[evidenceType] = descriptor;
                }
                finally 
                {
                    if (upgradedLock) 
                        DowngradeFromWriterLock(ref upgradeCookie); 
                }
            } 

            return descriptor;
        }
 
        /// 
        ///     This method is called if a piece of evidence is added but another piece of evidence of the same 
        ///     type already existed.  We have different strategies depending on compatibility concerns of the 
        ///     calling code.
        ///  
        private static EvidenceBase HandleDuplicateEvidence(EvidenceBase original,
                                                            EvidenceBase duplicate,
                                                            DuplicateEvidenceAction action)
        { 
            Contract.Assert(original != null);
            Contract.Assert(duplicate != null); 
            Contract.Assert(original.GetType() == duplicate.GetType() || original.GetType() == typeof(LegacyEvidenceList)); 

            switch (action) 
            {
                // Throw - duplicate evidence is not allowed (Arrowhead behavior), so throw an exception
                case DuplicateEvidenceAction.Throw:
                    throw new InvalidOperationException(Environment.GetResourceString("Policy_DuplicateEvidence", duplicate.GetType().FullName)); 

                // SelectNewObject - MergeWithNoDuplicates behavior - the duplicate object wins 
                case DuplicateEvidenceAction.SelectNewObject: 
                    return duplicate;
 
                // Merge - compat behavior. Merge the old and new evidence into a list so that both may exist
                case DuplicateEvidenceAction.Merge:

                    LegacyEvidenceList list = original as LegacyEvidenceList; 
                    if (list == null)
                    { 
                        list = new LegacyEvidenceList(); 
                        list.Add(original);
                    } 

                    list.Add(duplicate);
                    return list;
 
                default:
                    BCLDebug.Assert(false, "Uknown DuplicateEvidenceAction"); 
                    return null; 
            }
        } 

        /// 
        ///     Wrap evidence we recieved through a legacy API to ensure that it is stored in an EvidenceBase
        ///  
        private static EvidenceBase WrapLegacyEvidence(object evidence)
        { 
            Contract.Assert(evidence != null); 

            EvidenceBase wrappedEvidence = evidence as EvidenceBase; 
            if (wrappedEvidence == null)
            {
                wrappedEvidence = new LegacyEvidenceWrapper(evidence);
            } 

            return wrappedEvidence; 
        } 

        ///  
        ///     Upwrap evidence stored in a legacy adapter.
        ///
        ///     This is only necessary for the case where multiple objects derived from EvidenceBase is
        ///     are added via the legacy APIs and are then retrieved via GetHostEvidence. This may occur if 
        ///     a legacy application adds CLR supplied evidence types via the old APIs and a new application
        ///     consumes the resulting evidence. 
        ///  
        private static object UnwrapEvidence(EvidenceBase evidence)
        { 
            ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter;
            return adapter == null ? evidence : adapter.EvidenceObject;
        }
 
        /// 
        ///     Merge two evidence collections together.  Note that this will cause all of the lazily 
        ///     generated evidence for the input collection to be generated, as well as causing any lazily 
        ///     generated evidence that both collections share to be generated in the target.
        ///  
        [SecuritySafeCritical]
        public void Merge(Evidence evidence)
        {
            if (evidence == null) 
            {
                return; 
            } 

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) 
            {
                bool checkedLock = false;
                IEnumerator hostEnumerator = evidence.GetHostEnumerator();
                while (hostEnumerator.MoveNext()) 
                {
                    if (Locked && !checkedLock) 
                    { 
                        new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
                        checkedLock = true; 
                    }

                    // If we could potentially have evidence of the type about to be merged into our host list,
                    // then make sure that we generate that evidence before merging.  This will prevent the 
                    // newly merged evidence from masking the value that we would have generated on our own.
                    Type hostEvidenceType = hostEnumerator.Current.GetType(); 
                    if (m_evidence.ContainsKey(hostEvidenceType)) 
                    {
                        GetHostEvidenceNoLock(hostEvidenceType); 
                    }

                    EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
                    AddHostEvidenceNoLock(hostEvidence, 
                                          GetEvidenceIndexType(hostEvidence),
                                          DuplicateEvidenceAction.Merge); 
                } 

                // Add each piece of assembly evidence. We don't need to deserialize our copy of the 
                // evidence because AddAssemblyEvidenceNoLock will do this for us.
                IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator();
                while (assemblyEnumerator.MoveNext())
                { 
                    EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
                    AddAssemblyEvidenceNoLock(assemblyEvidence, 
                                              GetEvidenceIndexType(assemblyEvidence), 
                                              DuplicateEvidenceAction.Merge);
                } 
            }
        }

        ///  
        ///     Same as merge, except only one instance of any one evidence type is allowed. When duplicates
        ///     are found, the evidence in the input argument will have priority. Note this will force the 
        ///     entire input evidence to be generated, and does not check for locked evidence 
        /// 
        internal void MergeWithNoDuplicates(Evidence evidence) 
        {
            if (evidence == null)
            {
                return; 
            }
 
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) 
            {
                IEnumerator hostEnumerator = evidence.GetHostEnumerator(); 
                while (hostEnumerator.MoveNext())
                {
                    EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current);
                    AddHostEvidenceNoLock(hostEvidence, 
                                          GetEvidenceIndexType(hostEvidence),
                                          DuplicateEvidenceAction.SelectNewObject); 
                } 

                IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator(); 
                while (assemblyEnumerator.MoveNext())
                {
                    EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current);
                    AddAssemblyEvidenceNoLock(assemblyEvidence, 
                                              GetEvidenceIndexType(assemblyEvidence),
                                              DuplicateEvidenceAction.SelectNewObject); 
                } 
            }
        } 

#if FEATURE_SERIALIZATION
        /// 
        ///     Do a full serialization of the evidence, which requires that we generate all of the evidence 
        ///     we can and disconnect ourselves from the host and source assembly.
        ///  
        [ComVisible(false)] 
        [OnSerializing]
        [SecurityCritical] 
        [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
        private void OnSerializing(StreamingContext context)
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) 
            {
                // First, force all of the host evidence that might be lazily generated to be created 
                foreach (Type evidenceType in new List(m_evidence.Keys)) 
                {
                    GetHostEvidenceNoLock(evidenceType); 
                }

                // Also ensure that all serialized assembly evidence has been created
                DeserializeTargetEvidence(); 
            }
 
            // Fill in legacy evidence lists. We can't guarantee thread-safety here using locks 
            // because we can't put a lock in the serialization code that will read the lists.
            // The best we can do is prevent another thread from seeing a half-populated list. 
            // Therefore, we assign the lists after we've populated them fully (and declare them volatile.)
            ArrayList hostList = new ArrayList();
            IEnumerator hostEnumerator = GetHostEnumerator();
            while (hostEnumerator.MoveNext()) 
            {
                hostList.Add(hostEnumerator.Current); 
            } 
            m_hostList = hostList;
 
            ArrayList assemblyList = new ArrayList();
            IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
            while (assemblyEnumerator.MoveNext())
            { 
                assemblyList.Add(assemblyEnumerator.Current);
            } 
            m_assemblyList = assemblyList; 
        }
 
        /// 
        ///     Finish deserializing legacy evidence
        /// 
        [ComVisible(false)] 
        [OnDeserialized]
        [SecurityCritical] 
        private void OnDeserialized(StreamingContext context) 
        {
            // Look at host and assembly evidence lists only if we serialized using Whidbey. 
            if (m_evidence == null)
            {
                m_evidence = new Dictionary();
 
                // Whidbey evidence may need to be wrapped or added to a LegacyEvidenceList, so we go
                // through the legacy APIs to add them. 
#pragma warning disable 618 
                if (m_hostList != null)
                { 
                    foreach (object evidenceObject in m_hostList)
                    {
                        if (evidenceObject != null)
                        { 
                            AddHost(evidenceObject);
                        } 
                    } 

                    m_hostList = null; 
                }

                if (m_assemblyList != null)
                { 
                    foreach (object evidenceObject in m_assemblyList)
                    { 
                        if (evidenceObject != null) 
                        {
                            AddAssembly(evidenceObject); 
                        }
                    }

                    m_assemblyList = null; 
                }
#pragma warning restore 618 
            } 

            // see code:System.Security.Policy.Evidence#EvidenceLock 
            m_evidenceLock = new ReaderWriterLock();
        }
#endif // FEATURE_SERIALIZATION
 
        /// 
        ///     Load any serialized evidence out of the target assembly into our evidence collection. 
        /// 
        ///     We allow entry to this method with only a reader lock held, since most of the time we will
        ///     not need to write to the evidence dictionary. If we haven't yet deserialized the target 
        ///     evidence, then we will upgrade to a writer lock at that point.
        /// 
        private void DeserializeTargetEvidence()
        { 
#if FEATURE_SERIALIZATION
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld); 
 
            if (m_target != null && !m_deserializedTargetEvidence)
            { 
                bool upgradedLock = false;
                LockCookie lockCookie = new LockCookie();
                try
                { 
                    if (!IsWriterLockHeld)
                    { 
                        lockCookie = UpgradeToWriterLock(); 
                        upgradedLock = true;
                    } 

                    // Set this to true here because AddAssemblyEvidenceNoLock will attempt to reenter this
                    // method creating possible infinite recursion.
                    m_deserializedTargetEvidence = true; 

                    foreach (EvidenceBase targetEvidence in m_target.GetFactorySuppliedEvidence()) 
                    { 
                        AddAssemblyEvidenceNoLock(targetEvidence, GetEvidenceIndexType(targetEvidence), DuplicateEvidenceAction.Throw);
                    } 
                }
                finally
                {
                    if (upgradedLock) 
                        DowngradeFromWriterLock(ref lockCookie);
                } 
            } 
#endif // FEATURE_SERIALIZATION
        } 

#if FEATURE_SERIALIZATION
        /// 
        ///     Serialize out raw evidence objects which have already been generated, ignoring any evidence 
        ///     which might be present but has not yet been created for this assembly.
        /// 
        ///     This is used for indexing into the security policy cache, since we know that once policy is 
        ///     resolved, the relevent membership conditions will have checked for any applicable evidence
        ///     and therefore after poliyc resolution this evidence collection will contain any evidence 
        ///     objects necessary to arrive at its grant set.
        /// 
        [SecurityCritical]
        [PermissionSet(SecurityAction.Assert, Unrestricted = true)] 
        internal byte[] RawSerialize()
        { 
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) 
            {
                // Filter out any evidence which is not yet generated 
                Dictionary generatedEvidence = new Dictionary();
                foreach (KeyValuePair evidenceType in m_evidence)
                {
                    if (evidenceType.Value != null && evidenceType.Value.HostEvidence != null) 
                    {
                        generatedEvidence[evidenceType.Key] = evidenceType.Value.HostEvidence; 
                    } 
                }
 
                using (MemoryStream serializationStream = new MemoryStream())
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(serializationStream, generatedEvidence); 
                    return serializationStream.ToArray();
                } 
            } 
        }
#endif // FEATURE_SERIALIZATION 

        //
        // ICollection implementation.  All ICollection interface members are potentially much more
        // expensive in Arrowhead then they were downlevel.  They should not be used if the standard Get and 
        // Add methods will work instead.
        // 
 
        [Obsolete("Evidence should not be treated as an ICollection. Please use the GetHostEnumerator and GetAssemblyEnumerator methods rather than using CopyTo.")]
        public void CopyTo(Array array, int index) 
        {
            if (array == null)
                throw new ArgumentNullException("array");
            if (index < 0 || index > array.Length - Count) 
                throw new ArgumentOutOfRangeException("index");
            Contract.EndContractBlock(); 
 
            int currentIndex = index;
 
            IEnumerator hostEnumerator = GetHostEnumerator();
            while (hostEnumerator.MoveNext())
            {
                array.SetValue(hostEnumerator.Current, currentIndex); 
                ++currentIndex;
            } 
 
            IEnumerator assemblyEnumerator = GetAssemblyEnumerator();
            while (assemblyEnumerator.MoveNext()) 
            {
                array.SetValue(assemblyEnumerator.Current, currentIndex);
                ++currentIndex;
            } 
        }
 
        public IEnumerator GetHostEnumerator() 
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) 
            {
                return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host);
            }
        } 

        public IEnumerator GetAssemblyEnumerator() 
        { 
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            { 
                DeserializeTargetEvidence();
                return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Assembly);
            }
        } 

        ///  
        ///     Get an enumerator that can iterate over the raw evidence objects stored for the assembly 
        /// 
        internal RawEvidenceEnumerator GetRawAssemblyEvidenceEnumerator() 
        {
            Contract.Assert(IsReaderLockHeld);
            DeserializeTargetEvidence();
            return new RawEvidenceEnumerator(this, new List(m_evidence.Keys), false); 
        }
 
        ///  
        ///     Get an enumerator that can iterate over the raw evidence objects stored for the host
        ///  
        /// 
        internal RawEvidenceEnumerator GetRawHostEvidenceEnumerator()
        {
            Contract.Assert(IsReaderLockHeld); 
            return new RawEvidenceEnumerator(this, new List(m_evidence.Keys), true);
        } 
 
        [Obsolete("GetEnumerator is obsolete. Please use GetAssemblyEnumerator and GetHostEnumerator instead.")]
        public IEnumerator GetEnumerator() 
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            {
                return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host | EvidenceEnumerator.Category.Assembly); 
            }
        } 
 
        /// 
        ///     Get a specific type of assembly supplied evidence 
        /// 
        [ComVisible(false)]
        public T GetAssemblyEvidence() where T : EvidenceBase
        { 
            return UnwrapEvidence(GetAssemblyEvidence(typeof(T))) as T;
        } 
 
        internal EvidenceBase GetAssemblyEvidence(Type type)
        { 
            Contract.Assert(type != null);

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            { 
                return GetAssemblyEvidenceNoLock(type);
            } 
        } 

        private EvidenceBase GetAssemblyEvidenceNoLock(Type type) 
        {
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
            Contract.Assert(type != null);
 
            DeserializeTargetEvidence();
            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type); 
            if (descriptor != null) 
            {
                return descriptor.AssemblyEvidence; 
            }

            return null;
        } 

        ///  
        ///     Get a specific type of host supplied evidence 
        /// 
        [ComVisible(false)] 
        public T GetHostEvidence() where T : EvidenceBase
        {
            return UnwrapEvidence(GetHostEvidence(typeof(T))) as T;
        } 

        ///  
        ///     Get a specific type of evidence from the host which may not have been verified yet.  If the 
        ///     evidence was not verified, then don't mark it as being used yet.
        ///  
        internal T GetDelayEvaluatedHostEvidence() where T : EvidenceBase, IDelayEvaluatedEvidence
        {
            return UnwrapEvidence(GetHostEvidence(typeof(T), false)) as T;
        } 

        internal EvidenceBase GetHostEvidence(Type type) 
        { 
            Contract.Assert(type != null);
 
            return GetHostEvidence(type, true);
        }

        [SecuritySafeCritical] 
        private EvidenceBase GetHostEvidence(Type type, bool markDelayEvaluatedEvidenceUsed)
        { 
            Contract.Assert(type != null); 

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) 
            {
                EvidenceBase evidence = GetHostEvidenceNoLock(type);

                if (markDelayEvaluatedEvidenceUsed) 
                {
                    IDelayEvaluatedEvidence delayEvidence = evidence as IDelayEvaluatedEvidence; 
                    if (delayEvidence != null) 
                    {
                        delayEvidence.MarkUsed(); 
                    }
                }

                return evidence; 
            }
        } 
 
        /// 
        ///     Get host supplied evidence from the collection 
        ///
        ///     We attempt to find host evdience in the following order:
        ///
        ///       1. Already generated or explicitly supplied evidence 
        ///       2. Evidence supplied by the CLR host
        ///       3. Evidence supplied by the CLR itself 
        ///  
        [SecurityCritical]
        private EvidenceBase GetHostEvidenceNoLock(Type type) 
        {
            Contract.Assert(IsReaderLockHeld || IsWriterLockHeld);
            Contract.Assert(type != null);
 
            EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type);
 
            // If the evidence descriptor doesn't exist for the host evidence type than the evidence doesn't 
            // exist and neither the host nor the runtime can produce it.
            if (descriptor == null) 
            {
                return null;
            }
 
            // If the evidence has already been generated or if it was explicitly provided then return that
            if (descriptor.HostEvidence != null) 
            { 
                return descriptor.HostEvidence;
            } 

            // If we have a target, then the host or the runtime might be able to generate this type of
            // evidence on demand.
            if (m_target != null && !descriptor.Generated) 
            {
                using (EvidenceUpgradeLockHolder lockHolder = new EvidenceUpgradeLockHolder(this)) 
                { 
                    // Make sure that we don't attempt to generate this type of evidencea again if we fail to
                    // generate it now. 
                    descriptor.Generated = true;

                    EvidenceBase generatedEvidence = GenerateHostEvidence(type, descriptor.HostCanGenerate);
                    if (generatedEvidence != null) 
                    {
                        descriptor.HostEvidence = generatedEvidence; 
 
                        //
                        // #BackpatchGeneratedEvidence 
                        //
                        // If we were cloned from another evidence collection propigate any generated evidence
                        // back to the original collection.  Since Assembly and AppDomain both clone their
                        // evidence before giving it to users, this prevents us from having to regenerate 
                        // evidence types on each clone that gets created.  Note that we do not want to do this
                        // backpatching if the origin already has evidence of this type or if it has had 
                        // this type of evidence removed from its collection. 
                        //
 
                        Evidence cloneOrigin = m_cloneOrigin != null ? m_cloneOrigin.Target as Evidence : null;
                        if (cloneOrigin != null)
                        {
                            BCLDebug.Assert(cloneOrigin.Target != null && cloneOrigin.Target == Target, 
                                            "Attempt to backpatch evidence to a collection with a different target.");
 
                            using (EvidenceLockHolder cloneLockHolder = new EvidenceLockHolder(cloneOrigin, EvidenceLockHolder.LockType.Writer)) 
                            {
                                EvidenceTypeDescriptor cloneDescriptor = cloneOrigin.GetEvidenceTypeDescriptor(type); 
                                if (cloneDescriptor != null && cloneDescriptor.HostEvidence == null)
                                {
                                    cloneDescriptor.HostEvidence = generatedEvidence.Clone() as EvidenceBase;
                                } 
                            }
                        } 
 
                    }
 
                    return generatedEvidence;
                }
            }
 
            // The evidence could not be generated and was not found
            return null; 
        } 

        ///  
        ///     Attempt to generate host evidence on demand via calls to the runtime host or the evidence facotry
        /// 
        [SecurityCritical]
        private EvidenceBase GenerateHostEvidence(Type type, bool hostCanGenerate) 
        {
            Contract.Assert(type != null); 
            Contract.Assert(IsWriterLockHeld); 

#if FEATURE_CAS_POLICY 
            // First let the host generate the evidence if it can.
            if (hostCanGenerate)
            {
                AppDomain targetDomain = m_target.Target as AppDomain; 
                Assembly targetAssembly = m_target.Target as Assembly;
 
                EvidenceBase hostEvidence = null; 
                if (targetDomain != null)
                { 
                    hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAppDomainEvidence(type);
                }
                else if (targetAssembly != null)
                { 
                    hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAssemblyEvidence(type, targetAssembly);
                } 
 
                // If the host generated the evidence, verify that it generated the evidence we expected
                // and use that. 
                if (hostEvidence != null)
                {
                    if (!type.IsAssignableFrom(hostEvidence.GetType()))
                    { 
                        string hostType = AppDomain.CurrentDomain.HostSecurityManager.GetType().FullName;
                        string recievedType = hostEvidence.GetType().FullName; 
                        string requestedType = type.FullName; 

                        throw new InvalidOperationException(Environment.GetResourceString("Policy_IncorrectHostEvidence", hostType, recievedType, requestedType)); 
                    }

                    return hostEvidence;
                } 
            }
#endif // FEATURE_CAS_POLICY 
 
            // Finally, check to see if the CLR can generate the evidence
            return m_target.GenerateEvidence(type); 
        }

        [Obsolete("Evidence should not be treated as an ICollection. Please use GetHostEnumerator and GetAssemblyEnumerator to iterate over the evidence to collect a count.")]
        public int Count 
        {
            get 
            { 
                int count = 0;
 
                IEnumerator hostEvidence = GetHostEnumerator();
                while (hostEvidence.MoveNext())
                {
                    ++count; 
                }
 
                IEnumerator assemblyEvidence = GetAssemblyEnumerator(); 
                while (assemblyEvidence.MoveNext())
                { 
                    ++count;
                }

                return count; 
            }
        } 
 
        /// 
        ///     Get the number of pieces of evidence which are currently generated, without causing any 
        ///     lazily generated evidence to be created.
        /// 
        [ComVisible(false)]
        internal int RawCount 
        {
            get 
            { 
                int count = 0;
 
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
                {
                    foreach (Type evidenceType in new List(m_evidence.Keys))
                    { 
                        EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType);
 
                        if (descriptor != null) 
                        {
                            if (descriptor.AssemblyEvidence != null) 
                            {
                                ++count;
                            }
                            if (descriptor.HostEvidence != null) 
                            {
                                ++count; 
                            } 
                        }
                    } 
                }

                return count;
            } 
        }
 
        public Object SyncRoot 
        {
            get { return this; } 
        }

        public bool IsSynchronized
        { 
            get { return true; }
        } 
 
        public bool IsReadOnly
        { 
            get { return false; }
        }

#if FEATURE_CAS_POLICY 
        [ComVisible(false)]
        public Evidence Clone() 
        { 
            return new Evidence(this);
        } 
#endif // FEATURE_CAS_POLICY

        [ComVisible(false)]
        [SecuritySafeCritical] 
        public void Clear()
        { 
            if (Locked) 
            {
                new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); 
            }

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer))
            { 
                ++m_version;
                m_evidence.Clear(); 
            } 
        }
 
        [ComVisible(false)]
        [SecuritySafeCritical]
        public void RemoveType(Type t)
        { 
            if (t == null)
                throw new ArgumentNullException("t"); 
            Contract.EndContractBlock(); 

            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) 
            {
                EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(t);
                if (descriptor != null)
                { 
                    ++m_version;
 
                    // If we've locked this evidence collection, we need to do the lock check in the case that 
                    // either we have host evidence, or that the host might generate it, since removing the
                    // evidence will cause us to bypass the host's ability to ever generate the evidence. 
                    if (Locked && (descriptor.HostEvidence != null || descriptor.HostCanGenerate))
                    {
                        new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();
                    } 

                    m_evidence.Remove(t); 
                } 
            }
        } 

        /// 
        ///     Mark all of the already generated evidence in the collection as having been used during a
        ///     policy evaluation. 
        /// 
        internal void MarkAllEvidenceAsUsed() 
        { 
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader))
            { 
                foreach (KeyValuePair evidenceType in m_evidence)
                {
                    if (evidenceType.Value != null)
                    { 
                        IDelayEvaluatedEvidence hostEvidence = evidenceType.Value.HostEvidence as IDelayEvaluatedEvidence;
                        if (hostEvidence != null) 
                        { 
                            hostEvidence.MarkUsed();
                        } 

                        IDelayEvaluatedEvidence assemblyEvidence = evidenceType.Value.AssemblyEvidence as IDelayEvaluatedEvidence;
                        if (assemblyEvidence != null)
                        { 
                            assemblyEvidence.MarkUsed();
                        } 
                    } 
                }
            } 
        }

#if FEATURE_CAS_POLICY
        ///  
        ///     Determine if delay evaluated strong name evidence is contained in this collection, and if so
        ///     if it was used during policy evaluation. 
        /// 
        ///     This method is called from the VM in SecurityPolicy::WasStrongNameEvidenceUsed
        ///     This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to 
        ///     be able to get the evidence values out of an Evidence class.  It is tightly coupled with the
        ///     internal data structures holding the evidence objects in the Evidence class.
        /// 
        private bool WasStrongNameEvidenceUsed() 
        {
            using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) 
            { 
                EvidenceTypeDescriptor snTypeDescriptor = GetEvidenceTypeDescriptor(typeof(StrongName));
                if (snTypeDescriptor != null) 
                {
                    IDelayEvaluatedEvidence snEvidence = snTypeDescriptor.HostEvidence as IDelayEvaluatedEvidence;
                    return snEvidence != null && snEvidence.WasUsed;
                } 

                return false; 
            } 
        }
#endif // FEATURE_CAS_POLICY 

        /// 
        ///     Utility class to wrap acquiring a lock onto the evidence collection
        ///  
        private class EvidenceLockHolder : IDisposable
        { 
            private Evidence m_target; 
            private LockType m_lockType;
 
            public enum LockType
            {
                Reader,
                Writer 
            }
 
            public EvidenceLockHolder(Evidence target, LockType lockType) 
            {
                Contract.Assert(target != null); 
                Contract.Assert(lockType == LockType.Reader || lockType == LockType.Writer);

                m_target = target;
                m_lockType = lockType; 

                if (m_lockType == LockType.Reader) 
                { 
                    m_target.AcquireReaderLock();
                } 
                else
                {
                    m_target.AcquireWriterlock();
                } 
            }
 
            public void Dispose() 
            {
                if (m_lockType == LockType.Reader && m_target.IsReaderLockHeld) 
                {
                    m_target.ReleaseReaderLock();
                }
                else if (m_lockType == LockType.Writer && m_target.IsWriterLockHeld) 
                {
                    m_target.ReleaseWriterLock(); 
                } 
            }
        } 

        /// 
        ///     Utility class to wrap upgrading an acquired reader lock to a writer lock and then
        ///     downgrading it back to a reader lock. 
        /// 
        private class EvidenceUpgradeLockHolder : IDisposable 
        { 
            private Evidence m_target;
            private LockCookie m_cookie; 

            public EvidenceUpgradeLockHolder(Evidence target)
            {
                Contract.Assert(target != null); 

                m_target = target; 
                m_cookie = m_target.UpgradeToWriterLock(); 
            }
 
            public void Dispose()
            {
                if (m_target.IsWriterLockHeld)
                { 
                    m_target.DowngradeFromWriterLock(ref m_cookie);
                } 
            } 
        }
 
        /// 
        ///     Enumerator that iterates directly over the evidence type map, returning back the evidence objects
        ///     that are contained in it.  This enumerator will generate any lazy evaluated evidence it finds,
        ///     but it does not attempt to deal with legacy evidence adapters. 
        ///
        ///     This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to 
        ///     be able to get the evidence values out of an Evidence class.  It is tightly coupled with the 
        ///     internal data structures holding the evidence objects in the Evidence class.
        ///  
        internal sealed class RawEvidenceEnumerator : IEnumerator
        {
            private Evidence m_evidence;
            private bool m_hostEnumerator;      // true to enumerate host evidence, false to enumerate assembly evidence 
            private uint m_evidenceVersion;
 
            private Type[] m_evidenceTypes; 
            private int m_typeIndex;
            private EvidenceBase m_currentEvidence; 

            private static List s_expensiveEvidence;

            public RawEvidenceEnumerator(Evidence evidence, IEnumerable evidenceTypes, bool hostEnumerator) 
            {
                Contract.Assert(evidence != null); 
                Contract.Assert(evidenceTypes != null); 

                m_evidence = evidence; 
                m_hostEnumerator = hostEnumerator;
                m_evidenceTypes = GenerateEvidenceTypes(evidence, evidenceTypes, hostEnumerator);
                m_evidenceVersion = evidence.m_version;
 
                Reset();
            } 
 
            public EvidenceBase Current
            { 
                get
                {
                    if (m_evidence.m_version != m_evidenceVersion)
                        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); 

                    return m_currentEvidence; 
                } 
            }
 
            object IEnumerator.Current
            {
                get
                { 
                    if (m_evidence.m_version != m_evidenceVersion)
                        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); 
 
                    return m_currentEvidence;
                } 
            }

            /// 
            ///     List of types of evidence that we would like to avoid generating if possible 
            /// 
            private static List ExpensiveEvidence 
            { 
                get
                { 
                    if (s_expensiveEvidence == null)
                    {
                        List expensiveEvidence = new List();
#if FEATURE_CAS_POLICY 
                        expensiveEvidence.Add(typeof(Hash));
                        expensiveEvidence.Add(typeof(Publisher)); 
#endif // FEATURE_CAS_POLICY 
                        s_expensiveEvidence = expensiveEvidence;
 
#if _DEBUG
                        List runtimeTypes = new List(Evidence.RuntimeEvidenceTypes);
                        foreach (Type expensiveType in s_expensiveEvidence)
                        { 
                            BCLDebug.Assert(runtimeTypes.Contains(expensiveType),
                                            "Evidence type not generated by the runtime found in expensive evidence type list"); 
                        } 
#endif // _DEBUG
                    } 

                    return s_expensiveEvidence;
                }
            } 

            public void Dispose() 
            { 
                return;
            } 

            /// 
            ///     Generate the array of types of evidence that could have values for
            ///  
            private static Type[] GenerateEvidenceTypes(Evidence evidence,
                                                        IEnumerable evidenceTypes, 
                                                        bool hostEvidence) 
            {
                Contract.Assert(evidence != null); 
                Contract.Assert(evidenceTypes != null);

                //
                // Sort the evidence being generated into three categories, which we enumerate in order: 
                //   1. Evidence which has already been generated
                //   2. Evidence which is relatively inexpensive to generate 
                //   3. Evidence which is expensive to generate. 
                //
                // This allows us to be as efficient as possible in case the user of the enumerator stops the 
                // enumeration before we step up to the next more expensive category.
                //

                List alreadyGeneratedList = new List(); 
                List inexpensiveList = new List();
                List expensiveList = new List(ExpensiveEvidence.Count); 
 
                // Iterate over the evidence types classifying into the three groups.  We need to copy the list
                // here since GetEvidenceTypeDescriptor will potentially update the evidence dictionary, which 
                // evidenceTypes iterates over.
                foreach (Type evidenceType in evidenceTypes)
                {
                    EvidenceTypeDescriptor descriptor = evidence.GetEvidenceTypeDescriptor(evidenceType); 
                    BCLDebug.Assert(descriptor != null, "descriptor != null");
 
                    bool alreadyGenerated = (hostEvidence && descriptor.HostEvidence != null) || 
                                            (!hostEvidence && descriptor.AssemblyEvidence != null);
 
                    if (alreadyGenerated)
                    {
                        alreadyGeneratedList.Add(evidenceType);
                    } 
                    else if (ExpensiveEvidence.Contains(evidenceType))
                    { 
                        expensiveList.Add(evidenceType); 
                    }
                    else 
                    {
                        inexpensiveList.Add(evidenceType);
                    }
                } 

                Type[] enumerationTypes = new Type[alreadyGeneratedList.Count + inexpensiveList.Count + expensiveList.Count]; 
                alreadyGeneratedList.CopyTo(enumerationTypes, 0); 
                inexpensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count);
                expensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count + inexpensiveList.Count); 

                return enumerationTypes;
            }
 
            [SecuritySafeCritical]
            public bool MoveNext() 
            { 
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
                { 
                    if (m_evidence.m_version != m_evidenceVersion)
                        throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));

                    m_currentEvidence = null; 

                    // Iterate over the possible types of evidence that we could have until we find one that 
                    // really exists, or we run out of posibilities. 
                    do
                    { 
                        ++m_typeIndex;

                        if (m_typeIndex < m_evidenceTypes.Length)
                        { 
                            if (m_hostEnumerator)
                            { 
                                m_currentEvidence = m_evidence.GetHostEvidenceNoLock(m_evidenceTypes[m_typeIndex]); 
                            }
                            else 
                            {
                                m_currentEvidence = m_evidence.GetAssemblyEvidenceNoLock(m_evidenceTypes[m_typeIndex]);
                            }
                        } 
                    }
                    while (m_typeIndex < m_evidenceTypes.Length && m_currentEvidence == null); 
                } 

                return m_currentEvidence != null; 
            }

            public void Reset()
            { 
                if (m_evidence.m_version != m_evidenceVersion)
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); 
 
                m_typeIndex = -1;
                m_currentEvidence = null; 
            }
        }

        private sealed class EvidenceEnumerator : IEnumerator 
        {
            private Evidence m_evidence; 
            private Category m_category; 
            private Stack m_enumerators;
 
            private object m_currentEvidence;

            [Flags]
            internal enum Category 
            {
                Host = 0x1,     // Enumerate only host supplied evidence 
                Assembly = 0x2      // Enumerate only assembly supplied evidence 
            }
 
            internal EvidenceEnumerator(Evidence evidence, Category category)
            {
                Contract.Assert(evidence != null);
                Contract.Assert(evidence.IsReaderLockHeld); 

                m_evidence = evidence; 
                m_category = category; 
                ResetNoLock();
            } 

            public bool MoveNext()
            {
                IEnumerator currentEnumerator = CurrentEnumerator; 

                // No more enumerators means we can't go any further 
                if (currentEnumerator == null) 
                {
                    m_currentEvidence = null; 
                    return false;
                }

                // See if the current enumerator can continue 
                if (currentEnumerator.MoveNext())
                { 
                    // 
                    // If we've found an adapter for legacy evidence, we need to unwrap it for it to be the
                    // current enumerator's value.  For wrapped evidence, this is a simple unwrap, for a list of 
                    // evidence, we need to make that the current enumerator and get its first value.
                    //

                    LegacyEvidenceWrapper legacyWrapper = currentEnumerator.Current as LegacyEvidenceWrapper; 
                    LegacyEvidenceList legacyList = currentEnumerator.Current as LegacyEvidenceList;
 
                    if (legacyWrapper != null) 
                    {
                        m_currentEvidence = legacyWrapper.EvidenceObject; 
                    }
                    else if (legacyList != null)
                    {
                        IEnumerator legacyListEnumerator = legacyList.GetEnumerator(); 
                        m_enumerators.Push(legacyListEnumerator);
                        MoveNext(); 
                    } 
                    else
                    { 
                        m_currentEvidence = currentEnumerator.Current;
                    }

                    BCLDebug.Assert(m_currentEvidence != null, "m_currentEvidence != null"); 
                    return true;
                } 
                else 
                {
                    // If we've reached the end of the current enumerator, move to the next one and try again 
                    m_enumerators.Pop();
                    return MoveNext();
                }
            } 

            public object Current 
            { 
                get { return m_currentEvidence; }
            } 

            private IEnumerator CurrentEnumerator
            {
                get 
                {
                    return m_enumerators.Count > 0 ? m_enumerators.Peek() as IEnumerator : null; 
                } 
            }
 
            public void Reset()
            {
                using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader))
                { 
                    ResetNoLock();
                } 
            } 

            private void ResetNoLock() 
            {
                Contract.Assert(m_evidence != null);
                Contract.Assert(m_evidence.IsReaderLockHeld);
 
                m_currentEvidence = null;
                m_enumerators = new Stack(); 
 
                if ((m_category & Category.Host) == Category.Host)
                { 
                    m_enumerators.Push(m_evidence.GetRawHostEvidenceEnumerator());
                }
                if ((m_category & Category.Assembly) == Category.Assembly)
                { 
                    m_enumerators.Push(m_evidence.GetRawAssemblyEvidenceEnumerator());
                } 
            } 
        }
#endif //!FEATURE_CORECLR && FEATURE_RWLOCK 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK