Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions src/Tasks.UnitTests/StrongNameUtils_Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#if NETFRAMEWORK

using System;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using Microsoft.Build.Tasks;
using Shouldly;
using Xunit;

#nullable disable

namespace Microsoft.Build.UnitTests
{
public sealed class StrongNameUtils_Tests
{
/// <summary>
/// The BCL (mscorlib) is always a fully signed managed assembly.
/// </summary>
[Fact]
public void GetAssemblyStrongNameLevel_FullySignedAssembly_ReturnsFullySigned()
{
string bclPath = typeof(string).Assembly.Location;
bclPath.ShouldNotBeNullOrEmpty();
File.Exists(bclPath).ShouldBeTrue();

StrongNameUtils.GetAssemblyStrongNameLevel(bclPath).ShouldBe(StrongNameLevel.FullySigned);
}

/// <summary>
/// A managed assembly with a strong-name signature directory present but with the
/// <c>COMIMAGE_FLAGS_STRONGNAMESIGNED</c> bit cleared must be reported as DelaySigned.
/// We emit one on the fly by attaching a public key and tagging the assembly
/// <c>[assembly: AssemblyDelaySign(true)]</c>.
/// </summary>
[Fact]
public void GetAssemblyStrongNameLevel_DelaySignedAssembly_ReturnsDelaySigned()
{
using TestEnvironment env = TestEnvironment.Create();
TransientTestFolder folder = env.CreateFolder();
Comment thread
JeremyKuhne marked this conversation as resolved.

AssemblyName name = new AssemblyName("DelaySignedTestAssembly_" + Guid.NewGuid().ToString("N"));
name.SetPublicKey(typeof(string).Assembly.GetName().GetPublicKey());

// Mark as delay-signed via AssemblyDelaySignAttribute.
CustomAttributeBuilder delaySign = new CustomAttributeBuilder(
typeof(AssemblyDelaySignAttribute).GetConstructor([typeof(bool)]),
[true]);

AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
name,
AssemblyBuilderAccess.Save,
folder.Path);
asmBuilder.SetCustomAttribute(delaySign);

string fileName = name.Name + ".dll";
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(name.Name, fileName);
modBuilder.DefineType("Stub", TypeAttributes.Public).CreateType();
asmBuilder.Save(fileName);

string asmPath = Path.Combine(folder.Path, fileName);
File.Exists(asmPath).ShouldBeTrue();

StrongNameUtils.GetAssemblyStrongNameLevel(asmPath).ShouldBe(StrongNameLevel.DelaySigned);
}

/// <summary>
/// An unsigned managed assembly (COR20 header present, no strong name signature directory)
/// must be reported as None.
/// </summary>
[Fact]
public void GetAssemblyStrongNameLevel_UnsignedManagedAssembly_ReturnsNone()
{
using TestEnvironment env = TestEnvironment.Create();
TransientTestFolder folder = env.CreateFolder();

// Emit a trivial dynamic assembly to disk with no key file / key pair attached.
AssemblyName name = new AssemblyName("UnsignedTestAssembly_" + Guid.NewGuid().ToString("N"));
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
name,
AssemblyBuilderAccess.Save,
folder.Path);
string fileName = name.Name + ".dll";
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(name.Name, fileName);
modBuilder.DefineType("Stub", TypeAttributes.Public).CreateType();
asmBuilder.Save(fileName);

string asmPath = Path.Combine(folder.Path, fileName);
File.Exists(asmPath).ShouldBeTrue();

StrongNameUtils.GetAssemblyStrongNameLevel(asmPath).ShouldBe(StrongNameLevel.None);
}

/// <summary>
/// A native PE without a COR20 header must be reported as Unknown (not None) so that
/// callers like AxTlbBaseReference.SigningRequirementsMatchExistingWrapper can distinguish
/// "no managed signature present" from "not a managed image at all".
/// </summary>
[WindowsOnlyFact]
public void GetAssemblyStrongNameLevel_NativePE_ReturnsUnknown()
{
string systemRoot = Environment.GetEnvironmentVariable("SystemRoot") ?? Environment.GetFolderPath(Environment.SpecialFolder.Windows);
string kernel32 = Path.Combine(systemRoot, "System32", "kernel32.dll");
File.Exists(kernel32).ShouldBeTrue();

StrongNameUtils.GetAssemblyStrongNameLevel(kernel32).ShouldBe(StrongNameLevel.Unknown);
}

[Fact]
public void GetAssemblyStrongNameLevel_NonExistentFile_ReturnsUnknown()
{
using TestEnvironment env = TestEnvironment.Create();
TransientTestFile missing = env.GetTempFile(".dll");
File.Exists(missing.Path).ShouldBeFalse();

StrongNameUtils.GetAssemblyStrongNameLevel(missing.Path).ShouldBe(StrongNameLevel.Unknown);
}

[Fact]
public void GetAssemblyStrongNameLevel_GarbageFile_ReturnsUnknown()
{
using TestEnvironment env = TestEnvironment.Create();
TransientTestFile garbage = env.CreateFile();
File.WriteAllBytes(garbage.Path, [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]);

StrongNameUtils.GetAssemblyStrongNameLevel(garbage.Path).ShouldBe(StrongNameLevel.Unknown);
}

[Fact]
public void GetAssemblyStrongNameLevel_EmptyFile_ReturnsUnknown()
{
using TestEnvironment env = TestEnvironment.Create();
TransientTestFile empty = env.CreateFile();

StrongNameUtils.GetAssemblyStrongNameLevel(empty.Path).ShouldBe(StrongNameLevel.Unknown);
}

[Fact]
public void GetAssemblyStrongNameLevel_NullPath_Throws()
{
Should.Throw<ArgumentNullException>(() => StrongNameUtils.GetAssemblyStrongNameLevel(null));
}
}
}

#endif

207 changes: 0 additions & 207 deletions src/Tasks/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,6 @@ internal static partial class NativeMethods
#region Constants

internal static readonly IntPtr NullPtr = IntPtr.Zero;
internal static readonly IntPtr InvalidIntPtr = new IntPtr(-1);

internal const int ERROR_SUCCESS = 0;

Expand Down Expand Up @@ -507,14 +506,6 @@ internal enum REGKIND
internal const UInt16 IMAGE_FILE_MACHINE_ARM64 = 0xAA64; // ARM64 Little-Endian
internal const UInt16 IMAGE_FILE_MACHINE_R4000 = 0x166; // Used to test a architecture we do not expect to reference

internal const uint GENERIC_READ = 0x80000000;

internal const uint PAGE_READONLY = 0x02;

internal const uint FILE_MAP_READ = 0x04;

internal const uint FILE_TYPE_DISK = 0x01;

internal const int SE_ERR_ACCESSDENIED = 5;

[Flags]
Expand All @@ -528,152 +519,6 @@ internal enum MoveFileFlags
MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020
}

#endregion

#region NT header stuff

internal const uint IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
internal const uint IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;

internal const uint IMAGE_DIRECTORY_ENTRY_COMHEADER = 14;

internal const uint COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x08;

[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_FILE_HEADER
{
internal ushort Machine;
internal ushort NumberOfSections;
internal uint TimeDateStamp;
internal uint PointerToSymbolTable;
internal uint NumberOfSymbols;
internal ushort SizeOfOptionalHeader;
internal ushort Characteristics;
}

[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_DATA_DIRECTORY
{
internal uint VirtualAddress;
internal uint Size;
}

[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_OPTIONAL_HEADER32
{
internal ushort Magic;
internal byte MajorLinkerVersion;
internal byte MinorLinkerVersion;
internal uint SizeOfCode;
internal uint SizeOfInitializedData;
internal uint SizeOfUninitializedData;
internal uint AddressOfEntryPoint;
internal uint BaseOfCode;
internal uint BaseOfData;
internal uint ImageBase;
internal uint SectionAlignment;
internal uint FileAlignment;
internal ushort MajorOperatingSystemVersion;
internal ushort MinorOperatingSystemVersion;
internal ushort MajorImageVersion;
internal ushort MinorImageVersion;
internal ushort MajorSubsystemVersion;
internal ushort MinorSubsystemVersion;
internal uint Win32VersionValue;
internal uint SizeOfImage;
internal uint SizeOfHeaders;
internal uint CheckSum;
internal ushort Subsystem;
internal ushort DllCharacteristics;
internal uint SizeOfStackReserve;
internal uint SizeOfStackCommit;
internal uint SizeOfHeapReserve;
internal uint SizeOfHeapCommit;
internal uint LoaderFlags;
internal uint NumberOfRvaAndSizes;

// should be:
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] internal IMAGE_DATA_DIRECTORY[] DataDirectory;
// but fixed size arrays only work with simple types, so I have to use ulongs and convert them to IMAGE_DATA_DIRECTORY structs
// Fortunately, IMAGE_DATA_DIRECTORY is only 8 bytes long... (whew)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
internal ulong[] DataDirectory;
}

[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_OPTIONAL_HEADER64
{
internal ushort Magic;
internal byte MajorLinkerVersion;
internal byte MinorLinkerVersion;
internal uint SizeOfCode;
internal uint SizeOfInitializedData;
internal uint SizeOfUninitializedData;
internal uint AddressOfEntryPoint;
internal uint BaseOfCode;
internal ulong ImageBase;
internal uint SectionAlignment;
internal uint FileAlignment;
internal ushort MajorOperatingSystemVersion;
internal ushort MinorOperatingSystemVersion;
internal ushort MajorImageVersion;
internal ushort MinorImageVersion;
internal ushort MajorSubsystemVersion;
internal ushort MinorSubsystemVersion;
internal uint Win32VersionValue;
internal uint SizeOfImage;
internal uint SizeOfHeaders;
internal uint CheckSum;
internal ushort Subsystem;
internal ushort DllCharacteristics;
internal ulong SizeOfStackReserve;
internal ulong SizeOfStackCommit;
internal ulong SizeOfHeapReserve;
internal ulong SizeOfHeapCommit;
internal uint LoaderFlags;
internal uint NumberOfRvaAndSizes;

// should be:
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] internal IMAGE_DATA_DIRECTORY[] DataDirectory;
// but fixed size arrays only work with simple types, so I have to use ulongs and convert them to IMAGE_DATA_DIRECTORY structs
// Fortunately, IMAGE_DATA_DIRECTORY is only 8 bytes long... (whew)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
internal ulong[] DataDirectory;
}

[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_NT_HEADERS32
{
internal uint signature;
internal IMAGE_FILE_HEADER fileHeader;
internal IMAGE_OPTIONAL_HEADER32 optionalHeader;
}

[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_NT_HEADERS64
{
internal uint signature;
internal IMAGE_FILE_HEADER fileHeader;
internal IMAGE_OPTIONAL_HEADER64 optionalHeader;
}

[StructLayout(LayoutKind.Sequential)]
internal struct IMAGE_COR20_HEADER
{
internal uint cb;
internal ushort MajorRuntimeVersion;
internal ushort MinorRuntimeVersion;
internal IMAGE_DATA_DIRECTORY MetaData;
internal uint Flags;
internal uint EntryPointTokenOrEntryPointRVA;
internal IMAGE_DATA_DIRECTORY Resources;
internal IMAGE_DATA_DIRECTORY StrongNameSignature;
internal IMAGE_DATA_DIRECTORY CodeManagerTable;
internal IMAGE_DATA_DIRECTORY VTableFixups;
internal IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
internal IMAGE_DATA_DIRECTORY ManagedNativeHeader;
}

[StructLayout(LayoutKind.Sequential)]
internal struct CRYPTOAPI_BLOB
{
Expand Down Expand Up @@ -809,58 +654,6 @@ internal static extern void UnregisterTypeLib(
[return: MarshalAs(UnmanagedType.BStr)]
internal static extern string QueryPathOfRegTypeLib([In] ref Guid clsid, [In] short majorVersion, [In] short minorVersion, [In] int lcid);

//------------------------------------------------------------------------------
// CreateFile
//------------------------------------------------------------------------------
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, FileShare dwShareMode,
IntPtr lpSecurityAttributes, FileMode dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

//------------------------------------------------------------------------------
// GetFileType
//------------------------------------------------------------------------------
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern uint GetFileType(IntPtr hFile);

//------------------------------------------------------------------------------
// CloseHandle
//------------------------------------------------------------------------------
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr hObject);

//------------------------------------------------------------------------------
// CreateFileMapping
//------------------------------------------------------------------------------
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect,
uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);

//------------------------------------------------------------------------------
// MapViewOfFile
//------------------------------------------------------------------------------
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr MapViewOfFile(IntPtr hFileMapping, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, IntPtr dwNumberOfBytesToMap);

//------------------------------------------------------------------------------
// UnmapViewOfFile
//------------------------------------------------------------------------------
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);

//------------------------------------------------------------------------------
// ImageNtHeader
//------------------------------------------------------------------------------
[DllImport("dbghelp.dll", SetLastError = true)]
internal static extern IntPtr ImageNtHeader(IntPtr imageBase);

//------------------------------------------------------------------------------
// ImageRvaToVa
//------------------------------------------------------------------------------
[DllImport("dbghelp.dll", SetLastError = true)]
internal static extern IntPtr ImageRvaToVa(IntPtr ntHeaders, IntPtr imageBase, uint Rva, out IntPtr LastRvaSection);

internal static bool AllDrivesMapped()
{
#if FEATURE_WINDOWSINTEROP
Expand Down
Loading
Loading