Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / security / policy / assemblyevidencefactory.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 using System;
10 using System.Collections.Generic;
11 using System.Diagnostics.Contracts;
12 using System.Reflection;
13 using System.Runtime.CompilerServices;
14 using System.Runtime.InteropServices;
15 using System.Security;
16 using System.Security.Permissions;
17 using Microsoft.Win32.SafeHandles;
18
19 namespace System.Security.Policy
20 {
21
22     /// <summary>
23     ///     Factory class which can create evidence on demand for an assembly
24     /// </summary>
25     internal sealed class AssemblyEvidenceFactory : IRuntimeEvidenceFactory
26     {
27         private PEFileEvidenceFactory m_peFileFactory;
28         private RuntimeAssembly m_targetAssembly;
29
30         /// <summary>
31         ///     Create a factory which can generate evidence for the specified assembly
32         /// </summary>
33         private AssemblyEvidenceFactory(RuntimeAssembly targetAssembly, PEFileEvidenceFactory peFileFactory)
34         {
35             Contract.Assert(targetAssembly != null);
36             Contract.Assert(peFileFactory != null);
37
38             m_targetAssembly = targetAssembly;
39             m_peFileFactory = peFileFactory;
40         }
41
42         /// <summary>
43         ///     PEFile that the assembly is loaded from
44         /// </summary>
45         internal SafePEFileHandle PEFile
46         {
47             [SecurityCritical]
48             get { return m_peFileFactory.PEFile; }
49         }
50
51         /// <summary>
52         ///     Assembly that the evidence generated is for
53         /// </summary>
54         public IEvidenceFactory Target
55         {
56             get { return m_targetAssembly; }
57         }
58
59         /// <summary>
60         ///     Generate a specific type of evidence for this assembly
61         /// </summary>
62         public EvidenceBase GenerateEvidence(Type evidenceType)
63         {
64             // Assembly evidence is a superset of the evidence that a PEFile can supply, so first see if the
65             // requested evidence type can be generated by the assembly's PEFile
66             EvidenceBase evidence = m_peFileFactory.GenerateEvidence(evidenceType);
67             if (evidence != null)
68             {
69                 return evidence;
70             }
71
72             // If the PEFile didn't know about this type of evidence, see if it is an evidence type that the
73             // Assembly knows how to generate
74             if (evidenceType == typeof(GacInstalled))
75             {
76                 return GenerateGacEvidence();
77             }
78             else if (evidenceType == typeof(Hash))
79             {
80                 return GenerateHashEvidence();
81             }
82 #pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode
83             else if (evidenceType == typeof(PermissionRequestEvidence))
84             {
85                 return GeneratePermissionRequestEvidence();
86             }
87 #pragma warning restore 618
88             else if (evidenceType == typeof(StrongName))
89             {
90                 return GenerateStrongNameEvidence();
91             }
92
93             return null;
94         }
95
96         /// <summary>
97         ///     Generate evidence if the assembly is installed in the GAC
98         /// </summary>
99         private GacInstalled GenerateGacEvidence()
100         {
101             if (!m_targetAssembly.GlobalAssemblyCache)
102             {
103                 return null;
104             }
105
106             m_peFileFactory.FireEvidenceGeneratedEvent(EvidenceTypeGenerated.Gac);
107             return new GacInstalled();
108         }
109
110         /// <summary>
111         ///     Generate evidence for the assembly's hash value
112         /// </summary>
113         private Hash GenerateHashEvidence()
114         {
115             if (m_targetAssembly.IsDynamic)
116             {
117                 return null;
118             }
119
120             m_peFileFactory.FireEvidenceGeneratedEvent(EvidenceTypeGenerated.Hash);
121             return new Hash(m_targetAssembly);
122         }
123
124 #pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode
125         /// <summary>
126         ///     Generate evidence for the assembly's declarative security
127         /// </summary>
128         [SecuritySafeCritical]
129         private PermissionRequestEvidence GeneratePermissionRequestEvidence()
130         {
131             Contract.Assert(AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled);
132
133             PermissionSet minimumPermissions = null;
134             PermissionSet optionalPermissions = null;
135             PermissionSet refusedPermissions = null;
136
137             GetAssemblyPermissionRequests(m_targetAssembly.GetNativeHandle(),
138                                           JitHelpers.GetObjectHandleOnStack(ref minimumPermissions),
139                                           JitHelpers.GetObjectHandleOnStack(ref optionalPermissions),
140                                           JitHelpers.GetObjectHandleOnStack(ref refusedPermissions));
141
142             if (minimumPermissions != null || optionalPermissions != null || refusedPermissions != null)
143             {
144                 return new PermissionRequestEvidence(minimumPermissions,
145                                                      optionalPermissions,
146                                                      refusedPermissions);
147             }
148
149             return null;
150         }
151 #pragma warning restore 618
152
153         /// <summary>
154         ///     Generate evidence for this file's strong name
155         /// </summary>
156         [SecuritySafeCritical]
157         private StrongName GenerateStrongNameEvidence()
158         {
159             byte[] publicKeyBlob = null;
160             string simpleName = null;
161             ushort majorVersion = 0;
162             ushort minorVersion = 0;
163             ushort build = 0;
164             ushort revision = 0;
165
166             GetStrongNameInformation(m_targetAssembly.GetNativeHandle(),
167                                      JitHelpers.GetObjectHandleOnStack(ref publicKeyBlob),
168                                      JitHelpers.GetStringHandleOnStack(ref simpleName),
169                                      out majorVersion,
170                                      out minorVersion,
171                                      out build,
172                                      out revision);
173
174             if (publicKeyBlob == null || publicKeyBlob.Length == 0)
175             {
176                 return null;
177             }
178
179             return new StrongName(new StrongNamePublicKeyBlob(publicKeyBlob),
180                                   simpleName,
181                                   new Version(majorVersion, minorVersion, build, revision),
182                                   m_targetAssembly);
183         }
184
185         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
186         [SecurityCritical]
187         [SuppressUnmanagedCodeSecurity]
188         private static extern void GetAssemblyPermissionRequests(RuntimeAssembly assembly,
189                                                                  ObjectHandleOnStack retMinimumPermissions,
190                                                                  ObjectHandleOnStack retOptionalPermissions,
191                                                                  ObjectHandleOnStack retRefusedPermissions);
192
193         /// <summary>
194         ///     Get any evidence that was serialized into the assembly
195         /// </summary>
196         public IEnumerable<EvidenceBase> GetFactorySuppliedEvidence()
197         {
198             // The PEFile knows how to read the serialized evidence, so we can just delegate to it
199             return m_peFileFactory.GetFactorySuppliedEvidence();
200         }
201
202         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
203         [SecurityCritical]
204         [SuppressUnmanagedCodeSecurity]
205         private static extern void GetStrongNameInformation(RuntimeAssembly assembly,
206                                                             ObjectHandleOnStack retPublicKeyBlob,
207                                                             StringHandleOnStack retSimpleName,
208                                                             [Out] out ushort majorVersion,
209                                                             [Out] out ushort minorVersion,
210                                                             [Out] out ushort build,
211                                                             [Out] out ushort revision);
212
213         /// <summary>
214         ///     Retarget an evidence object from generating evidence for a PEFile to generating evidence for
215         ///     the file's assembly.
216         /// </summary>
217         [SecurityCritical]
218         private static Evidence UpgradeSecurityIdentity(Evidence peFileEvidence, RuntimeAssembly targetAssembly)
219         {
220             Contract.Assert(peFileEvidence != null);
221             Contract.Assert(targetAssembly != null);
222             Contract.Assert(peFileEvidence.Target is PEFileEvidenceFactory, "Expected upgrade path is from PEFile to Assembly");
223
224             peFileEvidence.Target = new AssemblyEvidenceFactory(targetAssembly,
225                                                                 peFileEvidence.Target as PEFileEvidenceFactory);
226
227             // Whidbey hosts would provide evidence for assemblies up front rather than on demand.  If there
228             // is a HostSecurityManager which does want to provide evidence, then we should provide it the
229             // opprotunity to do the same for compatibility.
230             HostSecurityManager securityManager = AppDomain.CurrentDomain.HostSecurityManager;
231             if ((securityManager.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) == HostSecurityManagerOptions.HostAssemblyEvidence)
232             {
233                 peFileEvidence = securityManager.ProvideAssemblyEvidence(targetAssembly, peFileEvidence);
234                 if (peFileEvidence == null)
235                 {
236                     throw new InvalidOperationException(Environment.GetResourceString("Policy_NullHostEvidence", securityManager.GetType().FullName, targetAssembly.FullName));
237                 }
238             }
239
240             return peFileEvidence;
241         }
242     }
243 }