|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// <OWNER>Microsoft</OWNER>
//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
namespace System.Security.Policy
{
/// <summary>
/// Factory class which can create evidence on demand for an assembly
/// </summary>
internal sealed class AssemblyEvidenceFactory : IRuntimeEvidenceFactory
{
private PEFileEvidenceFactory m_peFileFactory;
private RuntimeAssembly m_targetAssembly;
/// <summary>
/// Create a factory which can generate evidence for the specified assembly
/// </summary>
private AssemblyEvidenceFactory(RuntimeAssembly targetAssembly, PEFileEvidenceFactory peFileFactory)
{
Contract.Assert(targetAssembly != null);
Contract.Assert(peFileFactory != null);
m_targetAssembly = targetAssembly;
m_peFileFactory = peFileFactory;
}
/// <summary>
/// PEFile that the assembly is loaded from
/// </summary>
internal SafePEFileHandle PEFile
{
[SecurityCritical]
get { return m_peFileFactory.PEFile; }
}
/// <summary>
/// Assembly that the evidence generated is for
/// </summary>
public IEvidenceFactory Target
{
get { return m_targetAssembly; }
}
/// <summary>
/// Generate a specific type of evidence for this assembly
/// </summary>
public EvidenceBase GenerateEvidence(Type evidenceType)
{
// Assembly evidence is a superset of the evidence that a PEFile can supply, so first see if the
// requested evidence type can be generated by the assembly's PEFile
EvidenceBase evidence = m_peFileFactory.GenerateEvidence(evidenceType);
if (evidence != null)
{
return evidence;
}
// If the PEFile didn't know about this type of evidence, see if it is an evidence type that the
// Assembly knows how to generate
if (evidenceType == typeof(GacInstalled))
{
return GenerateGacEvidence();
}
else if (evidenceType == typeof(Hash))
{
return GenerateHashEvidence();
}
#pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode
else if (evidenceType == typeof(PermissionRequestEvidence))
{
return GeneratePermissionRequestEvidence();
}
#pragma warning restore 618
else if (evidenceType == typeof(StrongName))
{
return GenerateStrongNameEvidence();
}
return null;
}
/// <summary>
/// Generate evidence if the assembly is installed in the GAC
/// </summary>
private GacInstalled GenerateGacEvidence()
{
if (!m_targetAssembly.GlobalAssemblyCache)
{
return null;
}
m_peFileFactory.FireEvidenceGeneratedEvent(EvidenceTypeGenerated.Gac);
return new GacInstalled();
}
/// <summary>
/// Generate evidence for the assembly's hash value
/// </summary>
private Hash GenerateHashEvidence()
{
if (m_targetAssembly.IsDynamic)
{
return null;
}
m_peFileFactory.FireEvidenceGeneratedEvent(EvidenceTypeGenerated.Hash);
return new Hash(m_targetAssembly);
}
#pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode
/// <summary>
/// Generate evidence for the assembly's declarative security
/// </summary>
[SecuritySafeCritical]
private PermissionRequestEvidence GeneratePermissionRequestEvidence()
{
Contract.Assert(AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled);
PermissionSet minimumPermissions = null;
PermissionSet optionalPermissions = null;
PermissionSet refusedPermissions = null;
GetAssemblyPermissionRequests(m_targetAssembly.GetNativeHandle(),
JitHelpers.GetObjectHandleOnStack(ref minimumPermissions),
JitHelpers.GetObjectHandleOnStack(ref optionalPermissions),
JitHelpers.GetObjectHandleOnStack(ref refusedPermissions));
if (minimumPermissions != null || optionalPermissions != null || refusedPermissions != null)
{
return new PermissionRequestEvidence(minimumPermissions,
optionalPermissions,
refusedPermissions);
}
return null;
}
#pragma warning restore 618
/// <summary>
/// Generate evidence for this file's strong name
/// </summary>
[SecuritySafeCritical]
private StrongName GenerateStrongNameEvidence()
{
byte[] publicKeyBlob = null;
string simpleName = null;
ushort majorVersion = 0;
ushort minorVersion = 0;
ushort build = 0;
ushort revision = 0;
GetStrongNameInformation(m_targetAssembly.GetNativeHandle(),
JitHelpers.GetObjectHandleOnStack(ref publicKeyBlob),
JitHelpers.GetStringHandleOnStack(ref simpleName),
out majorVersion,
out minorVersion,
out build,
out revision);
if (publicKeyBlob == null || publicKeyBlob.Length == 0)
{
return null;
}
return new StrongName(new StrongNamePublicKeyBlob(publicKeyBlob),
simpleName,
new Version(majorVersion, minorVersion, build, revision),
m_targetAssembly);
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
private static extern void GetAssemblyPermissionRequests(RuntimeAssembly assembly,
ObjectHandleOnStack retMinimumPermissions,
ObjectHandleOnStack retOptionalPermissions,
ObjectHandleOnStack retRefusedPermissions);
/// <summary>
/// Get any evidence that was serialized into the assembly
/// </summary>
public IEnumerable<EvidenceBase> GetFactorySuppliedEvidence()
{
// The PEFile knows how to read the serialized evidence, so we can just delegate to it
return m_peFileFactory.GetFactorySuppliedEvidence();
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
private static extern void GetStrongNameInformation(RuntimeAssembly assembly,
ObjectHandleOnStack retPublicKeyBlob,
StringHandleOnStack retSimpleName,
[Out] out ushort majorVersion,
[Out] out ushort minorVersion,
[Out] out ushort build,
[Out] out ushort revision);
/// <summary>
/// Retarget an evidence object from generating evidence for a PEFile to generating evidence for
/// the file's assembly.
/// </summary>
[SecurityCritical]
private static Evidence UpgradeSecurityIdentity(Evidence peFileEvidence, RuntimeAssembly targetAssembly)
{
Contract.Assert(peFileEvidence != null);
Contract.Assert(targetAssembly != null);
Contract.Assert(peFileEvidence.Target is PEFileEvidenceFactory, "Expected upgrade path is from PEFile to Assembly");
peFileEvidence.Target = new AssemblyEvidenceFactory(targetAssembly,
peFileEvidence.Target as PEFileEvidenceFactory);
// Whidbey hosts would provide evidence for assemblies up front rather than on demand. If there
// is a HostSecurityManager which does want to provide evidence, then we should provide it the
// opprotunity to do the same for compatibility.
HostSecurityManager securityManager = AppDomain.CurrentDomain.HostSecurityManager;
if ((securityManager.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) == HostSecurityManagerOptions.HostAssemblyEvidence)
{
peFileEvidence = securityManager.ProvideAssemblyEvidence(targetAssembly, peFileEvidence);
if (peFileEvidence == null)
{
throw new InvalidOperationException(Environment.GetResourceString("Policy_NullHostEvidence", securityManager.GetType().FullName, targetAssembly.FullName));
}
}
return peFileEvidence;
}
}
}
|