summaryrefslogtreecommitdiff
path: root/src/strongname
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/strongname
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/strongname')
-rw-r--r--src/strongname/.gitmirror1
-rw-r--r--src/strongname/CMakeLists.txt1
-rw-r--r--src/strongname/api/.gitmirror1
-rw-r--r--src/strongname/api/CMakeLists.txt26
-rw-r--r--src/strongname/api/api.props43
-rw-r--r--src/strongname/api/common.cpp7
-rw-r--r--src/strongname/api/common.h404
-rw-r--r--src/strongname/api/crossgen/.gitmirror1
-rw-r--r--src/strongname/api/crossgen/strongname_crossgen.nativeproj18
-rw-r--r--src/strongname/api/cryptapis.h48
-rw-r--r--src/strongname/api/dac/.gitmirror1
-rw-r--r--src/strongname/api/dac/CMakeLists.txt4
-rw-r--r--src/strongname/api/dac/dirs.proj19
-rw-r--r--src/strongname/api/dirs.proj22
-rw-r--r--src/strongname/api/strongname.cpp4988
-rw-r--r--src/strongname/api/strongnamecoreclr.cpp99
-rw-r--r--src/strongname/api/strongnameinternal.cpp448
-rw-r--r--src/strongname/api/wks/.gitmirror1
-rw-r--r--src/strongname/api/wks/CMakeLists.txt1
-rw-r--r--src/strongname/api/wks/strongname_wks.nativeproj23
-rw-r--r--src/strongname/dirs.proj29
-rw-r--r--src/strongname/inc/.gitmirror1
-rw-r--r--src/strongname/inc/StrongName_inc.nativeproj31
-rw-r--r--src/strongname/inc/ecmakey.h10
-rw-r--r--src/strongname/inc/sncoreclr.h15
-rw-r--r--src/strongname/inc/strongname.h307
-rw-r--r--src/strongname/inc/strongnameholders.h104
-rw-r--r--src/strongname/inc/strongnameinternal.h59
-rw-r--r--src/strongname/inc/thekey.h105
-rw-r--r--src/strongname/inc/thetestkey.h87
-rw-r--r--src/strongname/strongname.vcxproj396
-rw-r--r--src/strongname/strongname.vcxproj.filters108
-rw-r--r--src/strongname/strongname.vcxproj.vspscc10
33 files changed, 7418 insertions, 0 deletions
diff --git a/src/strongname/.gitmirror b/src/strongname/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/strongname/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/strongname/CMakeLists.txt b/src/strongname/CMakeLists.txt
new file mode 100644
index 0000000000..dcfdb8cf57
--- /dev/null
+++ b/src/strongname/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(api) \ No newline at end of file
diff --git a/src/strongname/api/.gitmirror b/src/strongname/api/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/strongname/api/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/strongname/api/CMakeLists.txt b/src/strongname/api/CMakeLists.txt
new file mode 100644
index 0000000000..1eeed75267
--- /dev/null
+++ b/src/strongname/api/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+#this will again add vm to include directories. However, this will add vm to be the first include folder.
+#This is required because util.hpp is also present in ildasm folder and so due to ordering wrong util.hpp
+#is pickedup.
+include_directories(BEFORE ${VM_DIR})
+
+include_directories(${VM_DIR}/${ARCH_SOURCES_DIR})
+include_directories(${CLR_DIR}/src/md/compiler)
+
+add_definitions(-DSTRONGNAME_IN_VM -DSNAPI_INTERNAL)
+
+set(STRONGNAME_SOURCES
+ strongname.cpp
+ strongnamecoreclr.cpp
+ strongnameinternal.cpp
+)
+
+convert_to_absolute_path(STRONGNAME_SOURCES ${STRONGNAME_SOURCES})
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIC)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_subdirectory(dac)
+add_subdirectory(wks) \ No newline at end of file
diff --git a/src/strongname/api/api.props b/src/strongname/api/api.props
new file mode 100644
index 0000000000..2c4c278a69
--- /dev/null
+++ b/src/strongname/api/api.props
@@ -0,0 +1,43 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <PropertyGroup>
+ <UserIncludes>
+ $(UserIncludes);
+ $(Clrbase)\src\StrongName\inc;
+ $(Clrbase)\src\inc;
+ $(Clrbase)\src\md\inc;
+ $(Clrbase)\src\md\compiler;
+ $(Clrbase)\src\vm
+ </UserIncludes>
+
+ <UserIncludes Condition="'$(StrongnameInVm)' == 'true'">
+ $(UserIncludes);
+ $(Clrbase)\src\vm\$(TargetCpu)
+ </UserIncludes>
+
+ <CDefines Condition="'$(StrongnameInVm)' == 'true'">$(CDefines);STRONGNAME_IN_VM</CDefines>
+
+ <CDefines>$(CDefines);SNAPI_INTERNAL</CDefines>
+ <CDefines>$(CDefines);UNICODE;_UNICODE</CDefines>
+
+ <OutputPath>$(ClrLibDest)</OutputPath>
+ <TargetType>LIBRARY</TargetType>
+
+ <PCHHeader>common.h</PCHHeader>
+ <EnableCxxPCHHeaders>true</EnableCxxPCHHeaders>
+ <PCHCompile>$(Clrbase)\src\StrongName\api\common.cpp</PCHCompile>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="$(ClrSrcDirectory)inc\corguids.nativeproj">
+ <Comment>clrinternal.h</Comment>
+ </ProjectReference>
+ </ItemGroup>
+
+ <ItemGroup>
+ <CppCompile Include="$(Clrbase)\src\StrongName\api\strongname.cpp" />
+ <CppCompile Include="$(Clrbase)\src\StrongName\api\strongnamecoreclr.cpp" />
+ <CppCompile Include="$(Clrbase)\src\StrongName\api\strongnameinternal.cpp" />
+ </ItemGroup>
+
+</Project> \ No newline at end of file
diff --git a/src/strongname/api/common.cpp b/src/strongname/api/common.cpp
new file mode 100644
index 0000000000..f752dafb41
--- /dev/null
+++ b/src/strongname/api/common.cpp
@@ -0,0 +1,7 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#include "common.h"
+
diff --git a/src/strongname/api/common.h b/src/strongname/api/common.h
new file mode 100644
index 0000000000..45f14a8b2b
--- /dev/null
+++ b/src/strongname/api/common.h
@@ -0,0 +1,404 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//
+// common.h - precompiled headers include for the COM+ Execution Engine
+//
+
+#ifndef _common_h_
+#define _common_h_
+
+#if defined(_MSC_VER) && defined(_X86_) && !defined(FPO_ON)
+#pragma optimize("y", on) // Small critical routines, don't put in EBP frame
+#define FPO_ON 1
+#define COMMON_TURNED_FPO_ON 1
+#endif
+
+#if STRONGNAME_IN_VM
+
+#define USE_COM_CONTEXT_DEF
+
+#ifdef _DEBUG
+#define DEBUG_REGDISPLAY
+#endif
+
+#ifdef _MSC_VER
+
+ // These don't seem useful, so turning them off is no big deal
+#pragma warning(disable:4244) // loss of data int -> char ..
+
+#ifndef DEBUG
+#pragma warning(disable:4189) // local variable initialized but not used
+#pragma warning(disable:4505) // unreferenced local function has been removed
+#pragma warning(disable:4313) // 'format specifier' in format string conflicts with argument %d of type 'type'
+#endif // !DEBUG
+
+
+#endif // _MSC_VER
+
+#endif // STRONGNAME_IN_VM
+
+#define _CRT_DEPENDENCY_ //this code depends on the crt file functions
+
+
+#include <stdint.h>
+#include <winwrap.h>
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <winnt.h>
+#include <crosscomp.h>
+#include <clrnt.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <objbase.h>
+#include <stddef.h>
+#include <float.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+
+#include <olectl.h>
+
+#ifdef _MSC_VER
+//non inline intrinsics are faster
+#pragma function(memcpy,memcmp,strcmp,strcpy,strlen,strcat)
+#endif // _MSC_VER
+
+// make all the unsafe redefinitions available
+#include "unsafe.h"
+
+//-----------------------------------------------------------------------------------------------------------
+
+#include "lazycow.h"
+
+#include "compatibilityflags.h"
+extern BOOL GetCompatibilityFlag(CompatibilityFlag flag);
+extern DWORD* GetGlobalCompatibilityFlags();
+
+#include "strongname.h"
+#include "stdmacros.h"
+
+#define POISONC ((UINT_PTR)((sizeof(int *) == 4)?0xCCCCCCCCL:I64(0xCCCCCCCCCCCCCCCC)))
+
+#include "ndpversion.h"
+#include "switches.h"
+#include "holder.h"
+
+#if STRONGNAME_IN_VM
+#include "classnames.h"
+#include "util.hpp"
+#endif // STRONGNAME_IN_VM
+
+#include "corpriv.h"
+
+#include <daccess.h>
+
+#if STRONGNAME_IN_VM
+
+typedef VPTR(class LoaderAllocator) PTR_LoaderAllocator;
+typedef VPTR(class AppDomain) PTR_AppDomain;
+typedef VPTR(class AppDomainBaseObject) PTR_AppDomainBaseObject;
+typedef DPTR(class ArrayBase) PTR_ArrayBase;
+typedef DPTR(class ArrayTypeDesc) PTR_ArrayTypeDesc;
+typedef DPTR(class Assembly) PTR_Assembly;
+typedef DPTR(class AssemblyBaseObject) PTR_AssemblyBaseObject;
+typedef DPTR(class AssemblyNameBaseObject) PTR_AssemblyNameBaseObject;
+typedef VPTR(class BaseDomain) PTR_BaseDomain;
+typedef DPTR(class MscorlibBinder) PTR_MscorlibBinder;
+typedef DPTR(class ClassLoader) PTR_ClassLoader;
+typedef DPTR(class ComCallMethodDesc) PTR_ComCallMethodDesc;
+typedef VPTR(class CompilationDomain) PTR_CompilationDomain;
+typedef DPTR(class ComPlusCallMethodDesc) PTR_ComPlusCallMethodDesc;
+typedef VPTR(class DebugInterface) PTR_DebugInterface;
+typedef DPTR(class Dictionary) PTR_Dictionary;
+typedef VPTR(class DomainAssembly) PTR_DomainAssembly;
+typedef VPTR(class DomainFile) PTR_DomainFile;
+typedef VPTR(class DomainModule) PTR_DomainModule;
+typedef DPTR(struct FailedAssembly) PTR_FailedAssembly;
+typedef VPTR(class EditAndContinueModule) PTR_EditAndContinueModule;
+typedef DPTR(class EEClass) PTR_EEClass;
+typedef DPTR(class DelegateEEClass) PTR_DelegateEEClass;
+typedef DPTR(struct DomainLocalModule) PTR_DomainLocalModule;
+typedef VPTR(class EECodeManager) PTR_EECodeManager;
+typedef DPTR(class EEConfig) PTR_EEConfig;
+typedef VPTR(class EEDbgInterfaceImpl) PTR_EEDbgInterfaceImpl;
+typedef VPTR(class DebugInfoManager) PTR_DebugInfoManager;
+typedef DPTR(class FieldDesc) PTR_FieldDesc;
+typedef VPTR(class Frame) PTR_Frame;
+typedef VPTR(class ICodeManager) PTR_ICodeManager;
+typedef VPTR(class IJitManager) PTR_IJitManager;
+typedef DPTR(class InstMethodHashTable) PTR_InstMethodHashTable;
+typedef DPTR(class MetaSig) PTR_MetaSig;
+typedef DPTR(class MethodDesc) PTR_MethodDesc;
+typedef DPTR(class MethodDescChunk) PTR_MethodDescChunk;
+typedef DPTR(class MethodImpl) PTR_MethodImpl;
+typedef DPTR(class MethodTable) PTR_MethodTable;
+typedef VPTR(class Module) PTR_Module;
+typedef DPTR(class NDirectMethodDesc) PTR_NDirectMethodDesc;
+typedef VPTR(class Thread) PTR_Thread;
+typedef DPTR(class Object) PTR_Object;
+typedef DPTR(PTR_Object) PTR_PTR_Object;
+typedef DPTR(class ObjHeader) PTR_ObjHeader;
+typedef DPTR(class Precode) PTR_Precode;
+typedef VPTR(class ReflectionModule) PTR_ReflectionModule;
+typedef DPTR(class ReflectClassBaseObject) PTR_ReflectClassBaseObject;
+typedef DPTR(class ReflectModuleBaseObject) PTR_ReflectModuleBaseObject;
+typedef DPTR(class ReflectMethodObject) PTR_ReflectMethodObject;
+typedef DPTR(class ReflectFieldObject) PTR_ReflectFieldObject;
+typedef DPTR(class ReJitManager) PTR_ReJitManager;
+typedef DPTR(struct ReJitInfo) PTR_ReJitInfo;
+typedef DPTR(struct SharedReJitInfo) PTR_SharedReJitInfo;
+typedef DPTR(class StringObject) PTR_StringObject;
+typedef DPTR(class StringBufferObject) PTR_StringBufferObject;
+typedef DPTR(class TypeHandle) PTR_TypeHandle;
+#ifdef STUB_DISPATCH
+typedef VPTR(class VirtualCallStubManager) PTR_VirtualCallStubManager;
+typedef VPTR(class VirtualCallStubManagerManager) PTR_VirtualCallStubManagerManager;
+#endif
+typedef VPTR(class GCHeap) PTR_GCHeap;
+
+//
+// _UNCHECKED_OBJECTREF is for code that can't deal with DEBUG OBJECTREFs
+//
+typedef PTR_Object _UNCHECKED_OBJECTREF;
+typedef DPTR(PTR_Object) PTR_UNCHECKED_OBJECTREF;
+
+#ifdef USE_CHECKED_OBJECTREFS
+class OBJECTREF;
+#else
+typedef PTR_Object OBJECTREF;
+#endif
+typedef DPTR(OBJECTREF) PTR_OBJECTREF;
+typedef DPTR(PTR_OBJECTREF) PTR_PTR_OBJECTREF;
+
+
+EXTERN_C Thread* STDCALL GetThread();
+
+// This is a mechanism by which macros can make the Thread pointer available to inner scopes
+// that is robust to code changes. If the outer Thread no longer is available for some reason
+// (e.g. code refactoring), this GET_THREAD() macro will fall back to calling GetThread().
+const bool CURRENT_THREAD_AVAILABLE = false;
+Thread * const CURRENT_THREAD = NULL;
+#define GET_THREAD() (CURRENT_THREAD_AVAILABLE ? CURRENT_THREAD : GetThread())
+
+#define MAKE_CURRENT_THREAD_AVAILABLE() \
+ Thread * __pThread = GET_THREAD(); \
+ MAKE_CURRENT_THREAD_AVAILABLE_EX(__pThread)
+
+#define MAKE_CURRENT_THREAD_AVAILABLE_EX(__pThread) \
+ Thread * CURRENT_THREAD = __pThread; \
+ const bool CURRENT_THREAD_AVAILABLE = true; \
+ (void)CURRENT_THREAD_AVAILABLE; /* silence "local variable initialized but not used" warning */ \
+
+#ifndef DACCESS_COMPILE
+EXTERN_C AppDomain* GetAppDomain();
+#endif //!DACCESS_COMPILE
+
+inline void RetailBreak()
+{
+#if defined(_TARGET_X86_)
+ __asm int 3
+#else
+ DebugBreak();
+#endif
+}
+
+extern BOOL isMemoryReadable(const TADDR start, unsigned len);
+
+#ifndef memcpyUnsafe_f
+#define memcpyUnsafe_f
+
+// use this when you want to memcpy something that contains GC refs
+inline void* memcpyUnsafe(void *dest, const void *src, size_t len)
+{
+ WRAPPER_NO_CONTRACT;
+ return memcpy(dest, src, len);
+}
+
+#endif // !memcpyUnsafe_f
+
+//
+// By default logging, and debug GC are enabled under debug
+//
+// These can be enabled in non-debug by removing the #ifdef _DEBUG
+// allowing one to log/check_gc a free build.
+//
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ // You should be using CopyValueClass if you are doing an memcpy
+ // in the CG heap.
+ #if !defined(memcpy)
+ inline void* memcpyNoGCRefs(void * dest, const void * src, size_t len) {
+ WRAPPER_NO_CONTRACT;
+
+ return memcpy(dest, src, len);
+ }
+ extern "C" void * __cdecl GCSafeMemCpy(void *, const void *, size_t);
+ #define memcpy(dest, src, len) GCSafeMemCpy(dest, src, len)
+ #endif // !defined(memcpy)
+
+ #if !defined(CHECK_APP_DOMAIN_LEAKS)
+ #define CHECK_APP_DOMAIN_LEAKS 1
+ #endif
+#else // !_DEBUG && !DACCESS_COMPILE && !CROSSGEN_COMPILE
+ inline void* memcpyNoGCRefs(void * dest, const void * src, size_t len) {
+ WRAPPER_NO_CONTRACT;
+
+ return memcpy(dest, src, len);
+ }
+#endif // !_DEBUG && !DACCESS_COMPILE && !CROSSGEN_COMPILE
+
+namespace Loader
+{
+ typedef enum
+ {
+ Load, //should load
+ DontLoad, //should not load
+ SafeLookup //take no locks, no allocations
+ } LoadFlag;
+}
+
+#endif // STRONGNAME_IN_VM
+
+// src/inc
+#include "utilcode.h"
+#include "log.h"
+#include "loaderheap.h"
+
+#if STRONGNAME_IN_VM
+
+// src/vm
+#include "util.hpp"
+#include "ibclogger.h"
+#include "eepolicy.h"
+
+#include "vars.hpp"
+#include "crst.h"
+#include "argslot.h"
+#include "stublink.h"
+#include "cgensys.h"
+#include "ceemain.h"
+#include "hash.h"
+#include "eecontract.h"
+#include "pedecoder.h"
+#include "sstring.h"
+#include "slist.h"
+
+#include "eeconfig.h"
+
+#include "spinlock.h"
+#include "objecthandle.h"
+#include "cgensys.h"
+#include "declsec.h"
+
+#ifdef FEATURE_COMINTEROP
+#include "stdinterfaces.h"
+#endif
+
+#include "typehandle.h"
+#include "perfcounters.h"
+#include "methodtable.h"
+#include "typectxt.h"
+
+#include "eehash.h"
+
+#include "handletable.h"
+#include "vars.hpp"
+#include "eventstore.hpp"
+
+#include "synch.h"
+#include "regdisp.h"
+#include "stackframe.h"
+#include "gms.h"
+#include "stackprobe.h"
+#include "fcall.h"
+#include "syncblk.h"
+#include "gcdesc.h"
+#include "specialstatics.h"
+#include "object.h" // <NICE> We should not really need to put this so early... </NICE>
+#include "gchelpers.h"
+#include "pefile.h"
+#include "clrex.h"
+#include "clsload.hpp" // <NICE> We should not really need to put this so early... </NICE>
+#include "siginfo.hpp"
+#include "binder.h"
+#include "jitinterface.h" // <NICE> We should not really need to put this so early... </NICE>
+#include "ceeload.h"
+#include "memberload.h"
+#include "genericdict.h"
+#include "class.h"
+#include "codeman.h"
+#include "threads.h"
+#include "clrex.inl"
+#include "loaderallocator.hpp"
+#include "appdomain.hpp"
+#include "assembly.hpp"
+#include "pefile.inl"
+#include "excep.h"
+#include "method.hpp"
+#include "frames.h"
+
+#include "stackwalk.h"
+#include "stackingallocator.h"
+#include "interoputil.h"
+#include "wrappers.h"
+#include "dynamicmethod.h"
+
+
+HRESULT EnsureRtlFunctions();
+HINSTANCE GetModuleInst();
+
+
+#if defined(_DEBUG)
+
+// This catches CANNOTTHROW macros that occur outside the scope of a CONTRACT.
+// Note that it's important for m_CannotThrowLineNums to be NULL.
+struct DummyGlobalContract
+{
+ int *m_CannotThrowLineNums; //= NULL;
+ LPVOID *m_CannotThrowRecords; //= NULL;
+};
+
+extern DummyGlobalContract ___contract;
+
+#endif // defined(_DEBUG)
+
+// For down level platform compiles.
+#if !defined(_WIN64) && (_WIN32_WINNT < 0x0500)
+typedef VOID (__stdcall *WAITORTIMERCALLBACK)(PVOID, BOOL);
+#endif
+
+
+
+// All files get to see all of these .inl files to make sure all files
+// get the benefit of inlining.
+#include "ceeload.inl"
+#include "typedesc.inl"
+#include "class.inl"
+#include "methodtable.inl"
+#include "typehandle.inl"
+#include "object.inl"
+#include "ceeload.inl"
+#include "clsload.inl"
+#include "domainfile.inl"
+#include "handletable.inl"
+#include "clsload.inl"
+#include "method.inl"
+#include "stackprobe.inl"
+#include "syncblk.inl"
+#include "threads.inl"
+#include "eehash.inl"
+
+#endif // STRONGNAME_IN_VM
+
+#include "pedecoder.h"
+
+#if defined(COMMON_TURNED_FPO_ON)
+#pragma optimize("", on) // Go back to command line default optimizations
+#undef COMMON_TURNED_FPO_ON
+#undef FPO_ON
+#endif
+
+#endif // !_common_h_
diff --git a/src/strongname/api/crossgen/.gitmirror b/src/strongname/api/crossgen/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/strongname/api/crossgen/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/strongname/api/crossgen/strongname_crossgen.nativeproj b/src/strongname/api/crossgen/strongname_crossgen.nativeproj
new file mode 100644
index 0000000000..55e7cc8cd9
--- /dev/null
+++ b/src/strongname/api/crossgen/strongname_crossgen.nativeproj
@@ -0,0 +1,18 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" />
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <PropertyGroup>
+ <StrongnameInVm>true</StrongnameInVm>
+ </PropertyGroup>
+ <Import Project="$(ClrBase)\src\strongname\api\api.props" />
+
+ <PropertyGroup>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>strongname_crossgen</OutputName>
+ </PropertyGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/strongname/api/cryptapis.h b/src/strongname/api/cryptapis.h
new file mode 100644
index 0000000000..d5b22a8abd
--- /dev/null
+++ b/src/strongname/api/cryptapis.h
@@ -0,0 +1,48 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+// ===========================================================================
+// File: CryptApis.h
+//
+// CryptoAPI entry points used for StrongName implementation. This file is
+// included multiple times with different definitions of the DEFINE_IMPORT
+// macro in order handle dynamically finding these entry points.
+// ===========================================================================
+
+#ifndef DEFINE_IMPORT
+#error Must define DEFINE_IMPORT macro before including this file
+#endif
+
+// DEFINE_IMPORT parameters are:
+// 1) Function name (remember to add A to functions that take strings, don't
+// use W versions since they're unsupported on Win9X).
+// 2) Paranthesised argument types (return type is always assumed to be
+// BOOLEAN).
+// 3) TRUE if function is required, FALSE if it is optional (calls will not
+// fail because the function can't be found).
+
+DEFINE_IMPORT(CryptAcquireContextA, (HCRYPTPROV*, LPCSTR, LPCSTR, DWORD, DWORD), TRUE)
+DEFINE_IMPORT(CryptAcquireContextW, (HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD), TRUE)
+DEFINE_IMPORT(CryptReleaseContext, (HCRYPTPROV, DWORD), TRUE)
+DEFINE_IMPORT(CryptCreateHash, (HCRYPTPROV, ALG_ID, HCRYPTKEY, DWORD, HCRYPTHASH*), TRUE)
+DEFINE_IMPORT(CryptDestroyHash, (HCRYPTHASH), TRUE)
+DEFINE_IMPORT(CryptHashData, (HCRYPTHASH, CONST BYTE*, DWORD, DWORD), TRUE)
+DEFINE_IMPORT(CryptGetHashParam, (HCRYPTHASH, DWORD, BYTE*, DWORD*, DWORD), TRUE)
+DEFINE_IMPORT(CryptImportKey, (HCRYPTPROV, CONST BYTE*, DWORD, HCRYPTKEY, DWORD, HCRYPTKEY*), TRUE)
+DEFINE_IMPORT(CryptExportKey, (HCRYPTKEY, HCRYPTKEY, DWORD, DWORD, BYTE*, DWORD*), TRUE)
+DEFINE_IMPORT(CryptGenKey, (HCRYPTPROV, ALG_ID, DWORD, HCRYPTKEY*), TRUE)
+DEFINE_IMPORT(CryptGetKeyParam, (HCRYPTKEY, DWORD, BYTE*, DWORD*, DWORD), TRUE)
+DEFINE_IMPORT(CryptDestroyKey, (HCRYPTKEY), TRUE)
+DEFINE_IMPORT(CryptVerifySignatureA, (HCRYPTHASH, CONST BYTE*, DWORD, HCRYPTKEY, LPCSTR, DWORD), TRUE)
+DEFINE_IMPORT(CryptVerifySignatureW, (HCRYPTHASH, CONST BYTE*, DWORD, HCRYPTKEY, LPCWSTR, DWORD), TRUE)
+DEFINE_IMPORT(CryptSignHashA, (HCRYPTHASH, DWORD, LPCSTR, DWORD, BYTE*, DWORD*), TRUE)
+DEFINE_IMPORT(CryptSignHashW, (HCRYPTHASH, DWORD, LPCWSTR, DWORD, BYTE*, DWORD*), TRUE)
+
+DEFINE_IMPORT(CryptGetProvParam, (HCRYPTPROV, DWORD, BYTE*, DWORD*, DWORD), TRUE)
+DEFINE_IMPORT(CryptGetUserKey, (HCRYPTPROV, DWORD, HCRYPTKEY*), TRUE)
+DEFINE_IMPORT(CryptEnumProvidersA, (DWORD, DWORD*, DWORD, DWORD*, LPSTR, DWORD*), FALSE)
+DEFINE_IMPORT(CryptEnumProvidersW, (DWORD, DWORD*, DWORD, DWORD*, LPWSTR, DWORD*), FALSE)
+
+#undef DEFINE_IMPORT
diff --git a/src/strongname/api/dac/.gitmirror b/src/strongname/api/dac/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/strongname/api/dac/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/strongname/api/dac/CMakeLists.txt b/src/strongname/api/dac/CMakeLists.txt
new file mode 100644
index 0000000000..5278a67d83
--- /dev/null
+++ b/src/strongname/api/dac/CMakeLists.txt
@@ -0,0 +1,4 @@
+
+include(${CLR_DIR}/dac.cmake)
+
+add_library(strongname_dac ${STRONGNAME_SOURCES})
diff --git a/src/strongname/api/dac/dirs.proj b/src/strongname/api/dac/dirs.proj
new file mode 100644
index 0000000000..6ca01ad4ad
--- /dev/null
+++ b/src/strongname/api/dac/dirs.proj
@@ -0,0 +1,19 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="HostLocal\strongname_dac.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/strongname/api/dirs.proj b/src/strongname/api/dirs.proj
new file mode 100644
index 0000000000..996632d796
--- /dev/null
+++ b/src/strongname/api/dirs.proj
@@ -0,0 +1,22 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="dac\dirs.proj" />
+ <ProjectFile Condition="'$(BuildProjectName)' != 'CoreSys'" Include="standalone\strongname.nativeproj" />
+ <ProjectFile Condition="'$(BuildProjectName)' != 'CoreSys'" Include="standalone-winrt\strongname-winrt.nativeproj" />
+ <ProjectFile Include="wks\strongname_wks.nativeproj" />
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/strongname/api/strongname.cpp b/src/strongname/api/strongname.cpp
new file mode 100644
index 0000000000..ec91fe8788
--- /dev/null
+++ b/src/strongname/api/strongname.cpp
@@ -0,0 +1,4988 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+// ===========================================================================
+// File: StrongName.cpp
+//
+// Wrappers for signing and hashing functions needed to implement strong names
+// ===========================================================================
+
+#include "common.h"
+#include <imagehlp.h>
+
+#include <winwrap.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <cor.h>
+#include <corimage.h>
+#include <metadata.h>
+#include <daccess.h>
+#include <limits.h>
+#include <ecmakey.h>
+#include <sha1.h>
+
+#include "strongname.h"
+#include "ex.h"
+#include "pedecoder.h"
+#include "strongnameholders.h"
+#include "strongnameinternal.h"
+#include "common.h"
+#include "classnames.h"
+
+// Debug logging.
+#if !defined(_DEBUG) || defined(DACCESS_COMPILE)
+#define SNLOG(args)
+#endif // !_DEBUG || DACCESS_COMPILE
+
+#ifndef DACCESS_COMPILE
+
+// Debug logging.
+#if defined(_DEBUG)
+#include <stdarg.h>
+
+BOOLEAN g_fLoggingInitialized = FALSE;
+DWORD g_dwLoggingFlags = FALSE;
+
+#define SNLOG(args) Log args
+
+void Log(__in_z const WCHAR *wszFormat, ...)
+{
+ if (g_fLoggingInitialized && !g_dwLoggingFlags)
+ return;
+
+ DWORD dwError = GetLastError();
+
+ if (!g_fLoggingInitialized) {
+ g_dwLoggingFlags = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MscorsnLogging);
+ g_fLoggingInitialized = TRUE;
+ }
+
+ if (!g_dwLoggingFlags) {
+ SetLastError(dwError);
+ return;
+ }
+
+ va_list pArgs;
+ WCHAR wszBuffer[1024];
+ static WCHAR wszPrefix[] = W("SN: ");
+
+ wcscpy_s(wszBuffer, COUNTOF(wszBuffer), wszPrefix);
+
+ va_start(pArgs, wszFormat);
+ _vsnwprintf_s(&wszBuffer[COUNTOF(wszPrefix) - 1],
+ COUNTOF(wszBuffer) - COUNTOF(wszPrefix),
+ _TRUNCATE,
+ wszFormat,
+ pArgs);
+
+ wszBuffer[COUNTOF(wszBuffer) - 1] = W('\0');
+ va_end(pArgs);
+
+ if (g_dwLoggingFlags & 1)
+ wprintf(W("%s"), wszBuffer);
+ if (g_dwLoggingFlags & 2)
+ WszOutputDebugString(wszBuffer);
+ if (g_dwLoggingFlags & 4)
+ {
+ MAKE_UTF8PTR_FROMWIDE_NOTHROW(szMessage, wszBuffer);
+ if(szMessage != NULL)
+ LOG((LF_SECURITY, LL_INFO100, szMessage));
+ }
+
+ SetLastError(dwError);
+}
+
+#endif // _DEBUG
+
+// Size in bytes of strong name token.
+#define SN_SIZEOF_TOKEN 8
+
+enum StrongNameCachedCsp {
+ None = -1,
+ Sha1CachedCsp = 0,
+ Sha2CachedCsp = Sha1CachedCsp + 1,
+ CachedCspCount = Sha2CachedCsp + 1
+};
+
+// We cache a couple of things on a per thread basis: the last error encountered
+// and (potentially) CSP contexts. The following structure tracks these and is
+// allocated lazily as needed.
+struct SN_THREAD_CTX {
+ DWORD m_dwLastError;
+#if !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+ HCRYPTPROV m_hProv[CachedCspCount];
+#endif // !FEATURE_CORECLR || CROSSGEN_COMPILE
+};
+
+#endif // !DACCESS_COMPILE
+
+// Macro containing common code used at the start of most APIs.
+#define SN_COMMON_PROLOG() do { \
+ HRESULT __hr = InitStrongName(); \
+ if (FAILED(__hr)) { \
+ SetStrongNameErrorInfo(__hr); \
+ retVal = FALSE; \
+ goto Exit; \
+ } \
+ SetStrongNameErrorInfo(S_OK); \
+} while (0)
+
+// Macro to return an error from a SN entrypoint API
+#define SN_ERROR(__hr) do { \
+ if (FAILED(__hr)) { \
+ SetStrongNameErrorInfo(__hr); \
+ retVal = FALSE; \
+ goto Exit; \
+ } \
+} while (false)
+
+// Determine the size of a PublicKeyBlob structure given the size of the key
+// portion.
+#define SN_SIZEOF_KEY(_pKeyBlob) (offsetof(PublicKeyBlob, PublicKey) + GET_UNALIGNED_VAL32(&(_pKeyBlob)->cbPublicKey))
+
+// We allow a special abbreviated form of the Microsoft public key (16 bytes
+// long: 0 for both alg ids, 4 for key length and 4 bytes of 0 for the key
+// itself). This allows us to build references to system libraries that are
+// platform neutral (so a 3rd party can build mscorlib replacements). The
+// special zero PK is just shorthand for the local runtime's real system PK,
+// which is always used to perform the signature verification, so no security
+// hole is opened by this. Therefore we need to store a copy of the real PK (for
+// this platform) here.
+
+// the actual definition of the microsoft key is in separate file to allow custom keys
+#include "thekey.h"
+
+
+#define SN_THE_KEY() ((PublicKeyBlob*)g_rbTheKey)
+#define SN_SIZEOF_THE_KEY() sizeof(g_rbTheKey)
+
+#define SN_THE_KEYTOKEN() ((PublicKeyBlob*)g_rbTheKeyToken)
+
+// Determine if the given public key blob is the neutral key.
+#define SN_IS_NEUTRAL_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbNeutralPublicKey) && \
+ memcmp((_pk), g_rbNeutralPublicKey, sizeof(g_rbNeutralPublicKey)) == 0)
+
+#define SN_IS_THE_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbTheKey) && \
+ memcmp((_pk), g_rbTheKey, sizeof(g_rbTheKey)) == 0)
+
+
+#ifdef FEATURE_CORECLR
+
+// Silverlight platform key
+#define SN_THE_SILVERLIGHT_PLATFORM_KEYTOKEN() ((PublicKeyBlob*)g_rbTheSilverlightPlatformKeyToken)
+#define SN_IS_THE_SILVERLIGHT_PLATFORM_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbTheSilverlightPlatformKey) && \
+ memcmp((_pk), g_rbTheSilverlightPlatformKey, sizeof(g_rbTheSilverlightPlatformKey)) == 0)
+
+// Silverlight key
+#define SN_IS_THE_SILVERLIGHT_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbTheSilverlightKey) && \
+ memcmp((_pk), g_rbTheSilverlightKey, sizeof(g_rbTheSilverlightKey)) == 0)
+
+#define SN_THE_SILVERLIGHT_KEYTOKEN() ((PublicKeyBlob*)g_rbTheSilverlightKeyToken)
+
+#ifdef FEATURE_WINDOWSPHONE
+// Microsoft.Phone.* key
+#define SN_THE_MICROSOFT_PHONE_KEYTOKEN() ((PublicKeyBlob*)g_rbTheMicrosoftPhoneKeyToken)
+
+#define SN_IS_THE_MICROSOFT_PHONE_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbTheMicrosoftPhoneKey) && \
+ memcmp((_pk), g_rbTheMicrosoftPhoneKey, sizeof(g_rbTheMicrosoftPhoneKey)) == 0)
+
+// Microsoft.Xna.* key
+#define SN_THE_MICROSOFT_XNA_KEYTOKEN() ((PublicKeyBlob*)g_rbTheMicrosoftXNAKeyToken)
+
+#define SN_IS_THE_MICROSOFT_XNA_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbTheMicrosoftXNAKey) && \
+ memcmp((_pk), g_rbTheMicrosoftXNAKey, sizeof(g_rbTheMicrosoftXNAKey)) == 0)
+
+#endif // FEATURE_WINDOWSPHONE
+#endif // FEATURE_CORECLR
+
+#if !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+#include "caparser.h"
+#include "custattr.h"
+#include "cahlprinternal.h"
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+// The maximum length of CSP name we support (in characters).
+#define SN_MAX_CSP_NAME 1024
+
+// If we're being built as a standalone library, then we shouldn't redirect through the hosting APIs
+#if !STRONGNAME_IN_VM
+
+#undef MapViewOfFile
+#undef UnmapViewOfFile
+
+#define CLRMapViewOfFile MapViewOfFile
+#define CLRUnmapViewOfFile UnmapViewOfFile
+
+#if FEATURE_STANDALONE_SN && !FEATURE_CORECLR
+
+// We will need to call into shim, therefore include new hosting APIs
+#include "metahost.h"
+#include "clrinternal.h"
+
+#endif //FEATURE_STANDALONE_SN && !FEATURE_CORECLR
+
+#define DONOT_DEFINE_ETW_CALLBACK
+
+#endif // !STRONGNAME_IN_VM
+#include "eventtracebase.h"
+
+#ifndef DACCESS_COMPILE
+
+// Flag indicating whether the initialization of the strong name APIs has been completed.
+BOOLEAN g_bStrongNamesInitialized = FALSE;
+
+// Flag indicating whether it's OK to cache the results of verifying an assembly
+// whose file is accessible to users.
+BOOLEAN g_fCacheVerify = TRUE;
+
+// Algorithm IDs for hashing and signing. Like the CSP name, these values are
+// read from the registry at initialization time.
+ALG_ID g_uHashAlgId;
+ALG_ID g_uSignAlgId;
+
+// Flag read from the registry at initialization time. It controls the key spec
+// to be used. AT_SIGNATURE will be the default.
+DWORD g_uKeySpec;
+
+// CSP provider type. PROV_RSA_FULL will be the default.
+DWORD g_uProvType;
+
+// Critical section used to serialize some non-thread safe crypto APIs.
+CRITSEC_COOKIE g_rStrongNameMutex = NULL;
+
+// Name of CSP to use. This is read from the registry at initialization time. If
+// not found we look up a CSP by hashing and signing algorithms (see below) or
+// use the default CSP.
+
+BOOLEAN g_bHasCSPName = FALSE;
+WCHAR g_wszCSPName[SN_MAX_CSP_NAME + 1] = {0};
+
+// Flag read from the registry at initialization time. Controls whether we use
+// machine or user based key containers.
+BOOLEAN g_bUseMachineKeyset = TRUE;
+
+#ifdef FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+// Verification Skip Records
+//
+// These are entries in the registry (usually set up by SN) that control whether
+// an assembly needs to pass signature verification to be considered valid (i.e.
+// return TRUE from StrongNameSignatureVerification). This is useful during
+// development when it's not feasible to fully sign each assembly on each build.
+// Assemblies to be skipped can be specified by name and public key token, all
+// assemblies with a given public key token or just all assemblies. Each entry
+// can be further qualified by a list of user names to which the records
+// applies. When matching against an entry, the most specific one wins.
+//
+// We read these entries at startup time and place them into a global, singly
+// linked, NULL terminated list.
+
+// Structure used to represent each record we find in the registry.
+struct SN_VER_REC {
+ SN_VER_REC *m_pNext; // Pointer to next record (or NULL)
+ WCHAR *m_wszAssembly; // Assembly name/public key token as a string
+ WCHAR *m_mszUserList; // Pointer to multi-string list of valid users (or NULL)
+ WCHAR *m_wszTestPublicKey; // Test public key to use during strong name verification (or NULL)
+};
+
+// Head of the list of entries we found in the registry during initialization.
+SN_VER_REC *g_pVerificationRecords = NULL;
+#endif // FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+
+struct SN_REPLACEMENT_KEY_REC {
+ SN_REPLACEMENT_KEY_REC *m_pNext;
+ BYTE *m_pbReplacementKey;
+ ULONG m_cbReplacementKey;
+};
+
+struct SN_REVOCATION_REC {
+ SN_REVOCATION_REC *m_pNext;
+ BYTE *m_pbRevokedKey;
+ ULONG m_cbRevokedKey;
+ SN_REPLACEMENT_KEY_REC *m_pReplacementKeys;
+};
+
+SN_REVOCATION_REC *g_pRevocationRecords = NULL;
+
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+#endif // #ifndef DACCESS_COMPILE
+
+
+
+#include "thetestkey.h"
+
+#ifndef DACCESS_COMPILE
+
+// The actions that can be performed upon opening a CSP with LocateCSP.
+#define SN_OPEN_CONTAINER 0
+#define SN_IGNORE_CONTAINER 1
+#define SN_CREATE_CONTAINER 2
+#define SN_DELETE_CONTAINER 3
+#define SN_HASH_SHA1_ONLY 4
+
+// Macro to aid in setting flags for CryptAcquireContext based on container
+// actions above.
+#define SN_CAC_FLAGS(_act) \
+ (((_act) == SN_OPEN_CONTAINER ? 0 : \
+ ((_act) == SN_HASH_SHA1_ONLY) || ((_act) == SN_IGNORE_CONTAINER) ? CRYPT_VERIFYCONTEXT : \
+ (_act) == SN_CREATE_CONTAINER ? CRYPT_NEWKEYSET : \
+ (_act) == SN_DELETE_CONTAINER ? CRYPT_DELETEKEYSET : \
+ 0) | \
+ (g_bUseMachineKeyset ? CRYPT_MACHINE_KEYSET : 0))
+
+// Substitute a strong name error if the error we're wrapping is not transient
+FORCEINLINE HRESULT SubstituteErrorIfNotTransient(HRESULT hrOriginal, HRESULT hrSubstitute)
+{
+ return Exception::IsTransient(hrOriginal) ? hrOriginal : hrSubstitute;
+}
+
+// Private routine prototypes.
+SN_THREAD_CTX *GetThreadContext();
+VOID SetStrongNameErrorInfo(DWORD dwStatus);
+HCRYPTPROV LocateCSP(LPCWSTR wszKeyContainer,
+ DWORD dwAction,
+ ALG_ID uHashAlgId = 0,
+ ALG_ID uSignAlgId = 0);
+VOID FreeCSP(HCRYPTPROV hProv);
+HCRYPTPROV LookupCachedCSP(StrongNameCachedCsp cspNumber);
+VOID CacheCSP(HCRYPTPROV hProv, StrongNameCachedCsp cspNumber);
+BOOLEAN IsCachedCSP(HCRYPTPROV hProv);
+HRESULT ReadRegistryConfig();
+BOOLEAN LoadCryptoApis();
+#ifdef FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+HRESULT ReadVerificationRecords();
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+HRESULT ReadRevocationRecords();
+#endif // FEATURE_STRONGNAME_MIGRATION
+SN_VER_REC *GetVerificationRecord(__in_z __deref LPWSTR wszAssemblyName, PublicKeyBlob *pPublicKey);
+#endif // FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+
+BOOLEAN IsValidUser(__in_z WCHAR *mszUserList);
+BOOLEAN GetKeyContainerName(LPCWSTR *pwszKeyContainer, BOOLEAN *pbTempContainer);
+VOID FreeKeyContainerName(LPCWSTR wszKeyContainer, BOOLEAN bTempContainer);
+HRESULT GetMetadataImport(__in const SN_LOAD_CTX *pLoadCtx,
+ __in mdAssembly *ptkAssembly,
+ __out IMDInternalImport **ppMetaDataImport);
+HRESULT FindPublicKey(const SN_LOAD_CTX *pLoadCtx,
+ __out_ecount_opt(cchAssemblyName) LPWSTR wszAssemblyName,
+ DWORD cchAssemblyName,
+ __out PublicKeyBlob **ppPublicKey,
+ DWORD *pcbPublicKey = NULL);
+PublicKeyBlob *GetPublicKeyFromHex(LPCWSTR wszPublicKeyHexString);
+BOOLEAN RehashModules(SN_LOAD_CTX *pLoadCtx, LPCWSTR szFilePath);
+HRESULT VerifySignature(SN_LOAD_CTX *pLoadCtx,
+ DWORD dwInFlags,
+ PublicKeyBlob *pRealEcmaPublicKey,
+ DWORD *pdwOutFlags);
+HRESULT InitStrongNameCriticalSection();
+HRESULT InitStrongName();
+typedef BOOLEAN (*HashFunc)(HCRYPTHASH hHash, PBYTE start, DWORD length, DWORD flags, void* cookie);
+BOOLEAN ComputeHash(SN_LOAD_CTX *pLoadCtx, HCRYPTHASH hHash, HashFunc func, void* cookie);
+bool VerifyKeyMatchesAssembly(PublicKeyBlob * pAssemblySignaturePublicKey, __in_z LPCWSTR wszKeyContainer, BYTE *pbKeyBlob, ULONG cbKeyBlob, DWORD dwFlags);
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+HRESULT GetVerifiedSignatureKey(__in SN_LOAD_CTX *pLoadCtx, __out PublicKeyBlob **ppPublicKey, __out DWORD *pcbPublicKey = NULL);
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+
+void DbgCount(__in_z WCHAR *szCounterName)
+{
+
+#ifndef FEATURE_CORECLR
+ if (g_fLoggingInitialized && !(g_dwLoggingFlags & 4))
+ return;
+
+ DWORD dwError = GetLastError();
+
+ if (!g_fLoggingInitialized) {
+ g_dwLoggingFlags = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MscorsnLogging);
+ g_fLoggingInitialized = TRUE;
+ }
+
+ if (!(g_dwLoggingFlags & 4)) {
+ SetLastError(dwError);
+ return;
+ }
+
+ HKEY hKey = NULL;
+ DWORD dwCounter = 0;
+ DWORD dwBytes;
+
+ if (WszRegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ SN_CONFIG_KEY_W W("\\Counters"),
+ 0,
+ NULL,
+ 0,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hKey,
+ NULL) != ERROR_SUCCESS)
+ goto End;
+
+ WszRegQueryValueEx(hKey, szCounterName, NULL, NULL, (BYTE*)&dwCounter, &dwBytes);
+ dwCounter++;
+ WszRegSetValueEx(hKey, szCounterName, NULL, REG_DWORD, (BYTE*)&dwCounter, sizeof(DWORD));
+
+ End:
+ if (hKey)
+ RegCloseKey(hKey);
+ SetLastError(dwError);
+
+#endif //#ifndef FEATURE_CORECLR
+
+}
+
+
+void HexDump(BYTE *pbData,
+ DWORD cbData)
+{
+ if (g_dwLoggingFlags == 0)
+ return;
+
+ DWORD dwRow, dwCol;
+ WCHAR wszBuffer[1024];
+ WCHAR *wszPtr = wszBuffer;
+
+#define SN_PUSH0(_fmt) do { wszPtr += swprintf_s(wszPtr, COUNTOF(wszBuffer) - (wszPtr - wszBuffer), _fmt); } while (false)
+#define SN_PUSH1(_fmt, _arg1) do { wszPtr += swprintf_s(wszPtr, COUNTOF(wszBuffer) - (wszPtr - wszBuffer), _fmt, _arg1); } while (false)
+
+ wszBuffer[0] = W('\0');
+
+ for (dwRow = 0; dwRow < ((cbData + 15) / 16); dwRow++) {
+ SN_PUSH1(W("%08p "), pbData + (16 * dwRow));
+ for (dwCol = 0; dwCol < 16; dwCol++)
+ if (((dwRow * 16) + dwCol) < cbData)
+ SN_PUSH1(W("%02X "), pbData[(dwRow * 16) + dwCol]);
+ else
+ SN_PUSH0(W(" "));
+ for (dwCol = 0; dwCol < 16; dwCol++)
+ if (((dwRow * 16) + dwCol) < cbData) {
+ unsigned char c = pbData[(dwRow * 16) + dwCol];
+ if ((c >= 32) && (c <= 127))
+ SN_PUSH1(W("%c"), c);
+ else
+ SN_PUSH0(W("."));
+ } else
+ SN_PUSH0(W(" "));
+ SN_PUSH0(W("\n"));
+ }
+#undef SN_PUSH1
+#undef SN_PUSH0
+
+ _ASSERTE(wszPtr < &wszBuffer[COUNTOF(wszBuffer)]);
+
+ Log(W("%s"), wszBuffer);
+}
+
+#else // _DEBUG && !DACCESS_COMPILE
+
+#define HexDump(x)
+#define DbgCount(x)
+
+#endif // _DEBUG && !DACCESS_COMPILE
+
+
+BOOLEAN CalculateSize(HCRYPTHASH hHash, PBYTE start, DWORD length, DWORD flags, void* cookie)
+{
+ *(size_t*)cookie += length;
+ return TRUE;
+}
+
+struct CopyDataBufferDesc
+{
+ PBYTE pbData;
+ DWORD cbDataSize;
+};
+
+BOOLEAN CopyData(HCRYPTHASH hHash, PBYTE start, DWORD length, DWORD flags, void* cookie)
+{
+ _ASSERTE(cookie);
+
+ CopyDataBufferDesc *pBuffer = reinterpret_cast<CopyDataBufferDesc *>(cookie);
+ _ASSERTE(pBuffer->pbData);
+
+ memcpy_s(pBuffer->pbData, pBuffer->cbDataSize, start, length);
+ pBuffer->pbData += length;
+
+ _ASSERTE(pBuffer->cbDataSize >= length);
+ pBuffer->cbDataSize = pBuffer->cbDataSize >= length ? pBuffer->cbDataSize - length : 0;
+
+ return TRUE;
+}
+
+BOOLEAN CalcHash(HCRYPTHASH hHash, PBYTE start, DWORD length, DWORD flags, void* cookie)
+{
+ return CryptHashData(hHash, start, length, flags);
+}
+
+VOID
+WINAPI Fls_Callback (
+ IN PVOID lpFlsData
+ )
+{
+ STATIC_CONTRACT_SO_TOLERANT;
+ SN_THREAD_CTX *pThreadCtx = (SN_THREAD_CTX*)lpFlsData;
+ if (pThreadCtx != NULL) {
+ for(ULONG i = 0; i < CachedCspCount; i++)
+ {
+ if (pThreadCtx->m_hProv[i])
+ CryptReleaseContext(pThreadCtx->m_hProv[i], 0);
+ }
+
+ delete pThreadCtx;
+ }
+}
+
+HRESULT InitStrongNameCriticalSection()
+{
+ if (g_rStrongNameMutex)
+ return S_OK;
+
+ CRITSEC_COOKIE pv = ClrCreateCriticalSection(CrstStrongName, CRST_DEFAULT);
+ if (pv == NULL)
+ return E_OUTOFMEMORY;
+
+ if (InterlockedCompareExchangeT(&g_rStrongNameMutex, pv, NULL) != NULL)
+ ClrDeleteCriticalSection(pv);
+ return S_OK;
+}
+
+HRESULT InitStrongName()
+{
+ HRESULT hr = S_OK;
+ if (g_bStrongNamesInitialized)
+ return hr;
+
+ // Read CSP configuration info from the registry (if provided).
+ hr = ReadRegistryConfig();
+ if (FAILED(hr))
+ return hr;
+
+ // Associate a callback for freeing our TLS data.
+ ClrFlsAssociateCallback(TlsIdx_StrongName, Fls_Callback);
+
+ g_bStrongNamesInitialized = TRUE;
+
+ return hr;
+}
+
+// Generate a new key pair for strong name use.
+SNAPI StrongNameKeyGen(LPCWSTR wszKeyContainer, // [in] desired key container name, must be a non-empty string
+ DWORD dwFlags, // [in] flags (see below)
+ BYTE **ppbKeyBlob, // [out] public/private key blob
+ ULONG *pcbKeyBlob)
+{
+ BOOLEAN retVal = FALSE;
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ SN_COMMON_PROLOG();
+
+ if (wszKeyContainer == NULL && ppbKeyBlob == NULL)
+ SN_ERROR(E_INVALIDARG);
+ if (ppbKeyBlob != NULL && pcbKeyBlob == NULL)
+ SN_ERROR(E_POINTER);
+
+ DWORD dwKeySize;
+
+ // We set a key size of 1024 if we're using the default
+ // signing algorithm (RSA), otherwise we leave it at the default.
+ if (g_uSignAlgId == CALG_RSA_SIGN)
+ dwKeySize = 1024;
+ else
+ dwKeySize = 0;
+
+ retVal = StrongNameKeyGenEx(wszKeyContainer, dwFlags, dwKeySize, ppbKeyBlob, pcbKeyBlob);
+
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+// Generate a new key pair with the specified key size for strong name use.
+SNAPI StrongNameKeyGenEx(LPCWSTR wszKeyContainer, // [in] desired key container name, must be a non-empty string
+ DWORD dwFlags, // [in] flags (see below)
+ DWORD dwKeySize, // [in] desired key size.
+ BYTE **ppbKeyBlob, // [out] public/private key blob
+ ULONG *pcbKeyBlob)
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ HCRYPTPROV hProv = NULL;
+ HCRYPTKEY hKey = NULL;
+ BOOLEAN bTempContainer = FALSE;
+
+ SNLOG((W("StrongNameKeyGenEx(\"%s\", %08X, %08X, %08X, %08X)\n"), wszKeyContainer, dwFlags, dwKeySize, ppbKeyBlob, pcbKeyBlob));
+
+ SN_COMMON_PROLOG();
+
+ if (wszKeyContainer == NULL && ppbKeyBlob == NULL)
+ SN_ERROR(E_INVALIDARG);
+ if (ppbKeyBlob != NULL && pcbKeyBlob == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Check to see if a temporary container name is needed.
+ _ASSERTE((wszKeyContainer != NULL) || !(dwFlags & SN_LEAVE_KEY));
+ if (!GetKeyContainerName(&wszKeyContainer, &bTempContainer))
+ {
+ goto Exit;
+ }
+
+ // Open a CSP and container.
+ hProv = LocateCSP(wszKeyContainer, SN_CREATE_CONTAINER);
+ if (!hProv)
+ goto Error;
+
+
+ // Generate the new key pair, try for exportable first.
+ // Note: The key size in bits is encoded in the upper
+ // 16-bits of a DWORD (and OR'd together with other flags for the
+ // CryptGenKey call).
+ if (!CryptGenKey(hProv, g_uKeySpec, (dwKeySize << 16) | CRYPT_EXPORTABLE, &hKey)) {
+ SNLOG((W("Couldn't create exportable key, trying for non-exportable: %08X\n"), GetLastError()));
+ if (!CryptGenKey(hProv, g_uKeySpec, dwKeySize << 16, &hKey)) {
+ SNLOG((W("Couldn't create key pair: %08X\n"), GetLastError()));
+ goto Error;
+ }
+ }
+
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+ if (g_bHasCSPName) {
+ ALG_ID uAlgId;
+ DWORD dwAlgIdLen = sizeof(uAlgId);
+ // Check that signature algorithm used was the one we expected.
+ if (CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)&uAlgId, &dwAlgIdLen, 0)) {
+ _ASSERTE(uAlgId == g_uSignAlgId);
+ } else
+ SNLOG((W("Failed to get key params: %08X\n"), GetLastError()));
+ }
+#endif // _DEBUG
+
+ // If the user wants the key pair back, attempt to export it.
+ if (ppbKeyBlob) {
+
+ // Calculate length of blob first;
+ if (!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, pcbKeyBlob)) {
+ SNLOG((W("Couldn't export key pair: %08X\n"), GetLastError()));
+ goto Error;
+ }
+
+ // Allocate a buffer of the right size.
+ *ppbKeyBlob = new (nothrow) BYTE[*pcbKeyBlob];
+ if (*ppbKeyBlob == NULL) {
+ SetLastError(E_OUTOFMEMORY);
+ goto Error;
+ }
+
+ // Export the key pair.
+ if (!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, *ppbKeyBlob, pcbKeyBlob)) {
+ SNLOG((W("Couldn't export key pair: %08X\n"), GetLastError()));
+ delete[] *ppbKeyBlob;
+ *ppbKeyBlob = NULL;
+ goto Error;
+ }
+ }
+
+ // Destroy the key handle (but not the key pair itself).
+ CryptDestroyKey(hKey);
+ hKey = NULL;
+
+ // Release the CSP.
+ FreeCSP(hProv);
+
+ // If the user didn't explicitly want to keep the key pair around, delete the
+ // key container.
+ if (!(dwFlags & SN_LEAVE_KEY) || bTempContainer)
+ LocateCSP(wszKeyContainer, SN_DELETE_CONTAINER);
+
+ // Free temporary key container name if allocated.
+ FreeKeyContainerName(wszKeyContainer, bTempContainer);
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ if (hKey)
+ CryptDestroyKey(hKey);
+ if (hProv) {
+ FreeCSP(hProv);
+ if (!(dwFlags & SN_LEAVE_KEY) || bTempContainer)
+ LocateCSP(wszKeyContainer, SN_DELETE_CONTAINER);
+ }
+ FreeKeyContainerName(wszKeyContainer, bTempContainer);
+
+ Exit:
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+
+// Import key pair into a key container.
+SNAPI StrongNameKeyInstall(LPCWSTR wszKeyContainer,// [in] desired key container name, must be a non-empty string
+ BYTE *pbKeyBlob, // [in] public/private key pair blob
+ ULONG cbKeyBlob)
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ HCRYPTPROV hProv = NULL;
+ HCRYPTKEY hKey = NULL;
+
+ SNLOG((W("StrongNameKeyInstall(\"%s\", %08X, %08X)\n"), wszKeyContainer, pbKeyBlob, cbKeyBlob));
+
+ SN_COMMON_PROLOG();
+
+ if (wszKeyContainer == NULL)
+ SN_ERROR(E_POINTER);
+ if (pbKeyBlob == NULL)
+ SN_ERROR(E_POINTER);
+ if (cbKeyBlob == 0)
+ SN_ERROR(E_INVALIDARG);
+
+ // Open a CSP and container.
+ hProv = LocateCSP(wszKeyContainer, SN_CREATE_CONTAINER);
+ if (!hProv) {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ goto Exit;
+ }
+
+ // Import the key pair.
+ if (!CryptImportKey(hProv,
+ pbKeyBlob,
+ cbKeyBlob,
+ 0, 0, &hKey)) {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ FreeCSP(hProv);
+ goto Exit;
+ }
+
+ // Release the CSP.
+ FreeCSP(hProv);
+ retVal = TRUE;
+Exit:
+
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+
+// Delete a key pair.
+SNAPI StrongNameKeyDelete(LPCWSTR wszKeyContainer) // [in] desired key container name
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ HCRYPTPROV hProv;
+
+ SNLOG((W("StrongNameKeyDelete(\"%s\")\n"), wszKeyContainer));
+
+ SN_COMMON_PROLOG();
+
+ if (wszKeyContainer == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Open and delete the named container.
+ hProv = LocateCSP(wszKeyContainer, SN_DELETE_CONTAINER);
+ if (hProv) {
+ // Returned handle isn't actually valid in the delete case, so we're
+ // finished.
+ retVal = TRUE;
+ } else {
+ SetStrongNameErrorInfo(CORSEC_E_CONTAINER_NOT_FOUND);
+ retVal = FALSE;
+ }
+Exit:
+
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+
+}
+
+// Retrieve the public portion of a key pair.
+SNAPI StrongNameGetPublicKey (LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbPublicKeyBlob, // [out] public key blob
+ ULONG *pcbPublicKeyBlob)
+{
+ LIMITED_METHOD_CONTRACT;
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ retVal = StrongNameGetPublicKeyEx(
+ wszKeyContainer,
+ pbKeyBlob,
+ cbKeyBlob,
+ ppbPublicKeyBlob,
+ pcbPublicKeyBlob,
+ 0,
+ 0);
+
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+// Holder for any HCRYPTPROV handles allocated by the strong name APIs
+typedef Wrapper<HCRYPTPROV, DoNothing, FreeCSP, 0> HandleStrongNameCspHolder;
+
+
+SNAPI StrongNameGetPublicKeyEx (LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbPublicKeyBlob, // [out] public key blob
+ ULONG *pcbPublicKeyBlob,
+ ULONG uHashAlgId,
+ ULONG uReserved) // reserved for future use as uSigAlgId (signature algorithm id)
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ HandleStrongNameCspHolder hProv(NULL);
+ CapiKeyHolder hKey(NULL);
+ DWORD dwKeyLen;
+ PublicKeyBlob *pKeyBlob;
+ DWORD dwSigAlgIdLen;
+
+ SNLOG((W("StrongNameGetPublicKeyEx(\"%s\", %08X, %08X, %08X, %08X, %08X)\n"), wszKeyContainer, pbKeyBlob, cbKeyBlob, ppbPublicKeyBlob, pcbPublicKeyBlob, uHashAlgId));
+
+ SN_COMMON_PROLOG();
+
+ if (wszKeyContainer == NULL && pbKeyBlob == NULL)
+ SN_ERROR(E_INVALIDARG);
+ if (pbKeyBlob != NULL && !(StrongNameIsEcmaKey(pbKeyBlob, cbKeyBlob) || StrongNameIsValidKeyPair(pbKeyBlob, cbKeyBlob)))
+ SN_ERROR(E_INVALIDARG);
+ if (ppbPublicKeyBlob == NULL)
+ SN_ERROR(E_POINTER);
+ if (pcbPublicKeyBlob == NULL)
+ SN_ERROR(E_POINTER);
+ if (uReserved != 0)
+ SN_ERROR(E_INVALIDARG);
+
+ bool fHashAlgorithmValid;
+ fHashAlgorithmValid = uHashAlgId == 0 ||
+ (GET_ALG_CLASS(uHashAlgId) == ALG_CLASS_HASH && GET_ALG_SID(uHashAlgId) >= ALG_SID_SHA1 && GET_ALG_SID(uHashAlgId) <= ALG_SID_SHA_512);
+ if(!fHashAlgorithmValid)
+ SN_ERROR(E_INVALIDARG);
+
+ if(uHashAlgId == 0)
+ uHashAlgId = g_uHashAlgId;
+
+ // If we're handed a platform neutral public key, just hand it right back to
+ // the user. Well, hand back a copy at least.
+ if (pbKeyBlob && cbKeyBlob && SN_IS_NEUTRAL_KEY(pbKeyBlob)) {
+ *pcbPublicKeyBlob = sizeof(g_rbNeutralPublicKey);
+ *ppbPublicKeyBlob = (BYTE*)g_rbNeutralPublicKey;
+ retVal = TRUE;
+ goto Exit;
+ }
+
+ // Open a CSP. Create a key container if a public/private key blob is
+ // provided, otherwise we assume a key container already exists.
+ if (pbKeyBlob)
+ hProv = LocateCSP(NULL, SN_IGNORE_CONTAINER);
+ else
+ hProv = LocateCSP(wszKeyContainer, SN_OPEN_CONTAINER);
+ if (!hProv)
+ goto Error;
+
+ // If a key blob was provided, import the key pair into the container.
+ if (pbKeyBlob) {
+ if (!CryptImportKey(hProv,
+ pbKeyBlob,
+ cbKeyBlob,
+ 0, 0, &hKey))
+ goto Error;
+ } else {
+#if !defined(FEATURE_CORESYSTEM)
+ // Else fetch the signature key pair from the container.
+ if (!CryptGetUserKey(hProv, g_uKeySpec, &hKey))
+ goto Error;
+#else // FEATURE_CORESYSTEM
+ SetLastError(E_NOTIMPL);
+ goto Error;
+#endif // !FEATURE_CORESYSTEM
+ }
+
+ // Determine the length of the public key part as a blob.
+ if (!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, NULL, &dwKeyLen))
+ goto Error;
+
+
+#ifdef _PREFAST_
+#pragma warning(push)
+#pragma warning(disable:22011) // Suppress this PREFast warning which gets triggered by the offset macro expansion.
+#endif
+ // And then the length of the PublicKeyBlob structure we return to the
+ // caller.
+ *pcbPublicKeyBlob = offsetof(PublicKeyBlob, PublicKey) + dwKeyLen;
+#ifdef _PREFAST_
+#pragma warning(pop)
+#endif
+
+ // Allocate a large enough buffer.
+ *ppbPublicKeyBlob = new (nothrow) BYTE[*pcbPublicKeyBlob];
+ if (*ppbPublicKeyBlob == NULL) {
+ SetLastError(E_OUTOFMEMORY);
+ goto Error;
+ }
+
+ pKeyBlob = (PublicKeyBlob*)*ppbPublicKeyBlob;
+
+ // Extract the public part as a blob.
+ if (!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, pKeyBlob->PublicKey, &dwKeyLen)) {
+ delete[] *ppbPublicKeyBlob;
+ *ppbPublicKeyBlob = NULL;
+ goto Error;
+ }
+
+ // Extract key's signature algorithm and store it in the key blob.
+ dwSigAlgIdLen = sizeof(unsigned int);
+ ALG_ID SigAlgID;
+ if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)&SigAlgID, &dwSigAlgIdLen, 0)) {
+ delete[] *ppbPublicKeyBlob;
+ *ppbPublicKeyBlob = NULL;
+ goto Error;
+ }
+ SET_UNALIGNED_VAL32(&pKeyBlob->SigAlgID, SigAlgID);
+
+ // Fill in the other public key blob fields.
+ SET_UNALIGNED_VAL32(&pKeyBlob->HashAlgID, uHashAlgId);
+ SET_UNALIGNED_VAL32(&pKeyBlob->cbPublicKey, dwKeyLen);
+
+ retVal = TRUE;
+ goto Exit;
+
+Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+// Hash and sign a manifest.
+SNAPI StrongNameSignatureGeneration(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbSignatureBlob, // [out] signature blob
+ ULONG *pcbSignatureBlob)
+{
+ BOOL fRetVal = FALSE;
+ BEGIN_ENTRYPOINT_VOIDRET;
+ fRetVal = StrongNameSignatureGenerationEx(wszFilePath, wszKeyContainer, pbKeyBlob, cbKeyBlob, ppbSignatureBlob, pcbSignatureBlob, 0);
+ END_ENTRYPOINT_VOIDRET;
+ return fRetVal;
+}
+
+HRESULT FindAssemblySignaturePublicKey(const SN_LOAD_CTX *pLoadCtx,
+ __out PublicKeyBlob **ppPublicKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr;
+ StrongNameBufferHolder<PublicKeyBlob> result = NULL;
+
+ IfFailRet(FindPublicKey(pLoadCtx, NULL, 0, &result));
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+ PublicKeyBlob *pSignaturePublicKey = NULL;
+ IfFailRet(GetVerifiedSignatureKey((SN_LOAD_CTX*) pLoadCtx, &pSignaturePublicKey));
+
+ if(hr != S_FALSE)
+ {
+ result = pSignaturePublicKey;
+ }
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+ *ppPublicKey = result.Extract();
+
+ return S_OK;
+}
+
+SNAPI StrongNameSignatureGenerationEx(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbSignatureBlob, // [out] signature blob
+ ULONG *pcbSignatureBlob,
+ DWORD dwFlags) // [in] modifer flags
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+ HandleStrongNameCspHolder hProv(NULL);
+ CapiHashHolder hHash(NULL);
+ NewArrayHolder<BYTE> pbSig(NULL);
+ ULONG cbSig = 0;
+ SN_LOAD_CTX sLoadCtx;
+ BOOLEAN bImageLoaded = FALSE;
+ ALG_ID uHashAlgId;
+ StrongNameBufferHolder<PublicKeyBlob> pSignatureKey = NULL;
+
+ SNLOG((W("StrongNameSignatureGenerationEx(\"%s\", \"%s\", %08X, %08X, %08X, %08X, %08X)\n"), wszFilePath, wszKeyContainer, pbKeyBlob, cbKeyBlob, ppbSignatureBlob, pcbSignatureBlob, dwFlags));
+
+ SN_COMMON_PROLOG();
+
+ uHashAlgId = g_uHashAlgId;
+
+ if (pbKeyBlob != NULL && !StrongNameIsValidKeyPair(pbKeyBlob, cbKeyBlob))
+ SN_ERROR(E_INVALIDARG);
+ if (ppbSignatureBlob != NULL && pcbSignatureBlob == NULL)
+ SN_ERROR(E_POINTER);
+
+ if (wszFilePath != NULL) {
+ // Map the assembly into memory.
+ sLoadCtx.m_fReadOnly = FALSE;
+ if (!LoadAssembly(&sLoadCtx, wszFilePath))
+ goto Error;
+ bImageLoaded = TRUE;
+
+ // If we've asked to recalculate the file hashes of linked modules we have
+ // to load the metadata engine and search for file references.
+ if (dwFlags & SN_SIGN_ALL_FILES)
+ if (!RehashModules(&sLoadCtx, wszFilePath))
+ goto Error;
+
+ // If no key pair is provided, then we were only called to re-compute the hashes of
+ // linked modules in the assembly.
+ if (!wszKeyContainer && !pbKeyBlob)
+ {
+ retVal = TRUE;
+ goto Exit;
+ }
+
+ HRESULT hr;
+ if(FAILED(hr = FindAssemblySignaturePublicKey(&sLoadCtx, &pSignatureKey)))
+ {
+ SN_ERROR(hr);
+ }
+
+ // Ecma key has an algorithm of zero, so we ignore that case.
+ ALG_ID uKeyHashAlgId = GET_UNALIGNED_VAL32(&pSignatureKey->HashAlgID);
+ if(uKeyHashAlgId != 0)
+ {
+ uHashAlgId = uKeyHashAlgId;
+ }
+ }
+
+ if (wszKeyContainer || pbKeyBlob) { // We have a key pair in a container, or in a blob
+ // Open a CSP. If a public/private key blob is provided, use CRYPT_VERIFYCONTEXT,
+ // otherwise we assume the key container already exists.
+ if (pbKeyBlob)
+ hProv = LocateCSP(NULL, SN_IGNORE_CONTAINER, uHashAlgId);
+ else
+ hProv = LocateCSP(wszKeyContainer, SN_OPEN_CONTAINER, uHashAlgId);
+
+ if (hProv.GetValue() == NULL)
+ goto Error;
+
+ // If a key blob was provided, import the key pair into the container.
+ // This might be the real key or the test-sign key. In the case of test signing,
+ // there's no way to specify hash algorithm, so we use the one from the
+ // assembly signature public key (in the metadata table, or the migration attribute).
+ if (pbKeyBlob) {
+ // The provider holds a reference to the key, so we don't need to
+ // keep one around.
+ CapiKeyHolder hKey(NULL);
+ if (!CryptImportKey(hProv,
+ pbKeyBlob,
+ cbKeyBlob,
+ 0,
+ 0,
+ &hKey))
+ goto Error;
+ }
+
+ // Create a hash object.
+ if (!CryptCreateHash(hProv, uHashAlgId, 0, 0, &hHash))
+ goto Error;
+
+ // Compute size of the signature blob.
+ if (!CryptSignHashW(hHash, g_uKeySpec, NULL, 0, NULL, &cbSig))
+ goto Error;
+
+ // If the caller only wants the size of the signature, return it now and
+ // exit.
+ // RSA signature length is independent of the hash size, so hash algorithm
+ // doesn't matter here (we don't know the algorithm if the assembly path was passed in as NULL)
+ if (wszFilePath == NULL) {
+ *pcbSignatureBlob = cbSig;
+ retVal = TRUE;
+ goto Exit;
+ }
+ }
+
+ // Verify that the public key of the assembly being signed matches the private key we're signing with
+ if ((wszKeyContainer != NULL || pbKeyBlob != NULL) && !VerifyKeyMatchesAssembly(pSignatureKey, wszKeyContainer, pbKeyBlob, cbKeyBlob, dwFlags))
+ {
+ SetLastError(StrongNameErrorInfo());
+ goto Error;
+ }
+
+ // We set a bit in the header to indicate we're fully signing the assembly.
+ if (!(dwFlags & SN_TEST_SIGN))
+ sLoadCtx.m_pCorHeader->Flags |= VAL32(COMIMAGE_FLAGS_STRONGNAMESIGNED);
+ else
+ sLoadCtx.m_pCorHeader->Flags &= ~VAL32(COMIMAGE_FLAGS_STRONGNAMESIGNED);
+
+ // Destroy the old hash object and create a new one
+ // because CryptoAPI says you can't reuse a hash once you've signed it
+ // Note that this seems to work with MS-based CSPs but breaks on
+ // at least newer nCipher CSPs.
+ if (!CryptCreateHash(hProv, uHashAlgId, 0, 0, &hHash))
+ goto Error;
+
+ // Compute a hash over the image.
+ if (!ComputeHash(&sLoadCtx, hHash, CalcHash, NULL))
+ goto Error;
+
+ // Allocate the blob.
+ pbSig = new (nothrow) BYTE[cbSig];
+ if (pbSig == NULL) {
+ SetLastError(E_OUTOFMEMORY);
+ goto Error;
+ }
+
+ // Compute a signature blob over the hash of the manifest.
+ if (!CryptSignHashW(hHash, g_uKeySpec, NULL, 0, pbSig, &cbSig))
+ goto Error;
+
+ // Check the signature size
+ if (sLoadCtx.m_cbSignature != cbSig) {
+ SetLastError(CORSEC_E_SIGNATURE_MISMATCH);
+ goto Error;
+ }
+
+ // If the user hasn't asked for the signature to be returned as a pointer, write it to file.
+ if (!ppbSignatureBlob)
+ {
+ memcpy_s(sLoadCtx.m_pbSignature, sLoadCtx.m_cbSignature, pbSig, cbSig);
+
+ //
+ // Memory-mapped IO in Windows doesn't guarantee that it will update
+ // the file's "Modified" timestamp, so we update it ourselves.
+ //
+ _ASSERTE(sLoadCtx.m_hFile != INVALID_HANDLE_VALUE);
+
+ FILETIME ft;
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+
+ // We don't care if updating the timestamp fails for any reason.
+ if(SystemTimeToFileTime(&st, &ft))
+ {
+ SetFileTime(sLoadCtx.m_hFile, (LPFILETIME) NULL, (LPFILETIME) NULL, &ft);
+ }
+ }
+
+ // Unmap the image (automatically recalculates and updates the image
+ // checksum).
+ bImageLoaded = FALSE;
+ if (!UnloadAssembly(&sLoadCtx))
+ goto Error;
+
+ if (ppbSignatureBlob) {
+ *ppbSignatureBlob = pbSig.Extract();
+ *pcbSignatureBlob = cbSig;
+ }
+
+ retVal = TRUE;
+ goto Exit;
+
+Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+Exit:
+ if (bImageLoaded)
+ UnloadAssembly(&sLoadCtx);
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+//
+// Generate the digest of a delay signed assembly, which can be signed with StrongNameDigestSign. The digest
+// algorithm is determined from the HashAlgID of the assembly's public key blob.
+//
+// Parameters:
+// wszFilePath - path to the delay signed assembly to generate the digest of
+// ppbDigestBlob - on success this will point to a buffer that contains the digest of the wszFilePath
+// assembly. This buffer should be freed with StrongNameFreeBuffer.
+// pcbDigestBlob - on success this will point to the size of the digest buffer in *ppbDigestBlob
+// dwFlags - flags used to control signing. This is the same set of flags used by
+// StrongNameSignatureGenerationEx
+//
+
+bool StrongNameDigestGenerate_Internal(_In_z_ LPCWSTR wszFilePath,
+ _Outptr_result_bytebuffer_(*pcbDigestBlob) BYTE** ppbDigestBlob,
+ _Out_ ULONG* pcbDigestBlob,
+ DWORD dwFlags)
+{
+ // Load up the assembly and find its public key - this tells us which hash algorithm we need to use
+ // Note that it cannot be loaded read-only since we need to toggle the fully siged bit in order to
+ // calculate the correct hash for the signature.
+ StrongNameAssemblyLoadHolder assembly(wszFilePath, false /* read only */);
+ if (!assembly.IsLoaded())
+ {
+ return false;
+ }
+
+ // If we were asked to do a full rehashing of all modules that needs to be done before calculating the digest
+ if ((dwFlags & SN_SIGN_ALL_FILES) == SN_SIGN_ALL_FILES)
+ {
+ if (!RehashModules(assembly.GetLoadContext(), wszFilePath))
+ {
+ return false;
+ }
+ }
+
+ // During signature verification, the fully signed bit will be set in the assembly's COR header.
+ // Therefore, when calculating the digest of the assembly we must toggle this bit in order to make the
+ // digest match what will be calculated during verificaiton. However, we do not want to persist the
+ // bit flip on disk, since we're not actually signing the assembly now. We'll save the current COR
+ // flags, flip the bit for digesting, and then restore the COR flags before we finish calculating the
+ // digest.
+ class AssemblyFlagsHolder
+ {
+ private:
+ IMAGE_COR20_HEADER* m_pHeader;
+ DWORD m_originalFlags;
+
+ public:
+ AssemblyFlagsHolder(_In_ IMAGE_COR20_HEADER* pHeader)
+ : m_pHeader(pHeader),
+ m_originalFlags(pHeader->Flags)
+ {
+ }
+
+ ~AssemblyFlagsHolder()
+ {
+ m_pHeader->Flags = m_originalFlags;
+ }
+ } flagsHolder(assembly.GetLoadContext()->m_pCorHeader);
+ assembly.GetLoadContext()->m_pCorHeader->Flags |= VAL32(COMIMAGE_FLAGS_STRONGNAMESIGNED);
+
+ StrongNameBufferHolder<PublicKeyBlob> pPublicKey;
+ HRESULT hrPublicKey = FindAssemblySignaturePublicKey(assembly.GetLoadContext(), &pPublicKey);
+ if (FAILED(hrPublicKey))
+ {
+ SetStrongNameErrorInfo(hrPublicKey);
+ return false;
+ }
+
+ // Generate the digest of the assembly
+ HandleStrongNameCspHolder hProv(LocateCSP(nullptr, SN_IGNORE_CONTAINER, pPublicKey->HashAlgID));
+ if (!hProv)
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ CapiHashHolder hHash;
+ if (!CryptCreateHash(hProv, pPublicKey->HashAlgID, NULL, 0, &hHash))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ if (!ComputeHash(assembly.GetLoadContext(), hHash, CalcHash, nullptr))
+ {
+ return false;
+ }
+
+ // Figure out how big the resulting digest is so that we can pass it back out
+ DWORD hashSize = 0;
+ DWORD dwordSize = sizeof(hashSize);
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &dwordSize, 0))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ StrongNameBufferHolder<BYTE> pbHash(new (nothrow)BYTE[hashSize]);
+ if (!pbHash)
+ {
+ SetStrongNameErrorInfo(E_OUTOFMEMORY);
+ return false;
+ }
+
+ if (!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &hashSize, 0))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ *ppbDigestBlob = pbHash.Extract();
+ *pcbDigestBlob = hashSize;
+ return true;
+}
+
+SNAPI StrongNameDigestGenerate(_In_z_ LPCWSTR wszFilePath,
+ _Outptr_result_bytebuffer_(*pcbDigestBlob) BYTE** ppbDigestBlob,
+ _Out_ ULONG* pcbDigestBlob,
+ DWORD dwFlags)
+{
+ BOOLEAN retVal = FALSE;
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ SNLOG((W("StrongNameDigestGenerate(\"%s\", %08X, %08X, %04X)\n"), wszFilePath, ppbDigestBlob, pcbDigestBlob, dwFlags));
+
+ SN_COMMON_PROLOG();
+ if (wszFilePath == nullptr)
+ SN_ERROR(E_POINTER);
+ if (ppbDigestBlob == nullptr)
+ SN_ERROR(E_POINTER);
+ if (pcbDigestBlob == nullptr)
+ SN_ERROR(E_POINTER);
+
+ retVal = StrongNameDigestGenerate_Internal(wszFilePath, ppbDigestBlob, pcbDigestBlob, dwFlags);
+
+ END_ENTRYPOINT_VOIDRET;
+
+Exit:
+ return retVal;
+}
+
+//
+// Sign an the digest of an assembly calculated by StrongNameDigestGenerate
+//
+// Parameters:
+// wszKeyContainer - name of the key container that holds the key pair used to generate the signature. If
+// both a key container and key blob are specified, the key container name is ignored.
+// pbKeyBlob - raw key pair to be used to generate the signature. If both a key pair and a key
+// container are given, the key blob will be used.
+// cbKeyBlob - size of the key pair in pbKeyBlob
+// pbDigestBlob - digest of the assembly, calculated by StrongNameDigestGenerate
+// cbDigestBlob - size of the digest blob
+// hashAlgId - algorithm ID of the hash algorithm used to generate the digest blob
+// ppbSignatureBlob - on success this will point to a buffer that contains a signature over the blob. This
+// buffer should be freed with StrongNameFreeBuffer.
+// pcbSignatureBlob - on success this will point to the size of the signature blob in *ppbSignatureBlob
+// dwFlags - flags used to control signing. This is the same set of flags used by
+// StrongNameSignatureGenerationEx
+//
+
+bool StrongNameDigestSign_Internal(_In_opt_z_ LPCWSTR wszKeyContainer,
+ _In_reads_bytes_opt_(cbKeyBlob) BYTE* pbKeyBlob,
+ ULONG cbKeyBlob,
+ _In_reads_bytes_(cbDigestBlob) BYTE* pbDigestBlob,
+ ULONG cbDigestBlob,
+ DWORD hashAlgId,
+ _Outptr_result_bytebuffer_(*pcbSignatureBlob) BYTE** ppbSignatureBlob,
+ _Out_ ULONG* pcbSignatureBlob,
+ DWORD dwFlags)
+{
+ //
+ // Get the key we'll be signing with loaded into CAPI
+ //
+
+ HandleStrongNameCspHolder hProv;
+ CapiKeyHolder hKey;
+ if (pbKeyBlob != nullptr)
+ {
+ hProv = LocateCSP(nullptr, SN_IGNORE_CONTAINER, hashAlgId);
+
+ if (hProv != NULL)
+ {
+ if (!CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, 0, 0, &hKey))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+ }
+ }
+ else
+ {
+ hProv = LocateCSP(wszKeyContainer, SN_OPEN_CONTAINER, hashAlgId);
+ }
+
+ if (!hProv)
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ //
+ // Get the pre-calculated digest loaded into a CAPI Hash object
+ //
+
+ CapiHashHolder hHash;
+ if (!CryptCreateHash(hProv, hashAlgId, 0, 0, &hHash))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ DWORD hashSize = 0;
+ DWORD cbHashSize = sizeof(hashSize);
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &cbHashSize, 0))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ if (hashSize != cbDigestBlob)
+ {
+ SetStrongNameErrorInfo(NTE_BAD_HASH);
+ return false;
+ }
+
+ if (!CryptSetHashParam(hHash, HP_HASHVAL, pbDigestBlob, 0))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ //
+ // Sign the hash
+ //
+
+ DWORD cbSignature = 0;
+ if (!CryptSignHashW(hHash, g_uKeySpec, nullptr, 0, nullptr, &cbSignature))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ // CAPI has a quirk where some CSPs do not allow you to sign a hash object once you've asked for the size
+ // of the signature. To work in those cases, we must create a new hash object to sign.
+ if (!CryptCreateHash(hProv, hashAlgId, 0, 0, &hHash))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hashSize), &cbHashSize, 0))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ if (hashSize != cbDigestBlob)
+ {
+ SetStrongNameErrorInfo(NTE_BAD_HASH);
+ return false;
+ }
+
+ if (!CryptSetHashParam(hHash, HP_HASHVAL, pbDigestBlob, 0))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ // Now that we've got a fresh hash object to sign, we can compute the final signature
+ StrongNameBufferHolder<BYTE> pbSignature(new (nothrow)BYTE[cbSignature]);
+ if (pbSignature == nullptr)
+ {
+ SetStrongNameErrorInfo(E_OUTOFMEMORY);
+ return false;
+ }
+
+ if (!CryptSignHashW(hHash, g_uKeySpec, nullptr, 0, pbSignature, &cbSignature))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ *ppbSignatureBlob = pbSignature.Extract();
+ *pcbSignatureBlob = cbSignature;
+ return true;
+}
+
+SNAPI StrongNameDigestSign(_In_opt_z_ LPCWSTR wszKeyContainer,
+ _In_reads_bytes_opt_(cbKeyBlob) BYTE* pbKeyBlob,
+ ULONG cbKeyBlob,
+ _In_reads_bytes_(cbDigestBlob) BYTE* pbDigestBlob,
+ ULONG cbDigestBlob,
+ DWORD hashAlgId,
+ _Outptr_result_bytebuffer_(*pcbSignatureBlob) BYTE** ppbSignatureBlob,
+ _Out_ ULONG* pcbSignatureBlob,
+ DWORD dwFlags)
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+ SNLOG((W("StrongNameDigestSign(\"%s\", %08X, %04X, %08X, %04X, %04X, %08X, %08X, %04X)\n"), wszKeyContainer, pbKeyBlob, cbKeyBlob, pbDigestBlob, cbDigestBlob, hashAlgId, ppbSignatureBlob, pcbSignatureBlob, dwFlags));
+ SN_COMMON_PROLOG();
+
+ if (wszKeyContainer == nullptr && pbKeyBlob == nullptr)
+ SN_ERROR(E_POINTER);
+ if (pbKeyBlob != nullptr && !StrongNameIsValidKeyPair(pbKeyBlob, cbKeyBlob))
+ SN_ERROR(E_INVALIDARG);
+ if (pbDigestBlob == nullptr)
+ SN_ERROR(E_POINTER);
+ if (ppbSignatureBlob == nullptr)
+ SN_ERROR(E_POINTER);
+ if (pcbSignatureBlob == nullptr)
+ SN_ERROR(E_POINTER);
+
+ *ppbSignatureBlob = nullptr;
+ *pcbSignatureBlob = 0;
+
+ retVal = StrongNameDigestSign_Internal(wszKeyContainer, pbKeyBlob, cbKeyBlob, pbDigestBlob, cbDigestBlob, hashAlgId, ppbSignatureBlob, pcbSignatureBlob, dwFlags);
+
+ END_ENTRYPOINT_VOIDRET;
+Exit:
+ return retVal;
+}
+
+//
+// Embed a digest signature generated with StrongNameDigestSign into a delay signed assembly, completing
+// the signing process for that assembly.
+//
+// Parameters:
+// wszFilePath - path to the assembly to sign
+// pbSignatureBlob - signature blob to embed in the assembly
+// cbSignatureBlob - size of the signature blob
+//
+
+bool StrongNameDigestEmbed_Internal(_In_z_ LPCWSTR wszFilePath,
+ _In_reads_bytes_(cbSignatureBlob) BYTE* pbSignatureBlob,
+ ULONG cbSignatureBlob)
+{
+ StrongNameAssemblyLoadHolder assembly(wszFilePath, false);
+ if (!assembly.IsLoaded())
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+
+ memcpy_s(assembly.GetLoadContext()->m_pbSignature, assembly.GetLoadContext()->m_cbSignature, pbSignatureBlob, cbSignatureBlob);
+ assembly.GetLoadContext()->m_pCorHeader->Flags |= VAL32(COMIMAGE_FLAGS_STRONGNAMESIGNED);
+
+ FILETIME ft = { 0 };
+ SYSTEMTIME st = { 0 };
+ GetSystemTime(&st);
+ if (SystemTimeToFileTime(&st, &ft))
+ {
+ SetFileTime(assembly.GetLoadContext()->m_hFile, nullptr, nullptr, &ft);
+ }
+
+ return true;
+}
+
+SNAPI StrongNameDigestEmbed(_In_z_ LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly to update
+ _In_reads_bytes_(cbSignatureBlob) BYTE* pbSignatureBlob, // [in] signatuer blob for the assembly
+ ULONG cbSignatureBlob)
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+ SNLOG((W("StrongNameDigestEmbed(\"%s\", %08X, %04X)\n"), wszFilePath, pbSignatureBlob, cbSignatureBlob));
+ SN_COMMON_PROLOG();
+
+ if (wszFilePath == nullptr)
+ SN_ERROR(E_POINTER);
+ if (pbSignatureBlob == nullptr)
+ SN_ERROR(E_POINTER);
+
+ retVal = StrongNameDigestEmbed_Internal(wszFilePath, pbSignatureBlob, cbSignatureBlob);
+
+ END_ENTRYPOINT_VOIDRET;
+Exit:
+ return retVal;
+}
+
+// Create a strong name token from an assembly file.
+SNAPI StrongNameTokenFromAssembly(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BYTE **ppbStrongNameToken, // [out] strong name token
+ ULONG *pcbStrongNameToken)
+{
+ BOOL fRetValue = FALSE;
+ BEGIN_ENTRYPOINT_VOIDRET;
+ fRetValue = StrongNameTokenFromAssemblyEx(wszFilePath,
+ ppbStrongNameToken,
+ pcbStrongNameToken,
+ NULL,
+ NULL);
+ END_ENTRYPOINT_VOIDRET;
+ return fRetValue;
+}
+
+// Create a strong name token from an assembly file and additionally return the full public key.
+SNAPI StrongNameTokenFromAssemblyEx(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BYTE **ppbStrongNameToken, // [out] strong name token
+ ULONG *pcbStrongNameToken,
+ BYTE **ppbPublicKeyBlob, // [out] public key blob
+ ULONG *pcbPublicKeyBlob)
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+ SN_LOAD_CTX sLoadCtx;
+ BOOLEAN fMapped = FALSE;
+ BOOLEAN fSetErrorInfo = TRUE;
+ PublicKeyBlob *pPublicKey = NULL;
+ HRESULT hrKey = S_OK;
+
+ SNLOG((W("StrongNameTokenFromAssemblyEx(\"%s\", %08X, %08X, %08X, %08X)\n"), wszFilePath, ppbStrongNameToken, pcbStrongNameToken, ppbPublicKeyBlob, pcbPublicKeyBlob));
+
+ SN_COMMON_PROLOG();
+
+ if (wszFilePath == NULL)
+ SN_ERROR(E_POINTER);
+ if (ppbStrongNameToken == NULL)
+ SN_ERROR(E_POINTER);
+ if (pcbStrongNameToken == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Map the assembly into memory.
+ sLoadCtx.m_fReadOnly = TRUE;
+ if (!LoadAssembly(&sLoadCtx, wszFilePath))
+ goto Error;
+ fMapped = TRUE;
+
+ // Read the public key used to sign the assembly from the assembly metadata.
+ hrKey = FindPublicKey(&sLoadCtx, NULL, 0, &pPublicKey);
+ if (FAILED(hrKey))
+ {
+ SetStrongNameErrorInfo(hrKey);
+ fSetErrorInfo = FALSE;
+ goto Error;
+ }
+
+ // Unload the assembly.
+ fMapped = FALSE;
+ if (!UnloadAssembly(&sLoadCtx))
+ goto Error;
+
+ // Now we have a public key blob, we can call our more direct API to do the
+ // actual work.
+ if (!StrongNameTokenFromPublicKey((BYTE*)pPublicKey,
+ SN_SIZEOF_KEY(pPublicKey),
+ ppbStrongNameToken,
+ pcbStrongNameToken)) {
+ fSetErrorInfo = FALSE;
+ goto Error;
+ }
+
+ if (pcbPublicKeyBlob)
+ *pcbPublicKeyBlob = SN_SIZEOF_KEY(pPublicKey);
+
+ // Return public key information.
+ if (ppbPublicKeyBlob)
+ *ppbPublicKeyBlob = (BYTE*)pPublicKey;
+ else
+ delete [] (BYTE*)pPublicKey;
+
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ if (fSetErrorInfo)
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ if (pPublicKey)
+ delete [] (BYTE*)pPublicKey;
+ if (fMapped)
+ UnloadAssembly(&sLoadCtx);
+
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+
+ return retVal;
+}
+
+bool StrongNameSignatureVerificationEx2_Internal(LPCWSTR wszFilePath,
+ BOOLEAN fForceVerification,
+ BYTE *pbEcmaPublicKey,
+ DWORD cbEcmaPublicKey,
+ BOOLEAN *pfWasVerified)
+{
+ StrongNameAssemblyLoadHolder assembly(wszFilePath, true);
+ if (!assembly.IsLoaded())
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ return false;
+ }
+ else
+ {
+ DWORD dwOutFlags = 0;
+ HRESULT hrVerify = VerifySignature(assembly.GetLoadContext(),
+ SN_INFLAG_INSTALL | SN_INFLAG_ALL_ACCESS | (fForceVerification ? SN_INFLAG_FORCE_VER : 0),
+ reinterpret_cast<PublicKeyBlob *>(pbEcmaPublicKey),
+ &dwOutFlags);
+ if (FAILED(hrVerify))
+ {
+ SetStrongNameErrorInfo(hrVerify);
+ return false;
+ }
+
+ if (pfWasVerified)
+ {
+ *pfWasVerified = (dwOutFlags & SN_OUTFLAG_WAS_VERIFIED) != 0;
+ }
+
+ return true;
+ }
+}
+
+//
+// Verify the signature of a strongly named assembly, providing a mapping from the ECMA key to a real key
+//
+// Arguments:
+// wszFilePath - valid path to the PE file for the assembly
+// fForceVerification - verify even if settings in the registry disable it
+// pbEcmaPublicKey - mapping from the ECMA public key to the real key used for verification
+// cbEcmaPublicKey - length of the real ECMA public key
+// fWasVerified - [out] set to false if verify succeeded due to registry settings
+//
+// Return Value:
+// TRUE if the signature was successfully verified, FALSE otherwise
+//
+
+SNAPI StrongNameSignatureVerificationEx2(LPCWSTR wszFilePath,
+ BOOLEAN fForceVerification,
+ BYTE *pbEcmaPublicKey,
+ DWORD cbEcmaPublicKey,
+ BOOLEAN *pfWasVerified)
+{
+ BOOLEAN retVal = FALSE;
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ SNLOG((W("StrongNameSignatureVerificationEx2(\"%s\", %d, %08X, %08X, %08X)\n"), wszFilePath, fForceVerification, pbEcmaPublicKey, cbEcmaPublicKey, pfWasVerified));
+
+ SN_COMMON_PROLOG();
+
+ if (wszFilePath == NULL)
+ SN_ERROR(E_POINTER);
+ if (pbEcmaPublicKey == NULL)
+ SN_ERROR(E_POINTER);
+ if (!StrongNameIsValidPublicKey(pbEcmaPublicKey, cbEcmaPublicKey, false))
+ SN_ERROR(CORSEC_E_INVALID_PUBLICKEY);
+
+ retVal = StrongNameSignatureVerificationEx2_Internal(wszFilePath, fForceVerification, pbEcmaPublicKey, cbEcmaPublicKey, pfWasVerified);
+
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+// Verify a strong name/manifest against a public key blob.
+SNAPI StrongNameSignatureVerificationEx(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BOOLEAN fForceVerification, // [in] verify even if settings in the registry disable it
+ BOOLEAN *pfWasVerified) // [out] set to false if verify succeeded due to registry settings
+{
+ BOOLEAN fRet = FALSE;
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ fRet = StrongNameSignatureVerificationEx2(wszFilePath,
+ fForceVerification,
+ const_cast<BYTE *>(g_rbTheKey),
+ COUNTOF(g_rbTheKey),
+ pfWasVerified);
+
+ END_ENTRYPOINT_VOIDRET;
+ return fRet;
+}
+
+
+// Verify a strong name/manifest against a public key blob.
+SNAPI StrongNameSignatureVerification(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ DWORD dwInFlags, // [in] flags modifying behaviour
+ DWORD *pdwOutFlags) // [out] additional output info
+{
+ BOOLEAN retVal = TRUE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ SN_LOAD_CTX sLoadCtx;
+ BOOLEAN fMapped = FALSE;
+
+ SNLOG((W("StrongNameSignatureVerification(\"%s\", %08X, %08X, %08X)\n"), wszFilePath, dwInFlags, pdwOutFlags));
+
+ SN_COMMON_PROLOG();
+
+ if (wszFilePath == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Map the assembly into memory.
+ sLoadCtx.m_fReadOnly = TRUE;
+ if (LoadAssembly(&sLoadCtx, wszFilePath))
+ {
+ fMapped = TRUE;
+ }
+ else
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ retVal = FALSE;
+ }
+
+ // Go to common code to process the verification.
+ if (fMapped)
+ {
+ HRESULT hrVerify = VerifySignature(&sLoadCtx, dwInFlags, reinterpret_cast<PublicKeyBlob *>(const_cast<BYTE *>(g_rbTheKey)), pdwOutFlags);
+ if (FAILED(hrVerify))
+ {
+ SetStrongNameErrorInfo(hrVerify);
+ retVal = FALSE;
+ }
+
+ // Unmap the image. Only set error information if VerifySignature succeeded, since we do not want to
+ // overwrite its error information with the error code from UnloadAssembly.
+ if (!UnloadAssembly(&sLoadCtx))
+ {
+ if (retVal)
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ retVal = FALSE;
+ }
+ }
+
+ // SN_COMMON_PROLOG requires an Exit location
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+
+// Verify a strong name/manifest against a public key blob when the assembly is
+// already memory mapped.
+SNAPI StrongNameSignatureVerificationFromImage(BYTE *pbBase, // [in] base address of mapped manifest file
+ DWORD dwLength, // [in] length of mapped image in bytes
+ DWORD dwInFlags, // [in] flags modifying behaviour
+ DWORD *pdwOutFlags) // [out] additional output info
+{
+ BOOLEAN retVal = TRUE;
+
+ BEGIN_ENTRYPOINT_VOIDRET
+
+ SN_LOAD_CTX sLoadCtx;
+ BOOLEAN fMapped = FALSE;
+
+ SNLOG((W("StrongNameSignatureVerificationFromImage(%08X, %08X, %08X, %08X)\n"), pbBase, dwLength, dwInFlags, pdwOutFlags));
+
+ SN_COMMON_PROLOG();
+
+ if (pbBase == NULL)
+ SN_ERROR(E_POINTER);
+
+ // We don't need to map the image, it's already in memory. But we do need to
+ // set up a load context for some of the following routines. LoadAssembly
+ // copes with this case for us.
+ sLoadCtx.m_pbBase = pbBase;
+ sLoadCtx.m_dwLength = dwLength;
+ sLoadCtx.m_fReadOnly = TRUE;
+ if (LoadAssembly(&sLoadCtx, NULL, dwInFlags))
+ {
+ fMapped = TRUE;
+ }
+ else
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ retVal = FALSE;
+ }
+
+ if (fMapped)
+ {
+ // Go to common code to process the verification.
+ HRESULT hrVerify = VerifySignature(&sLoadCtx, dwInFlags, reinterpret_cast<PublicKeyBlob *>(const_cast<BYTE *>(g_rbTheKey)), pdwOutFlags);
+ if (FAILED(hrVerify))
+ {
+ SetStrongNameErrorInfo(hrVerify);
+ retVal = FALSE;
+ }
+
+ // Unmap the image.
+ if (!UnloadAssembly(&sLoadCtx))
+ {
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ retVal = FALSE;
+ }
+ }
+
+ // SN_COMMON_PROLOG requires an Exit location
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+// Find portions of an assembly to hash.
+BOOLEAN CollectBlob(SN_LOAD_CTX *pLoadCtx, PBYTE pbBlob, DWORD* pcbBlob)
+{
+ // Calculate the required size
+ DWORD cbRequired = 0;
+ BOOLEAN bRetval = ComputeHash(pLoadCtx, (HCRYPTHASH)INVALID_HANDLE_VALUE, CalculateSize, &cbRequired);
+ if (!bRetval)
+ return FALSE;
+ if (*pcbBlob < cbRequired) {
+ *pcbBlob = cbRequired;
+ SetLastError( E_INVALIDARG );
+ return FALSE;
+ }
+
+ CopyDataBufferDesc buffer = { pbBlob, *pcbBlob };
+ if (!ComputeHash(pLoadCtx, (HCRYPTHASH)INVALID_HANDLE_VALUE, CopyData, &buffer))
+ return FALSE;
+
+ *pcbBlob = cbRequired;
+ return TRUE;
+}
+
+// ensure that the symbol will be exported properly
+extern "C" SNAPI StrongNameGetBlob(LPCWSTR wszFilePath,
+ PBYTE pbBlob,
+ DWORD *cbBlob);
+
+SNAPI StrongNameGetBlob(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ PBYTE pbBlob, // [in] buffer to fill with blob
+ DWORD *cbBlob) // [in/out] size of buffer/number of bytes put into buffer
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ SN_LOAD_CTX sLoadCtx;
+ BOOLEAN fMapped = FALSE;
+
+ SNLOG((W("StrongNameGetBlob(\"%s\", %08X, %08X)\n"), wszFilePath, pbBlob, cbBlob));
+
+ SN_COMMON_PROLOG();
+
+ if (wszFilePath == NULL)
+ SN_ERROR(E_POINTER);
+ if (pbBlob == NULL)
+ SN_ERROR(E_POINTER);
+ if (cbBlob == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Map the assembly into memory.
+ sLoadCtx.m_fReadOnly = TRUE;
+ if (!LoadAssembly(&sLoadCtx, wszFilePath, 0, FALSE))
+ goto Error;
+ fMapped = TRUE;
+
+ if (!CollectBlob(&sLoadCtx, pbBlob, cbBlob))
+ goto Error;
+
+ // Unmap the image.
+ fMapped = FALSE;
+ if (!UnloadAssembly(&sLoadCtx))
+ goto Error;
+
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ if (fMapped)
+ UnloadAssembly(&sLoadCtx);
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+ return retVal;
+}
+
+// ensure that the symbol will be exported properly
+extern "C" SNAPI StrongNameGetBlobFromImage(BYTE *pbBase,
+ DWORD dwLength,
+ PBYTE pbBlob,
+ DWORD *cbBlob);
+
+SNAPI StrongNameGetBlobFromImage(BYTE *pbBase, // [in] base address of mapped manifest file
+ DWORD dwLength, // [in] length of mapped image in bytes
+ PBYTE pbBlob, // [in] buffer to fill with blob
+ DWORD *cbBlob) // [in/out] size of buffer/number of bytes put into buffer
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ SN_LOAD_CTX sLoadCtx;
+ BOOLEAN fMapped = FALSE;
+
+
+ SNLOG((W("StrongNameGetBlobFromImage(%08X, %08X, %08X, %08X)\n"), pbBase, dwLength, pbBlob, cbBlob));
+
+ SN_COMMON_PROLOG();
+
+ if (pbBase == NULL)
+ SN_ERROR(E_POINTER);
+ if (pbBlob == NULL)
+ SN_ERROR(E_POINTER);
+ if (cbBlob == NULL)
+ SN_ERROR(E_POINTER);
+
+ // We don't need to map the image, it's already in memory. But we do need to
+ // set up a load context for some of the following routines. LoadAssembly
+ // copes with this case for us.
+ sLoadCtx.m_pbBase = pbBase;
+ sLoadCtx.m_dwLength = dwLength;
+ sLoadCtx.m_fReadOnly = TRUE;
+ if (!LoadAssembly(&sLoadCtx, NULL, 0, FALSE))
+ goto Error;
+ fMapped = TRUE;
+
+ // Go to common code to process the verification.
+ if (!CollectBlob(&sLoadCtx, pbBlob, cbBlob))
+ goto Error;
+
+ // Unmap the image.
+ fMapped = FALSE;
+ if (!UnloadAssembly(&sLoadCtx))
+ goto Error;
+
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ if (fMapped)
+ UnloadAssembly(&sLoadCtx);
+
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+
+ return retVal;
+}
+
+
+// Verify that two assemblies differ only by signature blob.
+SNAPI StrongNameCompareAssemblies(LPCWSTR wszAssembly1, // [in] file name of first assembly
+ LPCWSTR wszAssembly2, // [in] file name of second assembly
+ DWORD *pdwResult) // [out] result of comparison
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+
+ SN_LOAD_CTX sLoadCtx1;
+ SN_LOAD_CTX sLoadCtx2;
+ size_t dwSkipOffsets[3];
+ size_t dwSkipLengths[3];
+ BOOLEAN bMappedAssem1 = FALSE;
+ BOOLEAN bMappedAssem2 = FALSE;
+ BOOLEAN bIdentical;
+ BOOLEAN bSkipping;
+ DWORD i, j;
+
+
+
+ SNLOG((W("StrongNameCompareAssemblies(\"%s\", \"%s\", %08X)\n"), wszAssembly1, wszAssembly2, pdwResult));
+
+ SN_COMMON_PROLOG();
+
+ if (wszAssembly1 == NULL)
+ SN_ERROR(E_POINTER);
+ if (wszAssembly2 == NULL)
+ SN_ERROR(E_POINTER);
+ if (pdwResult == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Map each assembly.
+ sLoadCtx1.m_fReadOnly = TRUE;
+ if (!LoadAssembly(&sLoadCtx1, wszAssembly1))
+ goto Error;
+ bMappedAssem1 = TRUE;
+
+ sLoadCtx2.m_fReadOnly = TRUE;
+ if (!LoadAssembly(&sLoadCtx2, wszAssembly2))
+ goto Error;
+ bMappedAssem2 = TRUE;
+
+ // If the files aren't even the same length then they must be different.
+ if (sLoadCtx1.m_dwLength != sLoadCtx2.m_dwLength)
+ goto ImagesDiffer;
+
+ // Check that the signatures are located at the same offset and are the same
+ // length in each assembly.
+ if (sLoadCtx1.m_pCorHeader->StrongNameSignature.VirtualAddress !=
+ sLoadCtx2.m_pCorHeader->StrongNameSignature.VirtualAddress)
+ goto ImagesDiffer;
+ if (sLoadCtx1.m_pCorHeader->StrongNameSignature.Size !=
+ sLoadCtx2.m_pCorHeader->StrongNameSignature.Size)
+ goto ImagesDiffer;
+
+ // Set up list of image ranges to skip in the upcoming comparison.
+ // First there's the signature blob.
+ dwSkipOffsets[0] = sLoadCtx1.m_pbSignature - sLoadCtx1.m_pbBase;
+ dwSkipLengths[0] = sLoadCtx1.m_cbSignature;
+
+ // Then there's the checksum.
+ if (sLoadCtx1.m_pNtHeaders->OptionalHeader.Magic != sLoadCtx2.m_pNtHeaders->OptionalHeader.Magic)
+ goto ImagesDiffer;
+ if (sLoadCtx1.m_pNtHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC))
+ dwSkipOffsets[1] = (BYTE*)&((IMAGE_NT_HEADERS32*)sLoadCtx1.m_pNtHeaders)->OptionalHeader.CheckSum - sLoadCtx1.m_pbBase;
+ else if (sLoadCtx1.m_pNtHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC))
+ dwSkipOffsets[1] = (BYTE*)&((IMAGE_NT_HEADERS64*)sLoadCtx1.m_pNtHeaders)->OptionalHeader.CheckSum - sLoadCtx1.m_pbBase;
+ else {
+ SetLastError(CORSEC_E_INVALID_IMAGE_FORMAT);
+ goto Error;
+ }
+ dwSkipLengths[1] = sizeof(DWORD);
+
+ // Skip the COM+ 2.0 PE header extension flags field. It's updated by the
+ // signing operation.
+ dwSkipOffsets[2] = (BYTE*)&sLoadCtx1.m_pCorHeader->Flags - sLoadCtx1.m_pbBase;
+ dwSkipLengths[2] = sizeof(DWORD);
+
+ // Compare the two mapped images, skipping the ranges we defined above.
+ bIdentical = TRUE;
+ for (i = 0; i < sLoadCtx1.m_dwLength; i++) {
+
+ // Determine if we're skipping the check on the current byte.
+ bSkipping = FALSE;
+ for (j = 0; j < (sizeof(dwSkipOffsets) / sizeof(dwSkipOffsets[0])); j++)
+ if ((i >= dwSkipOffsets[j]) && (i < (dwSkipOffsets[j] + dwSkipLengths[j]))) {
+ bSkipping = TRUE;
+ break;
+ }
+
+ // Perform comparisons as desired.
+ if (sLoadCtx1.m_pbBase[i] != sLoadCtx2.m_pbBase[i])
+ if (bSkipping)
+ bIdentical = FALSE;
+ else
+ goto ImagesDiffer;
+ }
+
+ // The assemblies are the same.
+ *pdwResult = bIdentical ? SN_CMP_IDENTICAL : SN_CMP_SIGONLY;
+
+ UnloadAssembly(&sLoadCtx1);
+ UnloadAssembly(&sLoadCtx2);
+
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ if (bMappedAssem1)
+ UnloadAssembly(&sLoadCtx1);
+ if (bMappedAssem2)
+ UnloadAssembly(&sLoadCtx2);
+ goto Exit;
+
+ ImagesDiffer:
+ if (bMappedAssem1)
+ UnloadAssembly(&sLoadCtx1);
+ if (bMappedAssem2)
+ UnloadAssembly(&sLoadCtx2);
+ *pdwResult = SN_CMP_DIFFERENT;
+ retVal = TRUE;
+
+Exit:
+ END_ENTRYPOINT_VOIDRET;
+
+ return retVal;
+}
+
+
+// Compute the size of buffer needed to hold a hash for a given hash algorithm.
+SNAPI StrongNameHashSize(ULONG ulHashAlg, // [in] hash algorithm
+ DWORD *pcbSize) // [out] size of the hash in bytes
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ HCRYPTPROV hProv = NULL;
+ HCRYPTHASH hHash = NULL;
+ DWORD dwSize;
+
+
+ SNLOG((W("StrongNameHashSize(%08X, %08X)\n"), ulHashAlg, pcbSize));
+
+ SN_COMMON_PROLOG();
+
+ if (pcbSize == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Default hashing algorithm ID if necessary.
+ if (ulHashAlg == 0)
+ ulHashAlg = CALG_SHA1;
+
+ // Find a CSP supporting the required algorithm.
+ hProv = LocateCSP(NULL, SN_IGNORE_CONTAINER, ulHashAlg);
+ if (!hProv)
+ goto Error;
+
+ // Create a hash object.
+ if (!CryptCreateHash(hProv, ulHashAlg, 0, 0, &hHash))
+ goto Error;
+
+ // And ask for the size of the hash.
+ dwSize = sizeof(DWORD);
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)pcbSize, &dwSize, 0))
+ goto Error;
+
+ // Cleanup and exit.
+ CryptDestroyHash(hHash);
+ FreeCSP(hProv);
+
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ if (hHash)
+ CryptDestroyHash(hHash);
+ if (hProv)
+ FreeCSP(hProv);
+
+ Exit:
+
+ END_ENTRYPOINT_VOIDRET;
+
+ return retVal;
+}
+
+
+// Compute the size that needs to be allocated for a signature in an assembly.
+SNAPI StrongNameSignatureSize(BYTE *pbPublicKeyBlob, // [in] public key blob
+ ULONG cbPublicKeyBlob,
+ DWORD *pcbSize) // [out] size of the signature in bytes
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ PublicKeyBlob *pPublicKey = (PublicKeyBlob*)pbPublicKeyBlob;
+ ALG_ID uHashAlgId;
+ ALG_ID uSignAlgId;
+ HCRYPTPROV hProv = NULL;
+ HCRYPTHASH hHash = NULL;
+ HCRYPTKEY hKey = NULL;
+ LPCWSTR wszKeyContainer = NULL;
+ BOOLEAN bTempContainer = FALSE;
+ DWORD dwKeyLen;
+ DWORD dwBytes;
+
+ SNLOG((W("StrongNameSignatureSize(%08X, %08X, %08X)\n"), pbPublicKeyBlob, cbPublicKeyBlob, pcbSize));
+
+ SN_COMMON_PROLOG();
+
+ if (pbPublicKeyBlob == NULL)
+ SN_ERROR(E_POINTER);
+ if (!StrongNameIsValidPublicKey(pbPublicKeyBlob, cbPublicKeyBlob, false))
+ SN_ERROR(CORSEC_E_INVALID_PUBLICKEY);
+ if (pcbSize == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Special case neutral key.
+ if (SN_IS_NEUTRAL_KEY(pPublicKey))
+ pPublicKey = SN_THE_KEY();
+
+ // Determine hashing/signing algorithms.
+ uHashAlgId = GET_UNALIGNED_VAL32(&pPublicKey->HashAlgID);
+ uSignAlgId = GET_UNALIGNED_VAL32(&pPublicKey->SigAlgID);
+
+ // Default hashing and signing algorithm IDs if necessary.
+ if (uHashAlgId == 0)
+ uHashAlgId = CALG_SHA1;
+ if (uSignAlgId == 0)
+ uSignAlgId = CALG_RSA_SIGN;
+
+ // Create a temporary key container name.
+ if (!GetKeyContainerName(&wszKeyContainer, &bTempContainer))
+ goto Exit;
+
+ // Find a CSP supporting the required algorithms and create a temporary key
+ // container.
+ hProv = LocateCSP(wszKeyContainer, SN_CREATE_CONTAINER, uHashAlgId, uSignAlgId);
+ if (!hProv)
+ goto Error;
+
+ // Import the public key (we need to do this in order to determine the key
+ // length reliably).
+ if (!CryptImportKey(hProv,
+ pPublicKey->PublicKey,
+ GET_UNALIGNED_VAL32(&pPublicKey->cbPublicKey),
+ 0, 0, &hKey))
+ goto Error;
+
+ // Query the key attributes (it's the length we're interested in).
+ dwBytes = sizeof(dwKeyLen);
+ if (!CryptGetKeyParam(hKey, KP_KEYLEN, (BYTE*)&dwKeyLen, &dwBytes, 0))
+ goto Error;
+
+ // Delete the key container.
+ if (LocateCSP(wszKeyContainer, SN_DELETE_CONTAINER) == NULL) {
+ SetLastError(CORSEC_E_CONTAINER_NOT_FOUND);
+ goto Error;
+ }
+
+ // Take shortcut for the typical case
+ if ((uSignAlgId == CALG_RSA_SIGN) && (dwKeyLen % 8 == 0)) {
+ // The signature size known for CALG_RSA_SIGN
+ *pcbSize = dwKeyLen / 8;
+ }
+ else {
+ // Recreate the container so we can create a temporary key pair.
+ hProv = LocateCSP(wszKeyContainer, SN_CREATE_CONTAINER, uHashAlgId, uSignAlgId);
+ if (!hProv)
+ goto Error;
+
+ // Create the temporary key pair.
+ if (!CryptGenKey(hProv, g_uKeySpec, dwKeyLen << 16, &hKey))
+ goto Error;
+
+ // Create a hash.
+ if (!CryptCreateHash(hProv, uHashAlgId, 0, 0, &hHash))
+ goto Error;
+
+ // Compute size of the signature blob.
+ if (!CryptSignHashW(hHash, g_uKeySpec, NULL, 0, NULL, pcbSize))
+ goto Error;
+ CryptDestroyHash(hHash);
+
+ if (bTempContainer)
+ LocateCSP(wszKeyContainer, SN_DELETE_CONTAINER);
+ }
+
+ SNLOG((W("Signature size for hashalg %08X, %08X key (%08X bits) is %08X bytes\n"), uHashAlgId, uSignAlgId, dwKeyLen, *pcbSize));
+
+ CryptDestroyKey(hKey);
+ FreeCSP(hProv);
+ FreeKeyContainerName(wszKeyContainer, bTempContainer);
+
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+ if (hHash)
+ CryptDestroyHash(hHash);
+ if (hKey)
+ CryptDestroyKey(hKey);
+ if (hProv)
+ FreeCSP(hProv);
+ if (bTempContainer)
+ LocateCSP(wszKeyContainer, SN_DELETE_CONTAINER);
+ FreeKeyContainerName(wszKeyContainer, bTempContainer);
+
+ Exit:
+ END_ENTRYPOINT_VOIDRET;
+
+ return retVal;
+}
+
+// Locate CSP based on criteria specified in the registry (CSP name etc).
+// Optionally create or delete a named key container within that CSP.
+HCRYPTPROV LocateCSP(LPCWSTR wszKeyContainer,
+ DWORD dwAction,
+ ALG_ID uHashAlgId,
+ ALG_ID uSignAlgId)
+{
+ DWORD i;
+ DWORD dwType;
+ WCHAR wszName[SN_MAX_CSP_NAME + 1];
+ DWORD dwNameLength;
+ HCRYPTPROV hProv;
+ BOOLEAN bFirstAlg;
+ BOOLEAN bFoundHash;
+ BOOLEAN bFoundSign;
+ PROV_ENUMALGS rAlgs;
+ HCRYPTPROV hRetProv;
+ DWORD dwAlgsLen;
+
+ DWORD dwProvType = g_uProvType;
+
+ // If a CSP name has been provided (and we're not opening a CSP just to do a
+ // SHA1 hash or a verification), open the CSP directly.
+ if (g_bHasCSPName &&
+ (dwAction != SN_HASH_SHA1_ONLY))
+ {
+ if (StrongNameCryptAcquireContext(&hProv,
+ wszKeyContainer ? wszKeyContainer : NULL,
+ g_wszCSPName,
+ dwProvType,
+ SN_CAC_FLAGS(dwAction)))
+ return (dwAction == SN_DELETE_CONTAINER) ? (HCRYPTPROV)~0 : hProv;
+ else {
+ SNLOG((W("Failed to open CSP '%s': %08X\n"), g_wszCSPName, GetLastError()));
+ return NULL;
+ }
+ }
+
+ // Set up hashing and signing algorithms to look for based upon input
+ // parameters. Or if these haven't been supplied use the configured defaults
+ // instead.
+ if (uHashAlgId == 0)
+ uHashAlgId = g_uHashAlgId;
+ if (uSignAlgId == 0)
+ uSignAlgId = g_uSignAlgId;
+
+ // If default hashing and signing algorithms have been selected (SHA1 and
+ // RSA), we select the default CSP for the RSA_FULL type.
+ // For SHA2 and RSA, we select the default CSP For RSA_AES.
+ // Otherwise, you just get the first CSP that supports the algorithms
+ // you specified (with no guarantee that the selected CSP is a default of any type).
+ // This is because we have no way of forcing the enumeration to just give us default
+ // CSPs.
+ bool fUseDefaultCsp = false;
+ StrongNameCachedCsp cachedCspNumber = None;
+
+ // We know what container to use for SHA1 algorithms with RSA
+ if (((uHashAlgId == CALG_SHA1) && (uSignAlgId == CALG_RSA_SIGN)) ||
+ (dwAction == SN_HASH_SHA1_ONLY)) {
+ fUseDefaultCsp = true;
+ cachedCspNumber = Sha1CachedCsp;
+ dwProvType = PROV_RSA_FULL;
+
+ SNLOG((W("Attempting to open default provider\n")));
+ }
+
+ // We know what container to use for SHA2 algorithms with RSA
+ if ((uHashAlgId == CALG_SHA_256 || uHashAlgId == CALG_SHA_384 || uHashAlgId == CALG_SHA_512)
+ && uSignAlgId == CALG_RSA_SIGN) {
+ fUseDefaultCsp = true;
+ cachedCspNumber = Sha2CachedCsp;
+ dwProvType = PROV_RSA_AES;
+
+ SNLOG((W("Attempting to open default SHA2 provider\n")));
+ }
+
+ if (fUseDefaultCsp)
+ {
+ // If we're not trying to create/open/delete a key container, see if a
+ // CSP is cached.
+ if (wszKeyContainer == NULL && dwAction != SN_DELETE_CONTAINER) {
+ hProv = LookupCachedCSP(cachedCspNumber);
+ if (hProv) {
+ SNLOG((W("Found provider in cache\n")));
+ return hProv;
+ }
+ }
+ if (StrongNameCryptAcquireContext(&hProv,
+ wszKeyContainer ? wszKeyContainer : NULL,
+ NULL,
+ dwProvType,
+ SN_CAC_FLAGS(dwAction))) {
+ // If we're not trying to create/open/delete a key container, cache
+ // the CSP returned.
+ if (wszKeyContainer == NULL && dwAction != SN_DELETE_CONTAINER)
+ CacheCSP(hProv, cachedCspNumber);
+ return (dwAction == SN_DELETE_CONTAINER) ? (HCRYPTPROV)~0 : hProv;
+ } else {
+ SNLOG((W("Failed to open: %08X\n"), GetLastError()));
+ return NULL;
+ }
+ }
+
+ HRESULT hr = InitStrongNameCriticalSection();
+ if (FAILED(hr)) {
+ SetLastError(hr);
+ return NULL;
+ }
+
+ // Some crypto APIs are non thread safe (e.g. enumerating CSP
+ // hashing/signing algorithms). Use a mutex to serialize these operations.
+ // The following usage is GC-safe and exception-safe:
+ {
+ CRITSEC_Holder csh(g_rStrongNameMutex);
+
+ for (i = 0; ; i++) {
+
+ // Enumerate all CSPs.
+ dwNameLength = sizeof(wszName);
+ if (CryptEnumProvidersW(i, 0, 0, &dwType, wszName, &dwNameLength)) {
+
+ // Open the currently selected CSP.
+ SNLOG((W("Considering CSP '%s'\n"), wszName));
+ if (StrongNameCryptAcquireContext(&hProv,
+ NULL,
+ wszName,
+ dwType,
+ CRYPT_SILENT |
+ CRYPT_VERIFYCONTEXT |
+ (g_bUseMachineKeyset ? CRYPT_MACHINE_KEYSET : 0))) {
+
+ // Enumerate all the algorithms the CSP supports.
+ bFirstAlg = TRUE;
+ bFoundHash = FALSE;
+ bFoundSign = FALSE;
+ for (;;) {
+
+ dwAlgsLen = sizeof(rAlgs);
+ if (CryptGetProvParam(hProv,
+ PP_ENUMALGS, (BYTE*)&rAlgs, &dwAlgsLen,
+ bFirstAlg ? CRYPT_FIRST : 0)) {
+
+ if (rAlgs.aiAlgid == uHashAlgId)
+ bFoundHash = TRUE;
+ else if (rAlgs.aiAlgid == uSignAlgId)
+ bFoundSign = TRUE;
+
+ if (bFoundHash && bFoundSign) {
+
+ // Found a CSP that supports the required
+ // algorithms. Re-open the context with access to
+ // the required key container.
+
+ SNLOG((W("CSP matches\n")));
+
+ if (StrongNameCryptAcquireContext(&hRetProv,
+ wszKeyContainer ? wszKeyContainer : NULL,
+ wszName,
+ dwType,
+ CRYPT_SILENT |
+ SN_CAC_FLAGS(dwAction))) {
+ CryptReleaseContext(hProv, 0);
+ return (dwAction == SN_DELETE_CONTAINER) ? (HCRYPTPROV)~0 : hRetProv;
+ } else {
+ SNLOG((W("Failed to re-open for container: %08X\n"), GetLastError()));
+ break;
+ }
+ }
+
+ bFirstAlg = FALSE;
+
+ } else {
+ _ASSERTE(GetLastError() == ERROR_NO_MORE_ITEMS);
+ break;
+ }
+
+ }
+
+ CryptReleaseContext(hProv, 0);
+
+ } else
+ SNLOG((W("Failed to open CSP: %08X\n"), GetLastError()));
+
+ } else if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+
+ }
+ // csh for g_rStrongNameMutex goes out of scope here
+ }
+
+ // No matching CSP found.
+ SetLastError(CORSEC_E_NO_SUITABLE_CSP);
+ return NULL;
+}
+
+
+// Release a CSP acquired through LocateCSP.
+VOID FreeCSP(HCRYPTPROV hProv)
+{
+ // If the CSP is currently cached, don't release it yet.
+ if (!IsCachedCSP(hProv))
+ CryptReleaseContext(hProv, 0);
+}
+
+// Locate a cached CSP for this thread.
+HCRYPTPROV LookupCachedCSP(StrongNameCachedCsp cspNumber)
+{
+ SN_THREAD_CTX *pThreadCtx = GetThreadContext();
+ if (pThreadCtx == NULL)
+ return NULL;
+ return pThreadCtx->m_hProv[cspNumber];
+}
+
+
+// Update the CSP cache for this thread (freeing any CSP displaced).
+VOID CacheCSP(HCRYPTPROV hProv, StrongNameCachedCsp cspNumber)
+{
+ SN_THREAD_CTX *pThreadCtx = GetThreadContext();
+ if (pThreadCtx == NULL)
+ return;
+ if (pThreadCtx->m_hProv[cspNumber])
+ CryptReleaseContext(pThreadCtx->m_hProv[cspNumber], 0);
+ pThreadCtx->m_hProv[cspNumber] = hProv;
+}
+
+
+// Determine whether a given CSP is currently cached.
+BOOLEAN IsCachedCSP(HCRYPTPROV hProv)
+{
+ SN_THREAD_CTX *pThreadCtx = GetThreadContext();
+ if (pThreadCtx == NULL)
+ return FALSE;
+ for (ULONG i = 0; i < CachedCspCount; i++)
+ {
+ if(pThreadCtx->m_hProv[i] == hProv)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// rehash all files in a multi-module assembly
+BOOLEAN RehashModules (SN_LOAD_CTX *pLoadCtx, LPCWSTR wszFilePath) {
+ HRESULT hr;
+ ULONG ulHashAlg;
+ mdAssembly tkAssembly;
+ HENUMInternal hFileEnum;
+ mdFile tkFile;
+ LPCSTR pszFile;
+ BYTE *pbFileHash;
+ DWORD cbFileHash;
+ NewArrayHolder<BYTE> pbNewFileHash(NULL);
+ DWORD cbNewFileHash = 0;
+ DWORD cchDirectory;
+ DWORD cchFullFile;
+ CHAR szFullFile[MAX_PATH + 1];
+ WCHAR wszFullFile[MAX_PATH + 1];
+ LPCWSTR pszSlash;
+ DWORD cchFile;
+ IMDInternalImport *pMetaDataImport = NULL;
+
+ // Determine the directory the assembly lives in (this is where we'll
+ // look for linked files).
+ if (((pszSlash = wcsrchr(wszFilePath, W('\\'))) != NULL) || ((pszSlash = wcsrchr(wszFilePath, W('/'))) != NULL)) {
+ cchDirectory = (DWORD) (pszSlash - wszFilePath + 1);
+ cchDirectory = WszWideCharToMultiByte(CP_UTF8, 0, wszFilePath, cchDirectory, szFullFile, MAX_PATH, NULL, NULL);
+ if (cchDirectory >= MAX_PATH) {
+ SNLOG((W("Assembly directory name too long\n")));
+ hr = ERROR_BUFFER_OVERFLOW;
+ goto Error;
+ }
+ } else
+ cchDirectory = 0;
+
+ // Open the scope on the mapped image.
+ if (FAILED(hr = GetMetadataImport(pLoadCtx, &tkAssembly, &pMetaDataImport)))
+ {
+ goto Error;
+ }
+
+ // Determine the hash algorithm used for file references.
+ if (FAILED(hr = pMetaDataImport->GetAssemblyProps(
+ tkAssembly, // [IN] The Assembly for which to get the properties
+ NULL, // [OUT] Pointer to the Originator blob
+ NULL, // [OUT] Count of bytes in the Originator Blob
+ &ulHashAlg, // [OUT] Hash Algorithm
+ NULL, // [OUT] Buffer to fill with name
+ NULL, // [OUT] Assembly MetaData
+ NULL))) // [OUT] Flags
+ {
+ SNLOG((W("Failed to get assembly 0x%08X info, %08X\n"), tkAssembly, hr));
+ goto Error;
+ }
+
+ // Enumerate all file references.
+ if (FAILED(hr = pMetaDataImport->EnumInit(mdtFile, mdTokenNil, &hFileEnum)))
+ {
+ SNLOG((W("Failed to enumerate linked files, %08X\n"), hr));
+ goto Error;
+ }
+
+ for (; pMetaDataImport->EnumNext(&hFileEnum, &tkFile); ) {
+
+ // Determine the file name and the location of the hash.
+ if (FAILED(hr = pMetaDataImport->GetFileProps(
+ tkFile,
+ &pszFile,
+ (const void **)&pbFileHash,
+ &cbFileHash,
+ NULL)))
+ {
+ SNLOG((W("Failed to get file 0x%08X info, %08X\n"), tkFile, hr));
+ goto Error;
+ }
+
+ // Build the full filename by appending to the assembly directory we
+ // calculated earlier.
+ cchFile = (DWORD) strlen(pszFile);
+ if ((cchFile + cchDirectory) >= COUNTOF(szFullFile)) {
+ pMetaDataImport->EnumClose(&hFileEnum);
+ SNLOG((W("Linked file name too long (%S)\n"), pszFile));
+ hr = ERROR_BUFFER_OVERFLOW;
+ goto Error;
+ }
+ memcpy_s(&szFullFile[cchDirectory], COUNTOF(szFullFile) - cchDirectory, pszFile, cchFile + 1);
+
+ // Allocate enough buffer for the new hash.
+ if (cbNewFileHash < cbFileHash) {
+ pbNewFileHash = new (nothrow) BYTE[cbFileHash];
+ if (pbNewFileHash == NULL) {
+ hr = E_OUTOFMEMORY;
+ goto Error;
+ }
+ cbNewFileHash = cbFileHash;
+ }
+
+ cchFullFile = WszMultiByteToWideChar(CP_UTF8, 0, szFullFile, -1, wszFullFile, MAX_PATH);
+ if (cchFullFile == 0 || cchFullFile >= MAX_PATH) {
+ pMetaDataImport->EnumClose(&hFileEnum);
+ SNLOG((W("Assembly directory name too long\n")));
+ hr = ERROR_BUFFER_OVERFLOW;
+ goto Error;
+ }
+
+ // Compute a new hash for the file.
+ if (FAILED(hr = GetHashFromFileW(wszFullFile,
+ (unsigned*)&ulHashAlg,
+ pbNewFileHash,
+ cbNewFileHash,
+ &cbNewFileHash))) {
+ pMetaDataImport->EnumClose(&hFileEnum);
+ SNLOG((W("Failed to get compute file hash, %08X\n"), hr));
+ goto Error;
+ }
+
+ // The new hash has to be the same size (since we used the same
+ // algorithm).
+ _ASSERTE(cbNewFileHash == cbFileHash);
+
+ // We make the assumption here that the pointer to the file hash
+ // handed to us by the metadata is a direct pointer and not a
+ // buffered copy. If this changes, we'll need a new metadata API to
+ // support updates of this type.
+ memcpy_s(pbFileHash, cbFileHash, pbNewFileHash, cbFileHash);
+ }
+
+ pMetaDataImport->EnumClose(&hFileEnum);
+ pMetaDataImport->Release();
+ return TRUE;
+
+Error:
+ if (pMetaDataImport)
+ pMetaDataImport->Release();
+ if (pbNewFileHash)
+ pbNewFileHash.Release();
+ SetLastError(hr);
+ return FALSE;
+}
+
+//
+// Check that the public key portion of an assembly's identity matches the private key that it is being
+// signed with.
+//
+// Arguments:
+// pAssemblySignaturePublicKey - Assembly signature public key blob
+// wszKeyContainer - Key container holding the key the assembly is signed with
+// dwFlags - SN_ECMA_SIGN if the assembly is being ECMA signed, SN_TEST_SIGN if it is being test signed
+//
+// Return Value:
+// true if the assembly's public key matches the private key in wszKeyContainer, otherwise false
+//
+
+bool VerifyKeyMatchesAssembly(PublicKeyBlob * pAssemblySignaturePublicKey, __in_z LPCWSTR wszKeyContainer, BYTE *pbKeyBlob, ULONG cbKeyBlob, DWORD dwFlags)
+{
+ _ASSERTE(wszKeyContainer != NULL || pbKeyBlob != NULL);
+
+ // If we're test signing, then the assembly's public key will not match the private key by design.
+ // Since there's nothing to check, we can quit early.
+ if ((dwFlags & SN_TEST_SIGN) == SN_TEST_SIGN)
+ {
+ return true;
+ }
+
+ if (SN_IS_NEUTRAL_KEY(pAssemblySignaturePublicKey))
+ {
+ // If we're ECMA signing an assembly with the ECMA public key, then by definition the key matches.
+ if ((dwFlags & SN_ECMA_SIGN) == SN_ECMA_SIGN)
+ {
+ return true;
+ }
+
+ // Swap the real public key in for ECMA signing
+ pAssemblySignaturePublicKey = SN_THE_KEY();
+ }
+
+ // Otherwise, we need to check that the public key from the key container matches the public key from
+ // the assembly.
+ StrongNameBufferHolder<BYTE> pbSignaturePublicKey = NULL;
+ DWORD cbSignaturePublicKey;
+ if (!StrongNameGetPublicKeyEx(wszKeyContainer, pbKeyBlob, cbKeyBlob, &pbSignaturePublicKey, &cbSignaturePublicKey, GET_UNALIGNED_VAL32(&pAssemblySignaturePublicKey->HashAlgID), 0 /*Should be GET_UNALIGNED_VAL32(&pAssemblySignaturePublicKey->HashAlgID) once we support different signature algorithms*/))
+ {
+ // We failed to get the public key for the key in the given key container. StrongNameGetPublicKey
+ // has already set the error information, so we can just return false here without resetting it.
+ return false;
+ }
+ _ASSERTE(!pbSignaturePublicKey.IsNull() && pAssemblySignaturePublicKey != NULL);
+
+ // Do a raw compare on the public key blobs to see if they match
+ if (SN_SIZEOF_KEY(reinterpret_cast<PublicKeyBlob *>(pbSignaturePublicKey.GetValue())) == SN_SIZEOF_KEY(pAssemblySignaturePublicKey) &&
+ memcmp(static_cast<void *>(pAssemblySignaturePublicKey),
+ static_cast<void *>(pbSignaturePublicKey.GetValue()),
+ cbSignaturePublicKey) == 0)
+ {
+ return true;
+ }
+
+ SetStrongNameErrorInfo(SN_E_PUBLICKEY_MISMATCH);
+ return false;
+}
+
+// Map an assembly into memory.
+BOOLEAN LoadAssembly(SN_LOAD_CTX *pLoadCtx, LPCWSTR wszFilePath, DWORD inFlags, BOOLEAN fRequireSignature)
+{
+ DWORD dwError = S_OK;
+
+ // If a filename is not supplied, the image has already been mapped (and the
+ // image base and length fields set up correctly).
+ if (wszFilePath == NULL)
+ {
+ pLoadCtx->m_fPreMapped = TRUE;
+ pLoadCtx->m_pedecoder = new (nothrow) PEDecoder(pLoadCtx->m_pbBase, static_cast<COUNT_T>(pLoadCtx->m_dwLength));
+ if (pLoadCtx->m_pedecoder == NULL) {
+ dwError = E_OUTOFMEMORY;
+ goto Error;
+ }
+ }
+ else {
+
+ pLoadCtx->m_hMap = INVALID_HANDLE_VALUE;
+ pLoadCtx->m_pbBase = NULL;
+
+ // Open the file for reading or writing.
+ pLoadCtx->m_hFile = WszCreateFile(wszFilePath,
+ GENERIC_READ | (pLoadCtx->m_fReadOnly ? 0 : GENERIC_WRITE),
+ pLoadCtx->m_fReadOnly ? FILE_SHARE_READ : FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (pLoadCtx->m_hFile == INVALID_HANDLE_VALUE) {
+ dwError = HRESULT_FROM_GetLastError();
+ goto Error;
+ }
+
+ pLoadCtx->m_dwLength = SafeGetFileSize(pLoadCtx->m_hFile, NULL);
+ if (pLoadCtx->m_dwLength == 0xffffffff) {
+ dwError = HRESULT_FROM_GetLastError();
+ goto Error;
+ }
+
+ // Create a mapping handle for the file.
+ pLoadCtx->m_hMap = WszCreateFileMapping(pLoadCtx->m_hFile, NULL, pLoadCtx->m_fReadOnly ? PAGE_READONLY : PAGE_READWRITE, 0, 0, NULL);
+ if (pLoadCtx->m_hMap == NULL) {
+ dwError = HRESULT_FROM_GetLastError();
+ goto Error;
+ }
+
+ // And map it into memory.
+ pLoadCtx->m_pbBase = (BYTE*)CLRMapViewOfFile(pLoadCtx->m_hMap, pLoadCtx->m_fReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE, 0, 0, 0);
+ if (pLoadCtx->m_pbBase == NULL) {
+ dwError = HRESULT_FROM_GetLastError();
+ goto Error;
+ }
+ pLoadCtx->m_pedecoder = new (nothrow) PEDecoder(pLoadCtx->m_pbBase, static_cast<COUNT_T>(pLoadCtx->m_dwLength));
+ if (pLoadCtx->m_pedecoder == NULL) {
+ dwError = E_OUTOFMEMORY;
+ goto Error;
+ }
+ }
+
+ if (!pLoadCtx->m_pedecoder->HasContents() || !pLoadCtx->m_pedecoder->CheckCORFormat()) {
+ dwError = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto Error;
+ }
+
+ // Locate standard NT image header.
+ pLoadCtx->m_pNtHeaders = pLoadCtx->m_pedecoder->GetNTHeaders32();
+
+ if (pLoadCtx->m_pNtHeaders == NULL) {
+ dwError = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto Error;
+ }
+
+ pLoadCtx->m_pCorHeader = pLoadCtx->m_pedecoder->GetCorHeader();
+
+ if (pLoadCtx->m_pCorHeader == NULL) {
+ dwError = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto Error;
+ }
+
+ // Set up signature pointer (if we require it).
+ if (fRequireSignature && pLoadCtx->m_pedecoder->HasStrongNameSignature())
+ {
+ COUNT_T size = 0;
+ BYTE* pbSignature = (BYTE*)pLoadCtx->m_pedecoder->GetStrongNameSignature(&size);
+
+ // Make sure the signature doesn't point back into the header
+ if (pbSignature <= reinterpret_cast<BYTE*>(pLoadCtx->m_pCorHeader) &&
+ pbSignature > reinterpret_cast<BYTE*>(pLoadCtx->m_pCorHeader) - size)
+ {
+ dwError = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto Error;
+ }
+ if (pbSignature >= reinterpret_cast<BYTE*>(pLoadCtx->m_pCorHeader) &&
+ pbSignature - sizeof(IMAGE_COR20_HEADER) < reinterpret_cast<BYTE*>(pLoadCtx->m_pCorHeader))
+ {
+ dwError = CORSEC_E_INVALID_IMAGE_FORMAT;
+ goto Error;
+ }
+
+ pLoadCtx->m_pbSignature = pbSignature;
+ pLoadCtx->m_cbSignature = static_cast<DWORD>(size);
+ }
+
+ return TRUE;
+
+ Error:
+ if (!pLoadCtx->m_fPreMapped) {
+ if (pLoadCtx->m_pbBase)
+ CLRUnmapViewOfFile(pLoadCtx->m_pbBase);
+ if (pLoadCtx->m_hMap != INVALID_HANDLE_VALUE)
+ CloseHandle(pLoadCtx->m_hMap);
+ if (pLoadCtx->m_hFile != INVALID_HANDLE_VALUE)
+ CloseHandle(pLoadCtx->m_hFile);
+ }
+ SetLastError(dwError);
+ return FALSE;
+}
+
+
+// Unload an assembly loaded with LoadAssembly (recomputing checksum if
+// necessary).
+BOOLEAN UnloadAssembly(SN_LOAD_CTX *pLoadCtx)
+{
+ BOOLEAN bResult = TRUE;
+
+ if (!pLoadCtx->m_fReadOnly) {
+
+ IMAGE_NT_HEADERS *pNtHeaders = NULL;
+ DWORD dwCheckSum = 0;
+
+ // We late bind CheckSumMappedFile to avoid bringing in IMAGEHLP unless
+ // we need to.
+ HMODULE hLibrary = WszLoadLibrary(W("imagehlp.dll"));
+ if (hLibrary) {
+ IMAGE_NT_HEADERS *(*SN_CheckSumMappedFile)(BYTE*, DWORD, DWORD*, DWORD*);
+
+ if ((*(FARPROC*)&SN_CheckSumMappedFile = GetProcAddress(hLibrary, "CheckSumMappedFile")) != NULL) {
+ DWORD dwOldCheckSum;
+
+ pNtHeaders = SN_CheckSumMappedFile(pLoadCtx->m_pbBase,
+ pLoadCtx->m_dwLength,
+ &dwOldCheckSum,
+ &dwCheckSum);
+ }
+
+ FreeLibrary(hLibrary);
+
+ }
+
+ if (pNtHeaders != NULL) {
+ if (pNtHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC))
+ ((IMAGE_NT_HEADERS32*)pNtHeaders)->OptionalHeader.CheckSum = VAL32(dwCheckSum);
+ else
+ if (pNtHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC))
+ ((IMAGE_NT_HEADERS64*)pNtHeaders)->OptionalHeader.CheckSum = VAL32(dwCheckSum);
+ } else
+ bResult = FALSE;
+
+ if (!pLoadCtx->m_fPreMapped && !FlushViewOfFile(pLoadCtx->m_pbBase, 0))
+ bResult = FALSE;
+ }
+
+ if (!pLoadCtx->m_fPreMapped) {
+ if (!CLRUnmapViewOfFile(pLoadCtx->m_pbBase))
+ bResult = FALSE;
+
+ if (!CloseHandle(pLoadCtx->m_hMap))
+ bResult = FALSE;
+
+ if (!CloseHandle(pLoadCtx->m_hFile))
+ bResult = FALSE;
+ }
+
+ if (pLoadCtx->m_pedecoder != NULL)
+ {
+ delete (pLoadCtx->m_pedecoder);
+ pLoadCtx->m_pedecoder = NULL;
+ }
+
+ return bResult;
+}
+
+template<class T>
+LONG RegQueryValueT(HKEY hKey, LPCWSTR pValueName, T * pData)
+{
+ DWORD dwLength = sizeof(T);
+
+ LONG status = WszRegQueryValueEx(hKey, pValueName, NULL, NULL, (BYTE*) pData, & dwLength);
+
+ return status;
+}
+
+// Reads CSP configuration info (name of CSP to use, IDs of hashing/signing
+// algorithms) from the registry.
+HRESULT ReadRegistryConfig()
+{
+ HKEY hKey;
+ DWORD dwLength;
+
+ // Initialize all settings to their default values, in case they've not been
+ // specified in the registry.
+ g_bHasCSPName = FALSE;
+ g_bUseMachineKeyset = TRUE;
+ g_uKeySpec = AT_SIGNATURE;
+ g_uHashAlgId = CALG_SHA1;
+ g_uSignAlgId = CALG_RSA_SIGN;
+ g_uProvType = PROV_RSA_FULL;
+
+#ifdef FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+ g_pVerificationRecords = NULL;
+#endif
+
+ g_fCacheVerify = TRUE;
+
+ // Open the configuration key in the registry.
+ if (WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, SN_CONFIG_KEY_W, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+ return S_OK;
+
+ // Read the preferred CSP name.
+ {
+ // Working set optimization: avoid touching g_wszCSPName (2052 bytes in size) unless registry has value for it
+ WCHAR tempCSPName[_countof(g_wszCSPName)];
+ dwLength = sizeof(tempCSPName);
+
+ tempCSPName[0] = 0;
+
+ // If the registry key value is too long, that means it is invalid.
+ VERIFY(WszRegQueryValueEx(hKey, SN_CONFIG_CSP_W, NULL, NULL,
+ (BYTE*) tempCSPName, &dwLength) != ERROR_MORE_DATA);
+ tempCSPName[COUNTOF(tempCSPName) - 1] = W('\0'); // make sure the string is NULL-terminated
+ SNLOG((W("Preferred CSP name: '%s'\n"), tempCSPName));
+
+ if (tempCSPName[0] != W('\0'))
+ {
+ memcpy(g_wszCSPName, tempCSPName, sizeof(g_wszCSPName));
+ g_bHasCSPName = TRUE;
+ }
+ }
+
+ // Read the machine vs user key container flag.
+ DWORD dwUseMachineKeyset = TRUE;
+ RegQueryValueT(hKey, SN_CONFIG_MACHINE_KEYSET_W, & dwUseMachineKeyset);
+ SNLOG((W("Use machine keyset: %s\n"), dwUseMachineKeyset ? W("TRUE") : W("FALSE")));
+ g_bUseMachineKeyset = (BOOLEAN)dwUseMachineKeyset;
+
+ // Read the key spec.
+ RegQueryValueT(hKey, SN_CONFIG_KEYSPEC_W, & g_uKeySpec);
+ SNLOG((W("Key spec: %08X\n"), g_uKeySpec));
+
+ // Read the provider type
+ RegQueryValueT(hKey, SN_CONFIG_PROV_TYPE_W, & g_uProvType);
+ SNLOG((W("Provider Type: %08X\n"), g_uProvType));
+
+ // Read the hashing algorithm ID.
+ RegQueryValueT(hKey, SN_CONFIG_HASH_ALG_W, & g_uHashAlgId);
+ SNLOG((W("Hashing algorithm: %08X\n"), g_uHashAlgId));
+
+ // Read the signing algorithm ID.
+ RegQueryValueT(hKey, SN_CONFIG_SIGN_ALG_W, & g_uSignAlgId);
+ SNLOG((W("Signing algorithm: %08X\n"), g_uSignAlgId));
+
+ // Read the OK to cache verifications flag.
+ DWORD dwCacheVerify = TRUE;
+ RegQueryValueT(hKey, SN_CONFIG_CACHE_VERIFY_W, & dwCacheVerify);
+ SNLOG((W("OK to cache verifications: %s\n"), dwCacheVerify ? W("TRUE") : W("FALSE")));
+ g_fCacheVerify = (BOOLEAN)dwCacheVerify;
+
+ RegCloseKey(hKey);
+
+ HRESULT hr = S_OK;
+#ifdef FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+ // Read verify disable records.
+ IfFailRet(ReadVerificationRecords());
+#endif // FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+ IfFailRet(ReadRevocationRecords());
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+ return hr;
+}
+
+#ifdef FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+// Read verification records from the registry during startup.
+HRESULT ReadVerificationRecords()
+{
+ HKEYHolder hKey;
+ WCHAR wszSubKey[MAX_PATH + 1];
+ DWORD cchSubKey;
+ SN_VER_REC *pVerificationRecords = NULL;
+ HRESULT hr = S_OK;
+
+ // Open the verification subkey in the registry.
+ if (WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, SN_CONFIG_KEY_W W("\\") SN_CONFIG_VERIFICATION_W, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+ return hr;
+
+ // Assembly specific records are represented as subkeys of the key we've
+ // just opened.
+ for (DWORD i = 0; ; i++) {
+ // Get the name of the next subkey.
+ cchSubKey = MAX_PATH + 1;
+ FILETIME sFiletime;
+ if (WszRegEnumKeyEx(hKey, i, wszSubKey, &cchSubKey, NULL, NULL, NULL, &sFiletime) != ERROR_SUCCESS)
+ break;
+
+ // Open the subkey.
+ HKEYHolder hSubKey;
+ if (WszRegOpenKeyEx(hKey, wszSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) {
+ NewArrayHolder<WCHAR> mszUserList(NULL);
+ DWORD cbUserList;
+ NewArrayHolder<WCHAR> wszTestPublicKey(NULL);
+ DWORD cbTestPublicKey;
+ NewArrayHolder<WCHAR> wszAssembly(NULL);
+ SN_VER_REC *pVerRec;
+
+ // Read a list of valid users, if supplied.
+ if ((WszRegQueryValueEx(hSubKey, SN_CONFIG_USERLIST_W, NULL, NULL, NULL, &cbUserList) == ERROR_SUCCESS) &&
+ (cbUserList > 0)) {
+ mszUserList = new (nothrow) WCHAR[cbUserList / sizeof(WCHAR)];
+ if (!mszUserList) {
+ hr = E_OUTOFMEMORY;
+ goto FreeListExit;
+ }
+ WszRegQueryValueEx(hSubKey, SN_CONFIG_USERLIST_W, NULL, NULL, (BYTE*)mszUserList.GetValue(), &cbUserList);
+ }
+
+ // Read the test public key, if supplied
+ if ((WszRegQueryValueEx(hSubKey, SN_CONFIG_TESTPUBLICKEY_W, NULL, NULL, NULL, &cbTestPublicKey) == ERROR_SUCCESS) &&
+ (cbTestPublicKey > 0)) {
+ wszTestPublicKey = new (nothrow) WCHAR[cbTestPublicKey / sizeof(WCHAR)];
+ if (!wszTestPublicKey) {
+ hr = E_OUTOFMEMORY;
+ goto FreeListExit;
+ }
+ WszRegQueryValueEx(hSubKey, SN_CONFIG_TESTPUBLICKEY_W, NULL, NULL, (BYTE*)wszTestPublicKey.GetValue(), &cbTestPublicKey);
+ }
+
+ size_t dwSubKeyLen = wcslen(wszSubKey);
+ wszAssembly = new (nothrow) WCHAR[dwSubKeyLen+1];
+ if (!wszAssembly) {
+ hr = E_OUTOFMEMORY;
+ goto FreeListExit;
+ }
+ wcsncpy_s(wszAssembly, dwSubKeyLen+1, wszSubKey, _TRUNCATE);
+ wszAssembly[dwSubKeyLen] = W('\0');
+
+ // We've found a valid entry, add it to the local list.
+ pVerRec = new (nothrow) SN_VER_REC;
+ if (!pVerRec) {
+ hr = E_OUTOFMEMORY;
+ goto FreeListExit;
+ }
+
+ pVerRec->m_mszUserList = mszUserList;
+ pVerRec->m_wszTestPublicKey = wszTestPublicKey;
+ pVerRec->m_wszAssembly = wszAssembly;
+
+ mszUserList.SuppressRelease();
+ wszTestPublicKey.SuppressRelease();
+ wszAssembly.SuppressRelease();
+
+ pVerRec->m_pNext = pVerificationRecords;
+ pVerificationRecords = pVerRec;
+ SNLOG((W("Verification record for '%s' found in registry\n"), wszSubKey));
+ }
+ }
+
+ // Initialize the global list of verification records.
+ PVOID pv = InterlockedCompareExchangeT(&g_pVerificationRecords, pVerificationRecords, NULL);
+ if (pv == NULL)
+ return hr;
+
+FreeListExit:
+ // Iterate over local list of verification records and free allocated memory.
+ SN_VER_REC *pVerRec = pVerificationRecords;
+ while (pVerRec) {
+ delete [] pVerRec->m_mszUserList;
+ delete [] pVerRec->m_wszTestPublicKey;
+ delete [] pVerRec->m_wszAssembly;
+ SN_VER_REC *tmp = pVerRec->m_pNext;
+ delete pVerRec;
+ pVerRec = tmp;
+ }
+ return hr;
+}
+#endif // FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+
+#define SN_REVOCATION_KEY_NAME_W W("RevokedKeys") // Registry revocation key name
+#define SN_REVOKEDKEY_VALUE_NAME_W W("RevokedKey") // Registry value name
+
+HRESULT ReadReplacementKeys(HKEY hKey, SN_REPLACEMENT_KEY_REC **ppReplacementRecords)
+{
+ HRESULT hr = S_OK;
+
+ DWORD uValueCount;
+ DWORD cchMaxValueNameLen;
+
+ NewArrayHolder<WCHAR> wszValueName(NULL);
+
+ if(RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &uValueCount, &cchMaxValueNameLen, NULL, NULL, NULL) != ERROR_SUCCESS)
+ return hr;
+
+ cchMaxValueNameLen++; // Add 1 for null character
+
+ DWORD cchValueName;
+ wszValueName = new (nothrow) WCHAR[cchMaxValueNameLen];
+ if (!wszValueName) {
+ return E_OUTOFMEMORY;
+ }
+
+ for (DWORD j = 0; j < uValueCount; j++) {
+ cchValueName = cchMaxValueNameLen;
+ if (WszRegEnumValue(hKey, j, wszValueName, &cchValueName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+ break;
+
+ if(SString::_wcsicmp(wszValueName, SN_REVOKEDKEY_VALUE_NAME_W) == 0) // Skip over the "RevokedKey" value
+ continue;
+
+ NewArrayHolder<BYTE> pbReplacementKey(NULL);
+ DWORD cbReplacementKey;
+ DWORD dwValType;
+ if ((WszRegQueryValueEx(hKey, wszValueName, NULL, &dwValType, NULL, &cbReplacementKey) == ERROR_SUCCESS) &&
+ (cbReplacementKey > 0) && (dwValType == REG_BINARY)) {
+ pbReplacementKey = new (nothrow) BYTE[cbReplacementKey];
+ if (!pbReplacementKey) {
+ return E_OUTOFMEMORY;
+ }
+ if(WszRegQueryValueEx(hKey, wszValueName, NULL, NULL, (BYTE*)pbReplacementKey.GetValue(), &cbReplacementKey) == ERROR_SUCCESS)
+ {
+ NewHolder<SN_REPLACEMENT_KEY_REC> pReplacementRecord(new (nothrow) SN_REPLACEMENT_KEY_REC);
+ if (pReplacementRecord == NULL) {
+ return E_OUTOFMEMORY;
+ }
+
+ pReplacementRecord->m_pbReplacementKey = pbReplacementKey.Extract();
+ pReplacementRecord->m_cbReplacementKey = cbReplacementKey;
+ // Insert into list
+ pReplacementRecord->m_pNext = *ppReplacementRecords;
+ *ppReplacementRecords = pReplacementRecord.Extract();
+ }
+ }
+ }
+
+ return hr;
+}
+
+// Read revocation records from the registry during startup.
+HRESULT ReadRevocationRecordsFromKey(REGSAM samDesired, SN_REVOCATION_REC **ppRevocationRecords)
+{
+ HKEYHolder hKey;
+ WCHAR wszSubKey[MAX_PATH + 1];
+ DWORD cchSubKey;
+ HRESULT hr = S_OK;
+
+ // Open the revocation subkey in the registry.
+ if (WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, SN_CONFIG_KEY_W W("\\") SN_REVOCATION_KEY_NAME_W, 0, samDesired, &hKey) != ERROR_SUCCESS)
+ return hr;
+
+ // Assembly specific records are represented as subkeys of the key we've
+ // just opened.
+ for (DWORD i = 0; ; i++) {
+ // Read the next subkey
+ cchSubKey = MAX_PATH + 1; // reset size of buffer, as the following call changes it
+ if (WszRegEnumKeyEx(hKey, i, wszSubKey, &cchSubKey, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+ break;
+
+ // Open the subkey.
+ HKEYHolder hSubKey;
+ if (WszRegOpenKeyEx(hKey, wszSubKey, 0, samDesired, &hSubKey) == ERROR_SUCCESS) {
+ NewArrayHolder<BYTE> pbRevokedKey(NULL);
+ DWORD cbRevokedKey;
+ DWORD dwValType;
+
+ // Read the "RevokedKey" value
+ if ((WszRegQueryValueEx(hSubKey, SN_REVOKEDKEY_VALUE_NAME_W, NULL, &dwValType, NULL, &cbRevokedKey) == ERROR_SUCCESS) &&
+ (cbRevokedKey > 0) && (dwValType == REG_BINARY)) {
+ pbRevokedKey = new (nothrow) BYTE[cbRevokedKey];
+ if (!pbRevokedKey) {
+ return E_OUTOFMEMORY;
+ }
+
+ if(WszRegQueryValueEx(hSubKey, SN_REVOKEDKEY_VALUE_NAME_W, NULL, NULL, (BYTE*)pbRevokedKey.GetValue(), &cbRevokedKey) == ERROR_SUCCESS)
+ {
+ // We've found a valid entry, store it
+ NewHolder<SN_REVOCATION_REC> pRevocationRecord(new (nothrow) SN_REVOCATION_REC);
+ if (pRevocationRecord == NULL) {
+ return E_OUTOFMEMORY;
+ }
+
+ pRevocationRecord->m_pbRevokedKey = pbRevokedKey.Extract();
+ pRevocationRecord->m_cbRevokedKey = cbRevokedKey;
+ pRevocationRecord->m_pReplacementKeys = NULL;
+
+ // Insert into list
+ pRevocationRecord->m_pNext = *ppRevocationRecords;
+ *ppRevocationRecords = pRevocationRecord.Extract();
+
+ IfFailRet(ReadReplacementKeys(hSubKey, &pRevocationRecord->m_pReplacementKeys));
+
+ SNLOG((W("Revocation record '%s' found in registry\n"), wszSubKey));
+ }
+ }
+ }
+ }
+
+ return hr;
+}
+
+HRESULT ReadRevocationRecords()
+{
+ HRESULT hr = S_OK;
+
+ SYSTEM_INFO systemInfo;
+ SN_REVOCATION_REC *pRevocationRecords = NULL;
+
+ GetNativeSystemInfo(&systemInfo);
+ // Read both Software\ and Software\WOW6432Node\ on 64-bit systems
+ if(systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+ {
+ IfFailGoto(ReadRevocationRecordsFromKey(KEY_READ | KEY_WOW64_64KEY, &pRevocationRecords), FreeListExit);
+ IfFailGoto(ReadRevocationRecordsFromKey(KEY_READ | KEY_WOW64_32KEY, &pRevocationRecords), FreeListExit);
+ }
+ else
+ {
+ IfFailGoto(ReadRevocationRecordsFromKey(KEY_READ, &pRevocationRecords), FreeListExit);
+ }
+
+ // Initialize the global list of verification records.
+ PVOID pv = InterlockedCompareExchangeT(&g_pRevocationRecords, pRevocationRecords, NULL);
+
+ if (pv == NULL) // Successfully inserted the list we just created
+ return hr;
+
+FreeListExit:
+ // Iterate over local list of verification records and free allocated memory.
+ SN_REVOCATION_REC *pRevRec = pRevocationRecords;
+ while (pRevRec) {
+ if(pRevRec->m_pbRevokedKey)
+ delete [] pRevRec->m_pbRevokedKey;
+
+ SN_REPLACEMENT_KEY_REC *pKeyRec = pRevRec->m_pReplacementKeys;
+ while (pKeyRec) {
+ if(pKeyRec->m_pbReplacementKey)
+ delete [] pKeyRec->m_pbReplacementKey;
+
+ SN_REPLACEMENT_KEY_REC *tmp = pKeyRec->m_pNext;
+ delete pKeyRec;
+ pKeyRec = tmp;
+ }
+
+ SN_REVOCATION_REC *tmp2 = pRevRec->m_pNext;
+ delete pRevRec;
+ pRevRec = tmp2;
+ }
+ return hr;
+}
+
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+// Check current user name against a multi-string user name list. Return true if
+// the name is found (or the list is empty).
+BOOLEAN IsValidUser(__in_z WCHAR *mszUserList)
+{
+ HANDLE hToken;
+ DWORD dwRetLen;
+ TOKEN_USER *pUser;
+ WCHAR wszUser[1024];
+ WCHAR wszDomain[1024];
+ DWORD cchUser;
+ DWORD cchDomain;
+ SID_NAME_USE eSidUse;
+ WCHAR *wszUserEntry;
+
+ // Empty list implies no user name checking.
+ if (mszUserList == NULL)
+ return TRUE;
+
+ // Get current user name. Don't cache this to avoid threading/impersonation
+ // problems.
+ // First look to see if there's a security token on the current thread
+ // (maybe we're impersonating). If not, we'll get the token from the
+ // process.
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_READ, FALSE, &hToken))
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) {
+ SNLOG((W("Failed to find a security token, error %08X\n"), GetLastError()));
+ return FALSE;
+ }
+
+ // Get the user SID. (Calculate buffer size first).
+ if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwRetLen) &&
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ SNLOG((W("Failed to calculate token information buffer size, error %08X\n"), GetLastError()));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ NewArrayHolder<BYTE> pvBuffer = new (nothrow) BYTE[dwRetLen];
+ if (pvBuffer == NULL)
+ {
+ SetLastError(E_OUTOFMEMORY);
+ return FALSE;
+ }
+
+ if (!GetTokenInformation(hToken, TokenUser, reinterpret_cast<LPVOID>((BYTE*)pvBuffer), dwRetLen, &dwRetLen)) {
+ SNLOG((W("Failed to acquire token information, error %08X\n"), GetLastError()));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ pUser = reinterpret_cast<TOKEN_USER *>(pvBuffer.GetValue());
+
+ // Get the user and domain names.
+ cchUser = sizeof(wszUser) / sizeof(WCHAR);
+ cchDomain = sizeof(wszDomain) / sizeof(WCHAR);
+ if (!WszLookupAccountSid(NULL, pUser->User.Sid,
+ wszUser, &cchUser,
+ wszDomain, &cchDomain,
+ &eSidUse)) {
+ SNLOG((W("Failed to lookup account information, error %08X\n"), GetLastError()));
+ CloseHandle(hToken);
+ return FALSE;
+ }
+
+ CloseHandle(hToken);
+
+ // Concatenate user and domain name to get a fully qualified account name.
+ if (((wcslen(wszUser) + wcslen(wszDomain) + 2) * sizeof(WCHAR)) > sizeof(wszDomain)) {
+ SNLOG((W("Fully qualified account name was too long\n")));
+ return FALSE;
+ }
+ wcscat_s(wszDomain, COUNTOF(wszDomain), W("\\"));
+ wcscat_s(wszDomain, COUNTOF(wszDomain), wszUser);
+ SNLOG((W("Current username is '%s'\n"), wszDomain));
+
+ // Check current user against each name in the multi-string (packed
+ // list of nul terminated strings terminated with an additional nul).
+ wszUserEntry = mszUserList;
+ while (*wszUserEntry) {
+ if (!SString::_wcsicmp(wszDomain, wszUserEntry))
+ return TRUE;
+ wszUserEntry += wcslen(wszUserEntry) + 1;
+ }
+
+ // No user name match, fail search.
+ SNLOG((W("No username match\n")));
+
+ return FALSE;
+}
+
+#ifdef FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+// See if there's a verification records for the given assembly.
+SN_VER_REC *GetVerificationRecord(__in_z __deref LPWSTR wszAssemblyName, PublicKeyBlob *pPublicKey)
+{
+ SN_VER_REC *pVerRec;
+ SN_VER_REC *pWildcardVerRec = NULL;
+ LPWSTR pAssembly = NULL;
+ BYTE *pbToken;
+ DWORD cbToken;
+ WCHAR wszStrongName[(SN_SIZEOF_TOKEN * 2) + 1];
+ DWORD i;
+
+ // Compress the public key to make for a shorter assembly name.
+ if (!StrongNameTokenFromPublicKey((BYTE*)pPublicKey,
+ SN_SIZEOF_KEY(pPublicKey),
+ &pbToken,
+ &cbToken))
+ return NULL;
+
+ if (cbToken > SN_SIZEOF_TOKEN)
+ return NULL;
+
+ // Turn the token into hex.
+ for (i = 0; i < cbToken; i++) {
+ static WCHAR *wszHex = W("0123456789ABCDEF");
+ wszStrongName[(i * 2) + 0] = wszHex[(pbToken[i] >> 4)];
+ wszStrongName[(i * 2) + 1] = wszHex[(pbToken[i] & 0x0F)];
+ }
+ wszStrongName[i * 2] = W('\0');
+ delete[] pbToken;
+
+ // Build the full assembly name.
+
+ size_t nLen = wcslen(wszAssemblyName) + wcslen(W(",")) + wcslen(wszStrongName);
+ pAssembly = new (nothrow) WCHAR[nLen +1]; // +1 for NULL
+ if (pAssembly == NULL)
+ return NULL;
+ wcscpy_s(pAssembly, nLen + 1, wszAssemblyName);
+ wcscat_s(pAssembly, nLen + 1, W(","));
+ wcscat_s(pAssembly, nLen + 1, wszStrongName);
+
+ // Iterate over global list of verification records.
+ for (pVerRec = g_pVerificationRecords; pVerRec; pVerRec = pVerRec->m_pNext) {
+ // Look for matching assembly name.
+ if (!SString::_wcsicmp(pAssembly, pVerRec->m_wszAssembly)) {
+ delete[] pAssembly;
+ // Check current user against allowed user name list.
+ if (IsValidUser(pVerRec->m_mszUserList))
+ return pVerRec;
+ else
+ return NULL;
+ } else if (!wcscmp(W("*,*"), pVerRec->m_wszAssembly)) {
+ // Found a wildcard record, it'll do if we don't find something more
+ // specific.
+ if (pWildcardVerRec == NULL)
+ pWildcardVerRec = pVerRec;
+ } else if (!wcsncmp(W("*,"), pVerRec->m_wszAssembly, 2)) {
+ // Found a wildcard record (with a specific strong name). If the
+ // strong names match it'll do unless we find something more
+ // specific (it overrides "*,*" wildcards though).
+ if (!SString::_wcsicmp(wszStrongName, &pVerRec->m_wszAssembly[2]))
+ pWildcardVerRec = pVerRec;
+ }
+ }
+
+ delete[] pAssembly;
+
+ // No match on specific assembly name, see if there's a wildcard entry.
+ if (pWildcardVerRec)
+ // Check current user against allowed user name list.
+ if (IsValidUser(pWildcardVerRec->m_mszUserList))
+ return pWildcardVerRec;
+ else
+ return NULL;
+
+ return NULL;
+}
+#endif // FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+
+HRESULT
+CallGetMetaDataInternalInterface(
+ LPVOID pData,
+ ULONG cbData,
+ DWORD flags,
+ REFIID riid,
+ LPVOID *ppInterface)
+{
+#ifdef FEATURE_STRONGNAME_STANDALONE_WINRT
+ return E_NOTIMPL;
+#elif STRONGNAME_IN_VM || !FEATURE_STANDALONE_SN
+ // We link the GetMetaDataInternalInterface, so just call it
+ return GetMetaDataInternalInterface(
+ pData,
+ cbData,
+ flags,
+ riid,
+ ppInterface);
+#elif FEATURE_CORECLR
+ return E_NOTIMPL;
+#else
+
+ // We late bind the metadata function to avoid having a direct dependence on
+ // mscoree.dll unless we absolutely need to.
+
+ HRESULT hr = S_OK;
+ ICLRMetaHost *pCLRMetaHost = NULL;
+ ICLRRuntimeInfo *pCLRRuntimeInfo = NULL;
+ ICLRRuntimeHostInternal *pCLRRuntimeHostInternal = NULL;
+
+ HMODULE hLibrary = WszLoadLibrary(MSCOREE_SHIM_W);
+ if (hLibrary == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("WszLoadLibrary(\"") MSCOREE_SHIM_W W("\") failed with %08x\n"), hr));
+ goto ErrExit;
+ }
+
+ typedef HRESULT (__stdcall *PFNCLRCreateInstance)(REFCLSID clsid, REFIID riid, /*iid_is(riid)*/ LPVOID *ppInterface);
+ PFNCLRCreateInstance pfnCLRCreateInstance = reinterpret_cast<PFNCLRCreateInstance>(GetProcAddress(
+ hLibrary,
+ "CLRCreateInstance"));
+ if (pfnCLRCreateInstance == NULL)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Couldn't find CLRCreateInstance() in ") MSCOREE_SHIM_W W(": %08x\n"), hr));
+ goto ErrExit;
+ }
+
+ if (FAILED(hr = pfnCLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID *)&pCLRMetaHost)))
+ {
+ SNLOG((W("Error calling CLRCreateInstance() in ") MSCOREE_SHIM_W W(": %08x\n"), hr));
+ goto ErrExit;
+ }
+
+ if (FAILED(hr = pCLRMetaHost->GetRuntime(
+ W("v") VER_PRODUCTVERSION_NO_QFE_STR_L,
+ IID_ICLRRuntimeInfo,
+ (LPVOID *)&pCLRRuntimeInfo)))
+ {
+ SNLOG((W("Error calling ICLRMetaHost::GetRuntime() in ") MSCOREE_SHIM_W W(": %08x\n"), hr));
+ goto ErrExit;
+ }
+
+ if (FAILED(hr = pCLRRuntimeInfo->GetInterface(
+ CLSID_CLRRuntimeHostInternal,
+ IID_ICLRRuntimeHostInternal,
+ (LPVOID *)&pCLRRuntimeHostInternal)))
+ {
+ SNLOG((W("Error calling ICLRRuntimeInfo::GetInterface() in ") MSCOREE_SHIM_W W(": %08x\n"), hr));
+ goto ErrExit;
+ }
+
+ hr = pCLRRuntimeHostInternal->GetMetaDataInternalInterface(
+ (BYTE *)pData,
+ cbData,
+ flags,
+ riid,
+ ppInterface);
+
+ErrExit:
+ if (pCLRMetaHost != NULL)
+ {
+ pCLRMetaHost->Release();
+ }
+ if (pCLRRuntimeInfo != NULL)
+ {
+ pCLRRuntimeInfo->Release();
+ }
+ if (pCLRRuntimeHostInternal != NULL)
+ {
+ pCLRRuntimeHostInternal->Release();
+ }
+
+ return hr;
+
+#endif
+} // CallGetMetaDataInternalInterface
+
+// Load metadata engine and return an importer.
+HRESULT
+GetMetadataImport(
+ __in const SN_LOAD_CTX *pLoadCtx,
+ __in mdAssembly *ptkAssembly,
+ __out IMDInternalImport **ppMetaDataImport)
+{
+ HRESULT hr = E_FAIL;
+ BYTE *pMetaData = NULL;
+
+ // Locate the COM+ meta data within the header.
+ if (pLoadCtx->m_pedecoder->CheckCorHeader())
+ {
+ pMetaData = (BYTE *)pLoadCtx->m_pedecoder->GetMetadata();
+ }
+
+ if (pMetaData == NULL)
+ {
+ SNLOG((W("Couldn't locate the COM+ header\n")));
+ return CORSEC_E_INVALID_IMAGE_FORMAT;
+ }
+
+ // Open a metadata scope on the memory directly.
+ ReleaseHolder<IMDInternalImport> pMetaDataImportHolder;
+ if (FAILED(hr = CallGetMetaDataInternalInterface(
+ pMetaData,
+ VAL32(pLoadCtx->m_pCorHeader->MetaData.Size),
+ ofRead,
+ IID_IMDInternalImport,
+ &pMetaDataImportHolder)))
+ {
+ SNLOG((W("GetMetaDataInternalInterface() failed with %08x\n"), hr));
+ return SubstituteErrorIfNotTransient(hr, CORSEC_E_INVALID_IMAGE_FORMAT);
+ }
+
+ // Determine the metadata token for the assembly from the scope.
+ if (FAILED(hr = pMetaDataImportHolder->GetAssemblyFromScope(ptkAssembly)))
+ {
+ SNLOG((W("pMetaData->GetAssemblyFromScope() failed with %08x\n"), hr));
+ return SubstituteErrorIfNotTransient(hr, CORSEC_E_INVALID_IMAGE_FORMAT);
+ }
+
+ *ppMetaDataImport = pMetaDataImportHolder.Extract();
+ return S_OK;
+}
+#if STRONGNAME_IN_VM
+// Function to form the fully qualified assembly name from the load context
+BOOL FormFullyQualifiedAssemblyName(SN_LOAD_CTX *pLoadCtx, SString &assemblyName)
+{
+ mdAssembly tkAssembly;
+ // Open a metadata scope on the image.
+ ReleaseHolder<IMDInternalImport> pMetaDataImport;
+ HRESULT hr;
+ if (FAILED(hr = GetMetadataImport(pLoadCtx, &tkAssembly, &pMetaDataImport)))
+ return FALSE;
+
+ if (pMetaDataImport != NULL)
+ {
+ PEAssembly::GetFullyQualifiedAssemblyName(pMetaDataImport, tkAssembly, assemblyName);
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+
+
+// Locate the public key blob located within the metadata of an assembly file
+// and return a copy (use delete to deallocate). Optionally get the assembly
+// name as well.
+HRESULT FindPublicKey(const SN_LOAD_CTX *pLoadCtx,
+ __out_ecount_opt(cchAssemblyName) LPWSTR wszAssemblyName,
+ DWORD cchAssemblyName,
+ __out PublicKeyBlob **ppPublicKey,
+ DWORD *pcbPublicKey)
+{
+ HRESULT hr = S_OK;
+ *ppPublicKey = NULL;
+
+ // Open a metadata scope on the image.
+ mdAssembly tkAssembly;
+ ReleaseHolder<IMDInternalImport> pMetaDataImport;
+ if (FAILED(hr = GetMetadataImport(pLoadCtx, &tkAssembly, &pMetaDataImport)))
+ return hr;
+
+ // Read the public key location from the assembly properties (it's known as
+ // the originator property).
+ PublicKeyBlob *pKey;
+ DWORD dwKeyLen;
+ LPCSTR szAssemblyName;
+ if (FAILED(hr = pMetaDataImport->GetAssemblyProps(tkAssembly, // [IN] The Assembly for which to get the properties
+ (const void **)&pKey, // [OUT] Pointer to the Originator blob
+ &dwKeyLen, // [OUT] Count of bytes in the Originator Blob
+ NULL, // [OUT] Hash Algorithm
+ &szAssemblyName, // [OUT] Buffer to fill with name
+ NULL, // [OUT] Assembly MetaData
+ NULL))) // [OUT] Flags
+ {
+ SNLOG((W("Did not get public key property: %08x\n"), hr));
+ return SubstituteErrorIfNotTransient(hr, CORSEC_E_MISSING_STRONGNAME);
+ }
+
+ if (dwKeyLen == 0)
+ {
+ SNLOG((W("No public key stored in metadata\n")));
+ return CORSEC_E_MISSING_STRONGNAME;
+ }
+
+ // Make a copy of the key blob (because we're going to close the metadata scope).
+ NewArrayHolder<BYTE> pKeyCopy(new (nothrow) BYTE[dwKeyLen]);
+ if (pKeyCopy == NULL)
+ return E_OUTOFMEMORY;
+ memcpy_s(pKeyCopy, dwKeyLen, pKey, dwKeyLen);
+
+ // Copy the assembly name as well (if it was asked for). We also convert
+ // from UTF8 to UNICODE while we're at it.
+ if (wszAssemblyName)
+ WszMultiByteToWideChar(CP_UTF8, 0, szAssemblyName, -1, wszAssemblyName, cchAssemblyName);
+
+ *ppPublicKey = reinterpret_cast<PublicKeyBlob *>(pKeyCopy.Extract());
+ if(pcbPublicKey != NULL)
+ *pcbPublicKey = dwKeyLen;
+
+ return S_OK;
+}
+
+BYTE HexToByte (WCHAR wc) {
+ if (!iswxdigit(wc)) return (BYTE) 0xff;
+ if (iswdigit(wc)) return (BYTE) (wc - W('0'));
+ if (iswupper(wc)) return (BYTE) (wc - W('A') + 10);
+ return (BYTE) (wc - W('a') + 10);
+}
+
+// Read the hex string into a PublicKeyBlob structure.
+// Caller owns the blob.
+PublicKeyBlob *GetPublicKeyFromHex(LPCWSTR wszPublicKeyHexString) {
+ size_t cchHex = wcslen(wszPublicKeyHexString);
+ size_t cbHex = cchHex / 2;
+ if (cchHex % 2 != 0)
+ return NULL;
+
+ BYTE *pKey = new (nothrow) BYTE[cbHex];
+ if (!pKey)
+ return NULL;
+ for (size_t i = 0; i < cbHex; i++) {
+ pKey[i] = (BYTE) ((HexToByte(*wszPublicKeyHexString) << 4) | HexToByte(*(wszPublicKeyHexString + 1)));
+ wszPublicKeyHexString += 2;
+ }
+ return (PublicKeyBlob*) pKey;
+}
+
+// Create a temporary key container name likely to be unique to this process and
+// thread. Any existing container with the same name is deleted.
+BOOLEAN GetKeyContainerName(LPCWSTR *pwszKeyContainer, BOOLEAN *pbTempContainer)
+{
+ *pbTempContainer = FALSE;
+
+ if (*pwszKeyContainer != NULL)
+ return TRUE;
+
+ GUID guid;
+ HRESULT hr = CoCreateGuid(&guid);
+ if (FAILED(hr)) {
+ SetStrongNameErrorInfo(hr);
+ return FALSE;
+ }
+
+ WCHAR wszGuid[64];
+ if (GuidToLPWSTR(guid, wszGuid, sizeof(wszGuid) / sizeof(WCHAR)) == 0) {
+ SetStrongNameErrorInfo(E_UNEXPECTED); // this operation should never fail
+ return FALSE;
+ }
+
+ // Name is of form '__MSCORSN__<guid>__' where <guid> is a GUID.
+ const size_t cchLengthOfKeyContainer = sizeof("__MSCORSN____") + (sizeof(wszGuid) / sizeof(WCHAR)) + 1 /* null */;
+ LPWSTR wszKeyContainer = new (nothrow) WCHAR[cchLengthOfKeyContainer];
+ if (wszKeyContainer == NULL) {
+ SetStrongNameErrorInfo(E_OUTOFMEMORY);
+ return FALSE;
+ }
+
+ _snwprintf_s(wszKeyContainer, cchLengthOfKeyContainer - 1 /* exclude null */, _TRUNCATE,
+ W("__MSCORSN__%s__"),
+ wszGuid);
+
+ // Delete any stale container with the same name.
+ LocateCSP(wszKeyContainer, SN_DELETE_CONTAINER);
+
+ SNLOG((W("Creating temporary key container name '%s'\n"), wszKeyContainer));
+
+ *pwszKeyContainer = wszKeyContainer;
+ *pbTempContainer = TRUE;
+
+ return TRUE;
+}
+
+
+// Free resources allocated by GetKeyContainerName and delete the named
+// container.
+VOID FreeKeyContainerName(LPCWSTR wszKeyContainer, BOOLEAN bTempContainer)
+{
+ if (bTempContainer) {
+ // Free the name.
+ delete [] (WCHAR*)wszKeyContainer;
+ }
+}
+
+static DWORD GetSpecialKeyFlags(PublicKeyBlob* pKey)
+{
+ if (SN_IS_THE_KEY(pKey))
+ return SN_OUTFLAG_MICROSOFT_SIGNATURE;
+
+ return 0;
+}
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+
+HRESULT VerifyCounterSignature(
+ PublicKeyBlob *pSignaturePublicKey,
+ ULONG cbSignaturePublicKey,
+ PublicKeyBlob *pIdentityPublicKey,
+ BYTE *pCounterSignature,
+ ULONG cbCounterSignature)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ HRESULT hr = S_OK;
+
+ HandleStrongNameCspHolder hProv(NULL);
+ HandleKeyHolder hKey(NULL);
+ HandleHashHolder hHash(NULL);
+
+ hProv = LocateCSP(NULL, SN_IGNORE_CONTAINER, GET_UNALIGNED_VAL32(&pIdentityPublicKey->HashAlgID), GET_UNALIGNED_VAL32(&pIdentityPublicKey->SigAlgID));
+
+ if (!hProv)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to acquire a CSP: %08x"), hr));
+ return hr;
+ }
+
+ if(SN_IS_NEUTRAL_KEY(pIdentityPublicKey))
+ {
+ pIdentityPublicKey = reinterpret_cast<PublicKeyBlob *>(const_cast<BYTE *>(g_rbTheKey));
+ }
+
+ BYTE *pbRealPublicKey = pIdentityPublicKey->PublicKey;
+ DWORD cbRealPublicKey = GET_UNALIGNED_VAL32(&pIdentityPublicKey->cbPublicKey);
+
+ if (!CryptImportKey(hProv, pbRealPublicKey, cbRealPublicKey, 0, 0, &hKey))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to import key: %08x"), hr));
+ return hr;
+ }
+
+ // Create a hash object.
+ if (!CryptCreateHash(hProv, GET_UNALIGNED_VAL32(&pIdentityPublicKey->HashAlgID), 0, 0, &hHash))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to create hash: %08x"), hr));
+ return hr;
+ }
+
+ if (!CryptHashData(hHash, (BYTE*)pSignaturePublicKey, cbSignaturePublicKey, 0))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to compute hash: %08x"), hr));
+ return hr;
+ }
+
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+ if (hHash != (HCRYPTHASH)INVALID_HANDLE_VALUE) {
+ DWORD cbHash;
+ DWORD dwRetLen = sizeof(cbHash);
+ if (CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHash, &dwRetLen, 0))
+ {
+ NewArrayHolder<BYTE> pbHash(new (nothrow) BYTE[cbHash]);
+ if (pbHash != NULL)
+ {
+ if (CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &cbHash, 0))
+ {
+ SNLOG((W("Computed Hash Value (%u bytes):\n"), cbHash));
+ HexDump(pbHash, cbHash);
+ }
+ else
+ {
+ SNLOG((W("CryptGetHashParam() failed with %08X\n"), GetLastError()));
+ }
+ }
+ }
+ else
+ {
+ SNLOG((W("CryptGetHashParam() failed with %08X\n"), GetLastError()));
+ }
+ }
+#endif // _DEBUG
+
+ // Verify the hash against the signature.
+ //DbgCount(dwInFlags & SN_INFLAG_RUNTIME ? W("RuntimeVerify") : W("FusionVerify"));
+ if (pCounterSignature != NULL && cbCounterSignature != 0 &&
+ CryptVerifySignatureW(hHash, pCounterSignature, cbCounterSignature, hKey, NULL, 0))
+ {
+ SNLOG((W("Counter-signature verification succeeded\n")));
+ }
+ else
+ {
+ SNLOG((W("Counter-signature verification failed\n")));
+ hr = CORSEC_E_INVALID_COUNTERSIGNATURE;
+ }
+
+ return hr;
+}
+
+HRESULT ParseStringArgs(
+ CustomAttributeParser &ca, // The Custom Attribute blob.
+ CaArg* pArgs, // Array of argument descriptors.
+ ULONG cArgs) // Count of argument descriptors.
+{
+ LIMITED_METHOD_CONTRACT;
+
+ HRESULT hr = S_OK;
+
+ // For each expected arg...
+ for (ULONG ix=0; ix<cArgs; ++ix)
+ {
+ CaArg* pArg = &pArgs[ix];
+ if(pArg->type.tag != SERIALIZATION_TYPE_STRING)
+ {
+ return E_UNEXPECTED; // The blob shouldn't have anything other than strings
+ }
+ IfFailGo(ca.GetString(&pArg->val.str.pStr, &pArg->val.str.cbStr));
+ }
+
+ErrExit:
+ return hr;
+}
+
+HRESULT GetVerifiedSignatureKey(__in SN_LOAD_CTX *pLoadCtx, __out PublicKeyBlob **ppPublicKey, __out_opt DWORD *pcbPublicKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ mdAssembly tkAssembly;
+ ReleaseHolder<IMDInternalImport> pMetaDataImport;
+ IfFailRet(GetMetadataImport(pLoadCtx, &tkAssembly, &pMetaDataImport));
+
+ HRESULT attributeHr;
+ void *pAttribute;
+ ULONG cbAttribute;
+ hr = pMetaDataImport->GetCustomAttributeByName(tkAssembly, g_AssemblySignatureKeyAttribute, const_cast<const void**>(&pAttribute), &cbAttribute);
+
+ if (SUCCEEDED(hr) && hr != S_FALSE)
+ {
+ CustomAttributeParser parser(pAttribute, cbAttribute);
+ IfFailRet(parser.ValidateProlog());
+
+ CaType caTypeString;
+ caTypeString.Init(SERIALIZATION_TYPE_STRING);
+
+ CaArg args[2];
+
+ CaArg* argPublicKey = &args[0];
+ argPublicKey->Init(caTypeString);
+
+ CaArg* argCounterSignature = &args[1];
+ argCounterSignature->Init(caTypeString);
+
+ IfFailRet(ParseStringArgs(parser, args, lengthof(args)));
+
+ StrongNameBufferHolder<PublicKeyBlob> pSignaturePublicKey;
+ ULONG cbSignaturePublicKey;
+ if (argPublicKey->val.str.pStr == NULL || argPublicKey->val.str.cbStr == 0 ||
+ (!GetBytesFromHex(argPublicKey->val.str.pStr, argPublicKey->val.str.cbStr, (BYTE**)(pSignaturePublicKey.GetAddr()), &cbSignaturePublicKey)) ||
+ !StrongNameIsValidPublicKey((BYTE*)pSignaturePublicKey.GetValue(), cbSignaturePublicKey, false))
+ {
+ return CORSEC_E_INVALID_SIGNATUREKEY;
+ }
+
+ NewArrayHolder<BYTE> pCounterSignature;
+ ULONG cbCounterSignature;
+ if (argCounterSignature->val.str.pStr == NULL || argCounterSignature->val.str.cbStr == 0 ||
+ (!GetBytesFromHex(argCounterSignature->val.str.pStr, argCounterSignature->val.str.cbStr, &pCounterSignature, &cbCounterSignature)))
+ {
+ return CORSEC_E_INVALID_COUNTERSIGNATURE;
+ }
+
+ StrongNameBufferHolder<PublicKeyBlob> pIdentityPublicKey = NULL;
+ IfFailRet(FindPublicKey(pLoadCtx, NULL, 0, &pIdentityPublicKey));
+
+ IfFailRet(VerifyCounterSignature(pSignaturePublicKey, cbSignaturePublicKey, pIdentityPublicKey, pCounterSignature, cbCounterSignature));
+
+ *ppPublicKey = pSignaturePublicKey.Extract();
+ if (pcbPublicKey != NULL)
+ *pcbPublicKey = cbSignaturePublicKey;
+ }
+ else
+ {
+ *ppPublicKey = NULL;
+ if (pcbPublicKey != NULL)
+ *pcbPublicKey = 0;
+ }
+
+ return hr;
+}
+
+// Checks revocation list against the assembly's public keys.
+// If the identity key has been revoked, then the signature key must be non-null and
+// must be in the replacement keys list to be allowed.
+bool AreKeysAllowedByRevocationList(BYTE* pbAssemblyIdentityKey, DWORD cbAssemblyIdentityKey, BYTE* pbAssemblySignatureKey, DWORD cbAssemblySignatureKey)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ bool fRevoked = false;
+
+ SN_REVOCATION_REC *pRevocationRec = g_pRevocationRecords;
+ while (pRevocationRec)
+ {
+ if (pRevocationRec->m_cbRevokedKey == cbAssemblyIdentityKey &&
+ memcmp(pRevocationRec->m_pbRevokedKey, pbAssemblyIdentityKey, cbAssemblyIdentityKey) == 0)
+ {
+ fRevoked = true; // Identity key can't be trusted.
+
+ if (pbAssemblySignatureKey != NULL)
+ {
+ SN_REPLACEMENT_KEY_REC *pReplacementKeyRec = pRevocationRec->m_pReplacementKeys;
+
+ while (pReplacementKeyRec)
+ {
+ if (pReplacementKeyRec->m_cbReplacementKey == cbAssemblySignatureKey &&
+ memcmp(pReplacementKeyRec->m_pbReplacementKey, pbAssemblySignatureKey, cbAssemblySignatureKey) == 0)
+ {
+ // Signature key was allowed as a replacement for the revoked identity key.
+ return true;
+ }
+
+ pReplacementKeyRec = pReplacementKeyRec->m_pNext;
+ }
+ }
+ // We didn't find the signature key in the list of allowed replacement keys for this record.
+ // However, we don't return here, because another record might have the same identity key
+ // and allow the signature key as a replacement.
+ }
+
+ pRevocationRec = pRevocationRec->m_pNext;
+ }
+
+ return !fRevoked;
+}
+
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+// The common code used to verify a signature (taking into account whether skip
+// verification is enabled for the given assembly).
+HRESULT VerifySignature(__in SN_LOAD_CTX *pLoadCtx, DWORD dwInFlags, PublicKeyBlob *pRealEcmaPublicKey,__out_opt DWORD *pdwOutFlags)
+{
+ if (pdwOutFlags)
+ *pdwOutFlags = 0;
+
+ // Read the public key used to sign the assembly from the assembly metadata.
+ // Also get the assembly name, we might need this if we fail the
+ // verification and need to look up a verification disablement entry.
+ WCHAR wszSimpleAssemblyName[MAX_PATH + 1];
+ SString strFullyQualifiedAssemblyName;
+ BOOL bSuccess = FALSE;
+#if STRONGNAME_IN_VM
+ BOOL bAssemblyNameFormed = FALSE;
+ BOOL bVerificationBegun = FALSE;
+#endif
+
+ HandleKeyHolder hKey(NULL);
+ HandleHashHolder hHash(NULL);
+ HandleStrongNameCspHolder hProv(NULL);
+
+ StrongNameBufferHolder<PublicKeyBlob> pAssemblyIdentityKey;
+ DWORD cbAssemblyIdentityKey;
+ HRESULT hr = FindPublicKey(pLoadCtx,
+ wszSimpleAssemblyName,
+ sizeof(wszSimpleAssemblyName) / sizeof(WCHAR),
+ &pAssemblyIdentityKey,
+ &cbAssemblyIdentityKey);
+ if (FAILED(hr))
+ return hr;
+
+ BOOL isEcmaKey = SN_IS_NEUTRAL_KEY(pAssemblyIdentityKey);
+ // If we're handed the ECMA key, we translate it to the real key at this point.
+ // Note: gcc gets confused with the complexity of StrongNameBufferHolder<> and
+ // won't auto-convert pAssemblyIdentityKey to type PublicKeyBlob*, so cast it explicitly.
+ PublicKeyBlob *pRealPublicKey = isEcmaKey ? pRealEcmaPublicKey : static_cast<PublicKeyBlob*>(pAssemblyIdentityKey);
+
+// An assembly can specify a signature public key in an attribute.
+// If one is present, we verify the signature using that public key.
+#ifdef FEATURE_STRONGNAME_MIGRATION
+ StrongNameBufferHolder<PublicKeyBlob> pAssemblySignaturePublicKey;
+ DWORD cbAssemblySignaturePublicKey;
+ IfFailRet(GetVerifiedSignatureKey(pLoadCtx, &pAssemblySignaturePublicKey, &cbAssemblySignaturePublicKey));
+ if(hr != S_FALSE) // Attribute was found
+ {
+ pRealPublicKey = pAssemblySignaturePublicKey;
+ }
+
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+ DWORD dwSpecialKeys = GetSpecialKeyFlags(pRealPublicKey);
+
+ // If this isn't the first time we've been called for this assembly and we
+ // know it was fully signed and we're confident it couldn't have been
+ // tampered with in the meantime, we can just skip the verification.
+ if (!(dwInFlags & SN_INFLAG_FORCE_VER) &&
+ !(dwInFlags & SN_INFLAG_INSTALL) &&
+ (pLoadCtx->m_pCorHeader->Flags & VAL32(COMIMAGE_FLAGS_STRONGNAMESIGNED)) &&
+ ((dwInFlags & SN_INFLAG_ADMIN_ACCESS) || g_fCacheVerify))
+ {
+ SNLOG((W("Skipping verification due to cached result\n")));
+ DbgCount(dwInFlags & SN_INFLAG_RUNTIME ? W("RuntimeSkipCache") : W("FusionSkipCache"));
+ return S_OK;
+ }
+
+#ifdef FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+ // If we're not forcing verification, let's see if there's a skip
+ // verification entry for this assembly. If there is we can skip all the
+ // hard work and just lie about the strong name now. The exception is if the
+ // assembly is marked as fully signed, in which case we have to force a
+ // verification to see if they're telling the truth.
+ StrongNameBufferHolder<PublicKeyBlob> pTestKey = NULL;
+ SN_VER_REC *pVerRec = GetVerificationRecord(wszSimpleAssemblyName, pAssemblyIdentityKey);
+ if (!(dwInFlags & SN_INFLAG_FORCE_VER) && !(pLoadCtx->m_pCorHeader->Flags & VAL32(COMIMAGE_FLAGS_STRONGNAMESIGNED)))
+ {
+ if (pVerRec != NULL)
+ {
+ if (pVerRec->m_wszTestPublicKey)
+ {
+ // substitute the public key with the test public key.
+ pTestKey = GetPublicKeyFromHex(pVerRec->m_wszTestPublicKey);
+ if (pTestKey != NULL)
+ {
+
+ SNLOG((W("Using test public key for verification due to registry entry\n")));
+ DbgCount(dwInFlags & SN_INFLAG_RUNTIME ? W("RuntimeSkipDelay") : W("FusionSkipDelay"));
+
+ // If the assembly was not ECMA signed, then we need to update the key that it will be
+ // verified with as well.
+ if (!isEcmaKey)
+ {
+ // When test signing, there's no way to specify a hash algorithm.
+ // So instead of defaulting to SHA1, we pick the algorithm the assembly
+ // would've been signed with, if the test key wasn't present.
+ // Thus we use the same algorithm when verifying the signature.
+ SET_UNALIGNED_VAL32(&pTestKey->HashAlgID, GET_UNALIGNED_VAL32(&pRealPublicKey->HashAlgID));
+
+ pRealPublicKey = pTestKey;
+ }
+ }
+ }
+ else
+ {
+ SNLOG((W("Skipping verification due to registry entry\n")));
+ DbgCount(dwInFlags & SN_INFLAG_RUNTIME ? W("RuntimeSkipDelay") : W("FusionSkipDelay"));
+ if (pdwOutFlags)
+ {
+ *pdwOutFlags |= dwSpecialKeys;
+ }
+ return S_OK;
+ }
+ }
+ }
+#endif // FEATURE_STRONGNAME_DELAY_SIGNING_ALLOWED
+
+#ifdef FEATURE_STRONGNAME_MIGRATION
+ if(!isEcmaKey) // We should never revoke the ecma key, as it is tied strongly to the runtime
+ {
+ if(!AreKeysAllowedByRevocationList((BYTE*)pAssemblyIdentityKey.GetValue(), cbAssemblyIdentityKey, (BYTE*)pAssemblySignaturePublicKey.GetValue(), cbAssemblySignaturePublicKey))
+ {
+ if(pAssemblySignaturePublicKey == NULL)
+ {
+ SNLOG((W("Verification failed. Assembly public key has been revoked\n")));
+ }
+ else
+ {
+ SNLOG((W("Verification failed. Assembly identity key has been revoked, an the assembly signature key isn't in the replacement key list\n")));
+ }
+
+ hr = CORSEC_E_INVALID_STRONGNAME;
+ goto Error;
+ }
+ }
+
+#endif // FEATURE_STRONGNAME_MIGRATION
+
+#ifdef FEATURE_CORECLR
+ // TritonTODO: check with security team on this
+ if (pLoadCtx->m_pbSignature == NULL)
+ {
+ hr = CORSEC_E_MISSING_STRONGNAME;
+ goto Error;
+ }
+#endif //FEATURE_CORECLR
+
+#if STRONGNAME_IN_VM
+ bVerificationBegun = TRUE;
+ // SN verification start event
+ if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_SECURITY_KEYWORD))
+ {
+ // form the fully qualified assembly name using the load context
+ bAssemblyNameFormed = FormFullyQualifiedAssemblyName(pLoadCtx, strFullyQualifiedAssemblyName);
+ if(bAssemblyNameFormed)
+ {
+ ETW::SecurityLog::StrongNameVerificationStart(dwInFlags,(LPWSTR)strFullyQualifiedAssemblyName.GetUnicode());
+ }
+ }
+#endif // STRONGNAME_IN_VM
+
+ ALG_ID uHashAlgId = GET_UNALIGNED_VAL32(&pRealPublicKey->HashAlgID);
+ ALG_ID uSignAlgId = GET_UNALIGNED_VAL32(&pRealPublicKey->SigAlgID);
+
+ // Default hashing and signing algorithm IDs if necessary.
+ if (uHashAlgId == 0)
+ uHashAlgId = CALG_SHA1;
+ if (uSignAlgId == 0)
+ uSignAlgId = CALG_RSA_SIGN;
+
+ // Find a CSP supporting the required algorithms.
+ hProv = LocateCSP(NULL, SN_IGNORE_CONTAINER, uHashAlgId, uSignAlgId);
+ if (!hProv)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to acquire a CSP: %08x"), hr));
+ goto Error;
+ }
+
+ BYTE *pbRealPublicKey;
+ pbRealPublicKey = pRealPublicKey->PublicKey;
+ DWORD cbRealPublicKey;
+ cbRealPublicKey = GET_UNALIGNED_VAL32(&pRealPublicKey->cbPublicKey);
+
+ if (!CryptImportKey(hProv, pbRealPublicKey, cbRealPublicKey, 0, 0, &hKey))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to import key: %08x"), hr));
+ goto Error;
+ }
+
+ // Create a hash object.
+
+ if (!CryptCreateHash(hProv, uHashAlgId, 0, 0, &hHash))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to create hash: %08x"), hr));
+ goto Error;
+ }
+
+ // Compute a hash over the image.
+ if (!ComputeHash(pLoadCtx, hHash, CalcHash, NULL))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ SNLOG((W("Failed to compute hash: %08x"), hr));
+ goto Error;
+ }
+
+ // Verify the hash against the signature.
+ DbgCount(dwInFlags & SN_INFLAG_RUNTIME ? W("RuntimeVerify") : W("FusionVerify"));
+ if (pLoadCtx->m_pbSignature != NULL && pLoadCtx->m_cbSignature != 0 &&
+ CryptVerifySignatureW(hHash, pLoadCtx->m_pbSignature, pLoadCtx->m_cbSignature, hKey, NULL, 0))
+ {
+ SNLOG((W("Verification succeeded (for real)\n")));
+ if (pdwOutFlags)
+ {
+ *pdwOutFlags |= dwSpecialKeys | SN_OUTFLAG_WAS_VERIFIED;
+ }
+ bSuccess = TRUE;
+ }
+ else
+ {
+ SNLOG((W("Verification failed\n")));
+ hr = CORSEC_E_INVALID_STRONGNAME;
+ }
+
+Error:
+
+#if STRONGNAME_IN_VM
+ // SN verification end event
+ if(bVerificationBegun &&
+ ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, TRACE_LEVEL_VERBOSE, CLR_SECURITY_KEYWORD))
+ {
+ // form the fully qualified assembly name using the load context if it has not yet been formed
+ if(!bAssemblyNameFormed)
+ {
+ strFullyQualifiedAssemblyName.Clear();
+ bAssemblyNameFormed = FormFullyQualifiedAssemblyName(pLoadCtx, strFullyQualifiedAssemblyName);
+ }
+ if(bAssemblyNameFormed)
+ {
+ ETW::SecurityLog::StrongNameVerificationStop(dwInFlags,(ULONG)hr, (LPWSTR)strFullyQualifiedAssemblyName.GetUnicode());
+ }
+ }
+#endif // STRONGNAME_IN_VM
+
+ if (bSuccess)
+ return S_OK;
+ else
+ return hr;
+}
+
+// Compute a hash over the elements of an assembly manifest file that should
+// remain static (skip checksum, Authenticode signatures and strong name
+// signature blob).
+// This function can also be used to get the blob of bytes that would be
+// hashed without actually hashing.
+BOOLEAN ComputeHash(SN_LOAD_CTX *pLoadCtx, HCRYPTHASH hHash, HashFunc func, void* cookie)
+{
+ union {
+ IMAGE_NT_HEADERS32 m_32;
+ IMAGE_NT_HEADERS64 m_64;
+ } sHeaders;
+ IMAGE_SECTION_HEADER *pSections;
+ ULONG i;
+ BYTE *pbSig = pLoadCtx->m_pbSignature;
+ DWORD cbSig = pLoadCtx->m_cbSignature;
+
+#define LIMIT_CHECK(_start, _length, _fileStart, _fileLength) \
+ do { if (((_start) < (_fileStart)) || \
+ (((_start)+(_length)) < (_start)) || \
+ (((_start)+(_length)) < (_fileStart)) || \
+ (((_start)+(_length)) > ((_fileStart)+(_fileLength))) ) \
+ { SetLastError(CORSEC_E_INVALID_IMAGE_FORMAT); return FALSE; } } while (false)
+
+#define FILE_LIMIT_CHECK(_start, _length) LIMIT_CHECK(_start, _length, pLoadCtx->m_pbBase, pLoadCtx->m_dwLength)
+
+#define SN_HASH(_start, _length) do { if (!func(hHash, (_start), (_length), 0, cookie)) return FALSE; } while (false)
+
+#define SN_CHECK_AND_HASH(_start, _length) do { FILE_LIMIT_CHECK(_start, _length); SN_HASH(_start, _length); } while (false)
+
+ // Make sure the file size doesn't wrap around.
+ if (pLoadCtx->m_pbBase + pLoadCtx->m_dwLength <= pLoadCtx->m_pbBase)
+ {
+ SetLastError(CORSEC_E_INVALID_IMAGE_FORMAT);
+ return FALSE;
+ }
+
+ // Make sure the signature is completely contained within the file.
+ FILE_LIMIT_CHECK(pbSig, cbSig);
+
+ // Hash the DOS header if it exists.
+ if ((BYTE*)pLoadCtx->m_pNtHeaders != pLoadCtx->m_pbBase)
+ SN_CHECK_AND_HASH(pLoadCtx->m_pbBase, (DWORD)((BYTE*)pLoadCtx->m_pNtHeaders - pLoadCtx->m_pbBase));
+
+ // Add image headers minus the checksum and security data directory.
+ if (pLoadCtx->m_pNtHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)) {
+ sHeaders.m_32 = *((IMAGE_NT_HEADERS32*)pLoadCtx->m_pNtHeaders);
+ sHeaders.m_32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = 0;
+ sHeaders.m_32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = 0;
+ sHeaders.m_32.OptionalHeader.CheckSum = 0;
+ SN_HASH((BYTE*)&sHeaders.m_32, sizeof(sHeaders.m_32));
+ } else if (pLoadCtx->m_pNtHeaders->OptionalHeader.Magic == VAL16(IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
+ sHeaders.m_64 = *((IMAGE_NT_HEADERS64*)pLoadCtx->m_pNtHeaders);
+ sHeaders.m_64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = 0;
+ sHeaders.m_64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = 0;
+ sHeaders.m_64.OptionalHeader.CheckSum = 0;
+ SN_HASH((BYTE*)&sHeaders.m_64, sizeof(sHeaders.m_64));
+ } else {
+ SetLastError(CORSEC_E_INVALID_IMAGE_FORMAT);
+ return FALSE;
+ }
+
+ // Then the section headers.
+ pSections = IMAGE_FIRST_SECTION(pLoadCtx->m_pNtHeaders);
+ SN_CHECK_AND_HASH((BYTE*)pSections, VAL16(pLoadCtx->m_pNtHeaders->FileHeader.NumberOfSections) * sizeof(IMAGE_SECTION_HEADER));
+
+ // Finally, add data from each section.
+ for (i = 0; i < VAL16(pLoadCtx->m_pNtHeaders->FileHeader.NumberOfSections); i++) {
+ BYTE *pbData = pLoadCtx->m_pbBase + VAL32(pSections[i].PointerToRawData);
+ DWORD cbData = VAL32(pSections[i].SizeOfRawData);
+
+ // We need to exclude the strong name signature blob from the hash. The
+ // blob could intersect the section in a number of ways.
+
+ if ((pbSig + cbSig) <= pbData || pbSig >= (pbData + cbData))
+ // No intersection at all. Hash all data.
+ SN_CHECK_AND_HASH(pbData, cbData);
+ else if (pbSig == pbData && cbSig == cbData)
+ // Signature consumes entire block. Hash no data.
+ ;
+ else if (pbSig == pbData)
+ // Signature at start. Hash end.
+ SN_CHECK_AND_HASH(pbData + cbSig, cbData - cbSig);
+ else if ((pbSig + cbSig) == (pbData + cbData))
+ // Signature at end. Hash start.
+ SN_CHECK_AND_HASH(pbData, cbData - cbSig);
+ else {
+ // Signature in the middle. Hash head and tail.
+ SN_CHECK_AND_HASH(pbData, (DWORD)(pbSig - pbData));
+ SN_CHECK_AND_HASH(pbSig + cbSig, cbData - (DWORD)(pbSig + cbSig - pbData));
+ }
+ }
+
+#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
+ if (hHash != (HCRYPTHASH)INVALID_HANDLE_VALUE) {
+ DWORD cbHash;
+ DWORD dwRetLen = sizeof(cbHash);
+ if (CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHash, &dwRetLen, 0))
+ {
+ NewArrayHolder<BYTE> pbHash(new (nothrow) BYTE[cbHash]);
+ if (pbHash != NULL)
+ {
+ if (CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &cbHash, 0))
+ {
+ SNLOG((W("Computed Hash Value (%u bytes):\n"), cbHash));
+ HexDump(pbHash, cbHash);
+ }
+ else
+ {
+ SNLOG((W("CryptGetHashParam() failed with %08X\n"), GetLastError()));
+ }
+ }
+ }
+ else
+ {
+ SNLOG((W("CryptGetHashParam() failed with %08X\n"), GetLastError()));
+ }
+ }
+#endif // _DEBUG
+
+ return TRUE;
+
+#undef SN_CHECK_AND_HASH
+#undef SN_HASH
+#undef FILE_LIMIT_CHECK
+#undef LIMIT_CHECK
+}
+
+
+SNAPI_(DWORD) GetHashFromAssemblyFile(LPCSTR szFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash) // [OUT] length of hash byte array
+{
+ BOOL retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+ // Convert filename to wide characters and call the W version of this
+ // function.
+
+ MAKE_WIDEPTR_FROMANSI(wszFilePath, szFilePath);
+ retVal = GetHashFromAssemblyFileW(wszFilePath, piHashAlg, pbHash, cchHash, pchHash);
+ END_ENTRYPOINT_NOTHROW;
+ return retVal;
+}
+
+SNAPI_(DWORD) GetHashFromAssemblyFileW(LPCWSTR wszFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash) // [OUT] length of hash byte array
+{
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ SN_LOAD_CTX sLoadCtx;
+ BYTE *pbMetaData = NULL;
+ DWORD cbMetaData;
+
+ sLoadCtx.m_fReadOnly = TRUE;
+ if (!LoadAssembly(&sLoadCtx, wszFilePath, 0, FALSE))
+ IfFailGo(HRESULT_FROM_GetLastError());
+
+ if (sLoadCtx.m_pedecoder->CheckCorHeader())
+ {
+ pbMetaData = (BYTE *)sLoadCtx.m_pedecoder->GetMetadata();
+ }
+ if (pbMetaData == NULL) {
+ UnloadAssembly(&sLoadCtx);
+ IfFailGo(E_INVALIDARG);
+ }
+ cbMetaData = VAL32(sLoadCtx.m_pCorHeader->MetaData.Size);
+
+ hr = GetHashFromBlob(pbMetaData, cbMetaData, piHashAlg, pbHash, cchHash, pchHash);
+
+ UnloadAssembly(&sLoadCtx);
+ErrExit:
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+SNAPI_(DWORD) GetHashFromFile(LPCSTR szFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash) // [OUT] length of hash byte array
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HANDLE hFile = CreateFileA(szFilePath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ }
+ else
+ {
+ hr = GetHashFromHandle(hFile, piHashAlg, pbHash, cchHash, pchHash);
+ CloseHandle(hFile);
+ }
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+SNAPI_(DWORD) GetHashFromFileW(LPCWSTR wszFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash) // [OUT] length of hash byte array
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HANDLE hFile = WszCreateFile(wszFilePath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ IfFailGo(HRESULT_FROM_GetLastError());
+
+ hr = GetHashFromHandle(hFile, piHashAlg, pbHash, cchHash, pchHash);
+ CloseHandle(hFile);
+ErrExit:
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+SNAPI_(DWORD) GetHashFromHandle(HANDLE hFile, // [IN] handle of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash) // [OUT] length of hash byte array
+{
+ HRESULT hr;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ PBYTE pbBuffer = NULL;
+ DWORD dwFileLen = SafeGetFileSize(hFile, 0);
+ if (dwFileLen == 0xffffffff)
+ IfFailGo(HRESULT_FROM_GetLastError());
+
+ if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF)
+ IfFailGo(HRESULT_FROM_GetLastError());
+
+ DWORD dwResultLen;
+ pbBuffer = new (nothrow) BYTE[dwFileLen];
+ IfNullGo(pbBuffer);
+
+ if (ReadFile(hFile, pbBuffer, dwFileLen, &dwResultLen, NULL))
+ hr = GetHashFromBlob(pbBuffer, dwResultLen, piHashAlg, pbHash, cchHash, pchHash);
+ else
+ hr = HRESULT_FROM_GetLastError();
+
+ delete[] pbBuffer;
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+SNAPI_(DWORD) GetHashFromBlob(BYTE *pbBlob, // [IN] pointer to memory block to hash
+ DWORD cchBlob, // [IN] length of blob
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash) // [OUT] length of hash byte array
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ HandleStrongNameCspHolder hProv(NULL);
+ CapiHashHolder hHash(NULL);
+
+ if (!piHashAlg || !pbHash || !pchHash)
+ IfFailGo(E_INVALIDARG);
+
+ if (!(*piHashAlg))
+ *piHashAlg = CALG_SHA1;
+
+ *pchHash = cchHash;
+
+ hProv = LocateCSP(NULL, SN_IGNORE_CONTAINER, *piHashAlg);
+
+ if (!hProv ||
+ (!CryptCreateHash(hProv, *piHashAlg, 0, 0, &hHash)) ||
+ (!CryptHashData(hHash, pbBlob, cchBlob, 0)) ||
+ (!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, pchHash, 0)))
+ hr = HRESULT_FROM_GetLastError();
+
+ErrExit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+#else // !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+
+#define InitStrongName() S_OK
+
+#endif // !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+
+
+// Free buffer allocated by routines below.
+SNAPI_(VOID) StrongNameFreeBuffer(BYTE *pbMemory) // [in] address of memory to free
+{
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+ SNLOG((W("StrongNameFreeBuffer(%08X)\n"), pbMemory));
+
+ if (pbMemory != (BYTE*)SN_THE_KEY() && pbMemory != g_rbNeutralPublicKey)
+ delete [] pbMemory;
+ END_ENTRYPOINT_VOIDRET;
+
+}
+
+#ifndef DACCESS_COMPILE
+// Retrieve per-thread context, lazily allocating it if necessary.
+SN_THREAD_CTX *GetThreadContext()
+{
+ SN_THREAD_CTX *pThreadCtx = (SN_THREAD_CTX*)ClrFlsGetValue(TlsIdx_StrongName);
+ if (pThreadCtx == NULL) {
+ pThreadCtx = new (nothrow) SN_THREAD_CTX;
+ if (pThreadCtx == NULL)
+ return NULL;
+ pThreadCtx->m_dwLastError = S_OK;
+#if !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+ for (ULONG i = 0; i < CachedCspCount; i++)
+ {
+ pThreadCtx->m_hProv[i] = NULL;
+ }
+#endif // !FEATURE_CORECLR || CROSSGEN_COMPILE
+
+ EX_TRY {
+ ClrFlsSetValue(TlsIdx_StrongName, pThreadCtx);
+ }
+ EX_CATCH {
+ delete pThreadCtx;
+ pThreadCtx = NULL;
+ }
+ EX_END_CATCH (SwallowAllExceptions);
+ }
+ return pThreadCtx;
+}
+
+// Set the per-thread last error code.
+VOID SetStrongNameErrorInfo(DWORD dwStatus)
+{
+ SN_THREAD_CTX *pThreadCtx = GetThreadContext();
+ if (pThreadCtx == NULL)
+ // We'll return E_OUTOFMEMORY when we attempt to get the error.
+ return;
+ pThreadCtx->m_dwLastError = dwStatus;
+}
+
+#endif // !DACCESS_COMPILE
+
+// Return last error.
+SNAPI_(DWORD) StrongNameErrorInfo(VOID)
+{
+ HRESULT hr = E_FAIL;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+#ifndef DACCESS_COMPILE
+ SN_THREAD_CTX *pThreadCtx = GetThreadContext();
+ if (pThreadCtx == NULL)
+ hr = E_OUTOFMEMORY;
+ else
+ hr = pThreadCtx->m_dwLastError;
+#else
+ hr = E_FAIL;
+#endif // #ifndef DACCESS_COMPILE
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+
+// Create a strong name token from a public key blob.
+SNAPI StrongNameTokenFromPublicKey(BYTE *pbPublicKeyBlob, // [in] public key blob
+ ULONG cbPublicKeyBlob,
+ BYTE **ppbStrongNameToken, // [out] strong name token
+ ULONG *pcbStrongNameToken)
+{
+ BOOLEAN retVal = FALSE;
+
+ BEGIN_ENTRYPOINT_VOIDRET;
+
+#ifndef DACCESS_COMPILE
+
+#ifndef FEATURE_CORECLR
+ HCRYPTPROV hProv = NULL;
+ HCRYPTHASH hHash = NULL;
+ HCRYPTKEY hKey = NULL;
+ DWORD dwHashLen;
+ DWORD dwRetLen;
+ NewArrayHolder<BYTE> pHash(NULL);
+#else // !FEATURE_CORECLR
+ SHA1Hash sha1;
+ BYTE *pHash = NULL;
+#endif // !FEATURE_CORECLR
+
+ DWORD i;
+ DWORD cbKeyBlob;
+ PublicKeyBlob *pPublicKey = NULL;
+ DWORD dwHashLenMinusTokenSize = 0;
+
+ SNLOG((W("StrongNameTokenFromPublicKey(%08X, %08X, %08X, %08X)\n"), pbPublicKeyBlob, cbPublicKeyBlob, ppbStrongNameToken, pcbStrongNameToken));
+
+#if STRONGNAME_IN_VM
+ FireEtwSecurityCatchCall_V1(GetClrInstanceId());
+#endif // STRONGNAME_IN_VM
+
+ SN_COMMON_PROLOG();
+
+ if (pbPublicKeyBlob == NULL)
+ SN_ERROR(E_POINTER);
+ if (!StrongNameIsValidPublicKey(pbPublicKeyBlob, cbPublicKeyBlob, false))
+ SN_ERROR(CORSEC_E_INVALID_PUBLICKEY);
+ if (ppbStrongNameToken == NULL)
+ SN_ERROR(E_POINTER);
+ if (pcbStrongNameToken == NULL)
+ SN_ERROR(E_POINTER);
+
+ // Allocate a buffer for the output token.
+ *ppbStrongNameToken = new (nothrow) BYTE[SN_SIZEOF_TOKEN];
+ if (*ppbStrongNameToken == NULL) {
+ SetStrongNameErrorInfo(E_OUTOFMEMORY);
+ goto Exit;
+ }
+ *pcbStrongNameToken = SN_SIZEOF_TOKEN;
+
+ // We cache a couple of common cases.
+ if (SN_IS_NEUTRAL_KEY(pbPublicKeyBlob)) {
+ memcpy_s(*ppbStrongNameToken, *pcbStrongNameToken, g_rbNeutralPublicKeyToken, SN_SIZEOF_TOKEN);
+ retVal = TRUE;
+ goto Exit;
+ }
+ if (cbPublicKeyBlob == SN_SIZEOF_THE_KEY() &&
+ memcmp(pbPublicKeyBlob, SN_THE_KEY(), cbPublicKeyBlob) == 0) {
+ memcpy_s(*ppbStrongNameToken, *pcbStrongNameToken, SN_THE_KEYTOKEN(), SN_SIZEOF_TOKEN);
+ retVal = TRUE;
+ goto Exit;
+ }
+#ifdef FEATURE_CORECLR
+ if (SN_IS_THE_SILVERLIGHT_PLATFORM_KEY(pbPublicKeyBlob))
+ {
+ memcpy_s(*ppbStrongNameToken, *pcbStrongNameToken, SN_THE_SILVERLIGHT_PLATFORM_KEYTOKEN(), SN_SIZEOF_TOKEN);
+ retVal = TRUE;
+ goto Exit;
+ }
+
+ if (SN_IS_THE_SILVERLIGHT_KEY(pbPublicKeyBlob))
+ {
+ memcpy_s(*ppbStrongNameToken, *pcbStrongNameToken, SN_THE_SILVERLIGHT_KEYTOKEN(), SN_SIZEOF_TOKEN);
+ retVal = TRUE;
+ goto Exit;
+ }
+
+#ifdef FEATURE_WINDOWSPHONE
+
+ if (SN_IS_THE_MICROSOFT_PHONE_KEY(pbPublicKeyBlob))
+ {
+ memcpy_s(*ppbStrongNameToken, *pcbStrongNameToken, SN_THE_MICROSOFT_PHONE_KEYTOKEN(), SN_SIZEOF_TOKEN);
+ retVal = TRUE;
+ goto Exit;
+ }
+
+ if (SN_IS_THE_MICROSOFT_XNA_KEY(pbPublicKeyBlob))
+ {
+ memcpy_s(*ppbStrongNameToken, *pcbStrongNameToken, SN_THE_MICROSOFT_XNA_KEYTOKEN(), SN_SIZEOF_TOKEN);
+ retVal = TRUE;
+ goto Exit;
+ }
+
+#endif //FEATURE_WINDOWSPHONE
+#endif //FEATURE_CORECLR
+
+ // To compute the correct public key token, we need to make sure the public key blob
+ // was not padded with extra bytes that CAPI CryptImportKey would've ignored.
+ // Without this round trip, we would blindly compute the hash over the padded bytes
+ // which could make finding a public key token collision a significantly easier task
+ // since an attacker wouldn't need to work hard on generating valid key pairs before hashing.
+ if (cbPublicKeyBlob <= sizeof(PublicKeyBlob)) {
+ SetLastError(CORSEC_E_INVALID_PUBLICKEY);
+ goto Error;
+ }
+
+ // Check that the blob type is PUBLICKEYBLOB.
+ pPublicKey = (PublicKeyBlob*) pbPublicKeyBlob;
+
+ if (pPublicKey->PublicKey + GET_UNALIGNED_VAL32(&pPublicKey->cbPublicKey) < pPublicKey->PublicKey) {
+ SetLastError(CORSEC_E_INVALID_PUBLICKEY);
+ goto Error;
+ }
+
+ if (cbPublicKeyBlob < SN_SIZEOF_KEY(pPublicKey)) {
+ SetLastError(CORSEC_E_INVALID_PUBLICKEY);
+ goto Error;
+ }
+
+ if (*(BYTE*) pPublicKey->PublicKey /* PUBLICKEYSTRUC->bType */ != PUBLICKEYBLOB) {
+ SetLastError(CORSEC_E_INVALID_PUBLICKEY);
+ goto Error;
+ }
+
+#ifndef FEATURE_CORECLR
+
+ // Look for a CSP to hash the public key.
+ hProv = LocateCSP(NULL, SN_HASH_SHA1_ONLY);
+ if (!hProv)
+ goto Error;
+
+ if (!CryptImportKey(hProv,
+ pPublicKey->PublicKey,
+ GET_UNALIGNED_VAL32(&pPublicKey->cbPublicKey),
+ 0,
+ 0,
+ &hKey))
+ goto Error;
+
+ cbKeyBlob = sizeof(DWORD);
+ if (!CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, NULL, &cbKeyBlob))
+ goto Error;
+
+ if ((offsetof(PublicKeyBlob, PublicKey) + cbKeyBlob) != cbPublicKeyBlob) {
+ SetLastError(CORSEC_E_INVALID_PUBLICKEY);
+ goto Error;
+ }
+
+ // Create a hash object.
+ if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
+ goto Error;
+
+ // Compute a hash over the public key.
+ if (!CryptHashData(hHash, pbPublicKeyBlob, cbPublicKeyBlob, 0))
+ goto Error;
+
+ // Get the length of the hash.
+ dwRetLen = sizeof(dwHashLen);
+ if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&dwHashLen, &dwRetLen, 0))
+ goto Error;
+
+ // Allocate a temporary block to hold the hash.
+ pHash = new (nothrow) BYTE[dwHashLen];
+ if (pHash == NULL)
+ {
+ SetLastError(E_OUTOFMEMORY);
+ goto Error;
+ }
+
+ // Read the hash value.
+ if (!CryptGetHashParam(hHash, HP_HASHVAL, pHash, &dwHashLen, 0))
+ goto Error;
+
+ // We no longer need the hash object or the provider.
+ CryptDestroyHash(hHash);
+ CryptDestroyKey(hKey);
+ FreeCSP(hProv);
+
+ // Take the last few bytes of the hash value for our token. (These are the
+ // low order bytes from a network byte order point of view). Reverse the
+ // order of these bytes in the output buffer to get host byte order.
+ _ASSERTE(dwHashLen >= SN_SIZEOF_TOKEN);
+ if (!ClrSafeInt<DWORD>::subtraction(dwHashLen, SN_SIZEOF_TOKEN, dwHashLenMinusTokenSize))
+ {
+ SetLastError(COR_E_OVERFLOW);
+ goto Error;
+ }
+
+#else // !FEATURE_CORECLR
+
+ // Compute a hash over the public key.
+ sha1.AddData(pbPublicKeyBlob, cbPublicKeyBlob);
+ pHash = sha1.GetHash();
+ static_assert(SHA1_HASH_SIZE >= SN_SIZEOF_TOKEN, "SN_SIZEOF_TOKEN must be smaller or equal to the SHA1_HASH_SIZE");
+ dwHashLenMinusTokenSize = SHA1_HASH_SIZE - SN_SIZEOF_TOKEN;
+
+#endif // !FEATURE_CORECLR
+
+ // Take the last few bytes of the hash value for our token. (These are the
+ // low order bytes from a network byte order point of view). Reverse the
+ // order of these bytes in the output buffer to get host byte order.
+ for (i = 0; i < SN_SIZEOF_TOKEN; i++)
+ (*ppbStrongNameToken)[SN_SIZEOF_TOKEN - (i + 1)] = pHash[i + dwHashLenMinusTokenSize];
+
+ retVal = TRUE;
+ goto Exit;
+
+ Error:
+ SetStrongNameErrorInfo(HRESULT_FROM_GetLastError());
+#ifndef FEATURE_CORECLR
+ if (hHash)
+ CryptDestroyHash(hHash);
+ if (hKey)
+ CryptDestroyKey(hKey);
+ if (hProv)
+ FreeCSP(hProv);
+#endif // !FEATURE_CORECLR
+
+ if (*ppbStrongNameToken) {
+ delete [] *ppbStrongNameToken;
+ *ppbStrongNameToken = NULL;
+ }
+Exit:
+#else
+ DacNotImpl();
+#endif // #ifndef DACCESS_COMPILE
+ END_ENTRYPOINT_VOIDRET;
+
+ return retVal;
+
+}
diff --git a/src/strongname/api/strongnamecoreclr.cpp b/src/strongname/api/strongnamecoreclr.cpp
new file mode 100644
index 0000000000..1430b42131
--- /dev/null
+++ b/src/strongname/api/strongnamecoreclr.cpp
@@ -0,0 +1,99 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+//
+// Several strong name tools are in a special scenario because they build in the CoreCLR build process, but
+// are expected to run against the desktop VM. Because of this, we need to setup the callback structure that
+// Utilcode asks for to point to callbacks that shim to the desktop. These methods provide that shimming functionality.
+//
+
+#include "common.h"
+
+#if defined(FEATURE_CORECLR)
+
+CoreClrCallbacks *GetCoreClrCallbacks();
+
+//
+// Get a pointer to an API out of the shim
+//
+// Arguments:
+// szApiName - name of the API to get a pointer to
+//
+//
+
+template<typename FunctionPointer>
+FunctionPointer ApiShim(LPCSTR szApiName)
+{
+ static FunctionPointer pfnApi = NULL;
+
+ if (pfnApi == NULL)
+ {
+ CoreClrCallbacks *pCallbacks = GetCoreClrCallbacks();
+ pfnApi = reinterpret_cast<FunctionPointer>(GetProcAddress(pCallbacks->m_hmodCoreCLR, szApiName));
+ _ASSERTE(pfnApi != NULL);
+ }
+
+ return pfnApi;
+}
+
+//
+// Shim APIs, passing off into the desktop VM
+//
+
+IExecutionEngine * __stdcall SnIEE()
+{
+ typedef IExecutionEngine * ( __stdcall *IEEFn_t)();
+ return ApiShim<IEEFn_t>("IEE")();
+}
+
+STDAPI SnGetCorSystemDirectory(LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwLength)
+{
+ typedef HRESULT (__stdcall *GetCorSystemDirectoryFn_t)(LPWSTR, DWORD, DWORD *);
+ return ApiShim<GetCorSystemDirectoryFn_t>("GetCORSystemDirectory")(pbuffer, cchBuffer, dwLength);
+}
+
+//
+// Initialize a set of CoreCLR callbacks for utilcode to call into the VM with
+//
+// Return Value:
+// CoreClrCallbacks for UtilCode
+//
+// Notes:
+// Will not return NULL
+//
+
+CoreClrCallbacks *GetCoreClrCallbacks()
+{
+ static CoreClrCallbacks coreClrCallbacks = { 0 };
+ if (coreClrCallbacks.m_hmodCoreCLR == NULL)
+ {
+ // Run against the desktop CLR
+ coreClrCallbacks.m_hmodCoreCLR = WszLoadLibrary(W("mscoree.dll"));
+ coreClrCallbacks.m_pfnIEE = SnIEE;
+ coreClrCallbacks.m_pfnGetCORSystemDirectory = SnGetCorSystemDirectory;
+ coreClrCallbacks.m_pfnGetCLRFunction = NULL;
+ }
+
+ return &coreClrCallbacks;
+}
+
+// Initialize Utilcode
+//
+// Notes:
+// Should only be called once
+//
+
+void InitUtilcode()
+{
+#ifdef _DEBUG
+ static bool fAlreadyInitialized = false;
+ _ASSERTE(!fAlreadyInitialized);
+ fAlreadyInitialized = true;
+#endif
+
+ InitUtilcode(*GetCoreClrCallbacks());
+}
+
+#endif // FEATURE_CORECLR && !STRONGNAME_IN_VM
diff --git a/src/strongname/api/strongnameinternal.cpp b/src/strongname/api/strongnameinternal.cpp
new file mode 100644
index 0000000000..10a08fa18d
--- /dev/null
+++ b/src/strongname/api/strongnameinternal.cpp
@@ -0,0 +1,448 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//
+// Strong name APIs which are not exposed publicly but are used by CLR code
+//
+
+#include "common.h"
+#include "strongnameinternal.h"
+#include "strongnameholders.h"
+#include "thekey.h"
+#include "ecmakey.h"
+
+#ifdef FEATURE_STRONGNAME_TESTKEY_ALLOWED
+#include "thetestkey.h"
+
+BYTE g_rbTestKeyBuffer[] = { TEST_KEY_HEADER TEST_KEY_BUFFER };
+#endif // FEATURE_STRONGNAME_TESTKEY_ALLOWED
+
+//---------------------------------------------------------------------------------------
+//
+// Check to see if a public key blob is the ECMA public key blob
+//
+// Arguments:
+// pbKey - public key blob to check
+// cbKey - size in bytes of pbKey
+//
+
+bool StrongNameIsEcmaKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // The key should be the same size as the ECMA key
+ if (cbKey != sizeof(g_rbNeutralPublicKey))
+ {
+ return false;
+ }
+
+ const PublicKeyBlob *pKeyBlob = reinterpret_cast<const PublicKeyBlob *>(pbKey);
+ return StrongNameIsEcmaKey(*pKeyBlob);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Check to see if a public key blob is the ECMA public key blob
+//
+// Arguments:
+// keyPublicKey - Key to check to see if it matches the ECMA key
+//
+
+bool StrongNameIsEcmaKey(const PublicKeyBlob &keyPublicKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ return StrongNameSizeOfPublicKey(keyPublicKey) == sizeof(g_rbNeutralPublicKey) &&
+ memcmp(reinterpret_cast<const BYTE *>(&keyPublicKey), g_rbNeutralPublicKey, sizeof(g_rbNeutralPublicKey)) == 0;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Check to see if a public key blob is the TheKey public key blob
+//
+// Arguments:
+// pbKey - public key blob to check
+// cbKey - size in bytes of pbKey
+//
+bool StrongNameIsTheKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // The key should be the same size as the TheKey key
+ if (cbKey != sizeof(g_rbTheKey))
+ {
+ return false;
+ }
+
+ return (memcmp(pbKey, g_rbTheKey, sizeof(g_rbTheKey)) == 0);
+}
+
+#ifdef FEATURE_CORECLR
+//---------------------------------------------------------------------------------------
+//
+// Check to see if a public key blob is the Silverlight Platform public key blob
+//
+// Arguments:
+// pbKey - public key blob to check
+// cbKey - size in bytes of pbKey
+//
+
+bool StrongNameIsSilverlightPlatformKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // The key should be the same size as the ECMA key
+ if (cbKey != sizeof(g_rbTheSilverlightPlatformKey))
+ {
+ return false;
+ }
+
+ const PublicKeyBlob *pKeyBlob = reinterpret_cast<const PublicKeyBlob *>(pbKey);
+ return StrongNameIsSilverlightPlatformKey(*pKeyBlob);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Check to see if a public key blob is the Silverlight Platform public key blob
+//
+// Arguments:
+// keyPublicKey - Key to check to see if it matches the ECMA key
+//
+
+bool StrongNameIsSilverlightPlatformKey(const PublicKeyBlob &keyPublicKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ return StrongNameSizeOfPublicKey(keyPublicKey) == sizeof(g_rbTheSilverlightPlatformKey) &&
+ memcmp(reinterpret_cast<const BYTE *>(&keyPublicKey), g_rbTheSilverlightPlatformKey, sizeof(g_rbTheSilverlightPlatformKey)) == 0;
+}
+#endif //FEATURE_CORECLR
+
+#ifdef FEATURE_STRONGNAME_TESTKEY_ALLOWED
+
+//---------------------------------------------------------------------------------------
+//
+// Check to see if a public key blob is the Silverlight Platform public key blob
+//
+// See code:g_rbTestKeyBuffer#TestKeyStamping
+//
+// Arguments:
+// pbKey - public key blob to check
+// cbKey - size in bytes of pbKey
+//
+
+bool StrongNameIsTestKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // The key should be the same size as the ECMA key
+ if (cbKey != sizeof(g_rbTestKeyBuffer) - 2 * sizeof(GUID))
+ {
+ return false;
+ }
+
+ const PublicKeyBlob *pKeyBlob = reinterpret_cast<const PublicKeyBlob *>(pbKey);
+ return StrongNameIsTestKey(*pKeyBlob);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Determine if the public key blob is the test public key stamped into the VM.
+//
+// See code:g_rbTestKeyBuffer#TestKeyStamping
+//
+// Arguments:
+// keyPublicKey - public key blob to check for emptyness
+//
+
+bool StrongNameIsTestKey(const PublicKeyBlob &keyPublicKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // Find the blob in the VM by looking past the two header GUIDs in the buffer
+ _ASSERTE(sizeof(g_rbTestKeyBuffer) > 2 * sizeof(GUID) + sizeof(PublicKeyBlob));
+ const PublicKeyBlob *pbTestPublicKey = reinterpret_cast<const PublicKeyBlob *>(g_rbTestKeyBuffer + 2 * sizeof(GUID));
+
+ DWORD cbTestPublicKey = StrongNameSizeOfPublicKey(*pbTestPublicKey);
+ DWORD cbCheckPublicKey = StrongNameSizeOfPublicKey(keyPublicKey);
+
+ // Check whether valid test key was stamped in
+ if (cbTestPublicKey == 0)
+ return false;
+
+ // This is the test public key if it is the same size as the public key in the buffer, and is identical
+ // to the test key as well.
+ return cbTestPublicKey == cbCheckPublicKey &&
+ memcmp(reinterpret_cast<const void *>(pbTestPublicKey), reinterpret_cast<const void *>(&keyPublicKey), cbTestPublicKey) == 0;
+}
+
+#endif // FEATURE_STRONGNAME_TESTKEY_ALLOWED
+
+//---------------------------------------------------------------------------------------
+//
+// Verify that a public key blob looks like a reasonable public key
+//
+// Arguments:
+// pbBuffer - buffer to verify the format of
+// cbBuffer - size of pbBuffer
+// fImportKeys - do a more extensive check by attempting to import the keys
+//
+
+bool StrongNameIsValidPublicKey(__in_ecount(cbBuffer) const BYTE *pbBuffer, DWORD cbBuffer, bool fImportKeys)
+{
+ CONTRACTL
+ {
+ PRECONDITION(CheckPointer(pbBuffer));
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // The buffer must be at least as large as the public key structure
+ if (cbBuffer < sizeof(PublicKeyBlob))
+ {
+ return false;
+ }
+
+ // The buffer must be the same size as the structure header plus the trailing key data
+ const PublicKeyBlob *pkeyPublicKey = reinterpret_cast<const PublicKeyBlob *>(pbBuffer);
+ if (GET_UNALIGNED_VAL32(&pkeyPublicKey->cbPublicKey) != cbBuffer - offsetof(PublicKeyBlob, PublicKey))
+ {
+ return false;
+ }
+
+ // The buffer itself looks reasonable, but the public key structure needs to be validated as well
+ return StrongNameIsValidPublicKey(*pkeyPublicKey, fImportKeys);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Verify that a public key blob looks like a reasonable public key.
+//
+// Arguments:
+// keyPublicKey - key blob to verify
+// fImportKeys - do a more extensive check by verifying that the key data imports into CAPI
+//
+// Notes:
+// This can be a very expensive operation, since it involves importing keys.
+//
+
+bool StrongNameIsValidPublicKey(const PublicKeyBlob &keyPublicKey, bool fImportKeys)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ // The ECMA key doesn't look like a valid key so it will fail the below checks. If we were passed that
+ // key, then we can skip them
+ if (StrongNameIsEcmaKey(keyPublicKey))
+ {
+ return true;
+ }
+
+ // If a hash algorithm is specified, it must be a sensible value
+ bool fHashAlgorithmValid = GET_ALG_CLASS(GET_UNALIGNED_VAL32(&keyPublicKey.HashAlgID)) == ALG_CLASS_HASH &&
+ GET_ALG_SID(GET_UNALIGNED_VAL32(&keyPublicKey.HashAlgID)) >= ALG_SID_SHA1;
+ if (keyPublicKey.HashAlgID != 0 && !fHashAlgorithmValid)
+ {
+ return false;
+ }
+
+ // If a signature algorithm is specified, it must be a sensible value
+ bool fSignatureAlgorithmValid = GET_ALG_CLASS(GET_UNALIGNED_VAL32(&keyPublicKey.SigAlgID)) == ALG_CLASS_SIGNATURE;
+ if (keyPublicKey.SigAlgID != 0 && !fSignatureAlgorithmValid)
+ {
+ return false;
+ }
+
+ // The key blob must indicate that it is a PUBLICKEYBLOB
+ if (keyPublicKey.PublicKey[0] != PUBLICKEYBLOB)
+ {
+ return false;
+ }
+
+#if !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+ // Make sure the public key blob imports properly
+ if (fImportKeys)
+ {
+ CapiProviderHolder hProv;
+ if (!StrongNameCryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+ return false;
+ }
+
+ CapiKeyHolder hKey;
+ if (!CryptImportKey(hProv, keyPublicKey.PublicKey, GET_UNALIGNED_VAL32(&keyPublicKey.cbPublicKey), NULL, 0, &hKey))
+ {
+ return false;
+ }
+ }
+#else // !FEATURE_CORECLR || CROSSGEN_COMPILE
+ _ASSERTE(!fImportKeys);
+#endif // !FEATURE_CORECLR || CROSSGEN_COMPILE
+
+ return true;
+}
+
+
+//---------------------------------------------------------------------------------------
+//
+// Determine the number of bytes that a public key blob occupies, including the key portion
+//
+// Arguments:
+// keyPublicKey - key blob to calculate the size of
+//
+
+DWORD StrongNameSizeOfPublicKey(const PublicKeyBlob &keyPublicKey)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ return offsetof(PublicKeyBlob, PublicKey) + // Size of the blob header plus
+ GET_UNALIGNED_VAL32(&keyPublicKey.cbPublicKey); // the number of bytes in the key
+}
+
+#if !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+
+//---------------------------------------------------------------------------------------
+//
+// Check to see if the value held in a buffer is a full strong name key pair
+//
+// Arguments:
+// pbBuffer - Blob to check
+// cbBuffer - Size of the buffer in bytes
+//
+// Return Value:
+// true if the buffer represents a full strong name key pair, false otherwise
+//
+
+bool StrongNameIsValidKeyPair(__in_ecount(cbKeyPair) const BYTE *pbKeyPair, DWORD cbKeyPair)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(pbKeyPair));
+ }
+ CONTRACTL_END;
+
+ // Key pairs are just CAPI PRIVATEKEYBLOBs, so see if CAPI can import the blob
+ CapiProviderHolder hProv;
+ if (!StrongNameCryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+ return false;
+ }
+
+ CapiKeyHolder hKey;
+ if (!CryptImportKey(hProv, pbKeyPair, cbKeyPair, NULL, 0, &hKey))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+BYTE HexToByteA (char c) {
+ LIMITED_METHOD_CONTRACT;
+
+ if (!isxdigit(c)) return (BYTE) 0xff;
+ if (isdigit(c)) return (BYTE) (c - '0');
+ if (isupper(c)) return (BYTE) (c - 'A' + 10);
+ return (BYTE) (c - 'a' + 10);
+}
+
+// Read the hex string into a buffer
+// Caller owns the buffer.
+// Returns NULL if the string contains non-hex characters, or doesn't contain a multiple of 2 characters.
+bool GetBytesFromHex(LPCUTF8 szHexString, ULONG cchHexString, BYTE** buffer, ULONG *cbBufferSize) {
+ LIMITED_METHOD_CONTRACT;
+
+ ULONG cchHex = cchHexString;
+ if (cchHex % 2 != 0)
+ return false;
+ *cbBufferSize = cchHex / 2;
+ NewArrayHolder<BYTE> tempBuffer(new (nothrow) BYTE[*cbBufferSize]);
+ if (tempBuffer == NULL)
+ return false;
+
+ for (ULONG i = 0; i < *cbBufferSize; i++) {
+ BYTE msn = HexToByteA(*szHexString);
+ BYTE lsn = HexToByteA(*(szHexString + 1));
+ if(msn == 0xFF || lsn == 0xFF)
+ {
+ return false;
+ }
+
+ tempBuffer[i] = (BYTE) ( (msn << 4) | lsn );
+ szHexString += 2;
+ }
+
+ *buffer = tempBuffer.Extract();
+ return true;
+}
+
+// Helper method to call CryptAcquireContext, making sure we have a valid set of flags
+bool StrongNameCryptAcquireContext(HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider, DWORD dwProvType, DWORD dwFlags)
+{
+ LIMITED_METHOD_CONTRACT;
+
+#if defined(CRYPT_VERIFYCONTEXT) && defined(CRYPT_MACHINE_KEYSET)
+ // Specifying both verify context (for an ephemeral key) and machine keyset (for a persisted machine key)
+ // does not make sense. Additionally, Widows is beginning to lock down against uses of MACHINE_KEYSET
+ // (for instance in the app container), even if verify context is present. Therefore, if we're using
+ // an ephemeral key, strip out MACHINE_KEYSET from the flags.
+ if ((dwFlags & CRYPT_VERIFYCONTEXT) && (dwFlags & CRYPT_MACHINE_KEYSET))
+ {
+ dwFlags &= ~CRYPT_MACHINE_KEYSET;
+ }
+#endif // FEATURE_CRYPTO
+
+ return !!WszCryptAcquireContext(phProv, pwszContainer, pwszProvider, dwProvType, dwFlags);
+}
+
+#endif // !FEATURE_CORECLR || CROSSGEN_COMPILE
+
diff --git a/src/strongname/api/wks/.gitmirror b/src/strongname/api/wks/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/strongname/api/wks/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/strongname/api/wks/CMakeLists.txt b/src/strongname/api/wks/CMakeLists.txt
new file mode 100644
index 0000000000..581fee7717
--- /dev/null
+++ b/src/strongname/api/wks/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(strongname_wks ${STRONGNAME_SOURCES})
diff --git a/src/strongname/api/wks/strongname_wks.nativeproj b/src/strongname/api/wks/strongname_wks.nativeproj
new file mode 100644
index 0000000000..fcfa71ae6c
--- /dev/null
+++ b/src/strongname/api/wks/strongname_wks.nativeproj
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <PropertyGroup>
+ <StrongnameInVm>true</StrongnameInVm>
+ </PropertyGroup>
+ <Import Project="$(ClrBase)\src\strongname\api\api.props" />
+ <PropertyGroup Label="Globals">
+ <SccProjectName>SAK</SccProjectName>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccProvider>SAK</SccProvider>
+ </PropertyGroup>
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>strongname_wks</OutputName>
+ </PropertyGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/strongname/dirs.proj b/src/strongname/dirs.proj
new file mode 100644
index 0000000000..9cb3cf6724
--- /dev/null
+++ b/src/strongname/dirs.proj
@@ -0,0 +1,29 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <ItemDefinitionGroup>
+ <ProjectFile>
+ <ProductGroups>FX</ProductGroups>
+ </ProjectFile>
+ </ItemDefinitionGroup>
+
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1-->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="api\dirs.proj" />
+ <ProjectFile Include="inc\StrongName_inc.nativeproj" />
+ <ProjectFile Include="tools\dirs.proj" >
+ <ProductGroups>VS;FX</ProductGroups>
+ </ProjectFile>
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/strongname/inc/.gitmirror b/src/strongname/inc/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/strongname/inc/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/strongname/inc/StrongName_inc.nativeproj b/src/strongname/inc/StrongName_inc.nativeproj
new file mode 100644
index 0000000000..c72249f207
--- /dev/null
+++ b/src/strongname/inc/StrongName_inc.nativeproj
@@ -0,0 +1,31 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputPath>$(ClrLibDest)</OutputPath>
+ <TargetType>PUBLISH</TargetType>
+ <OutputName>StrongName</OutputName>
+ </PropertyGroup>
+
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <PublishPartLinked Include="StrongName.h">
+ <Visibility>Inter</Visibility>
+ <FileType>Include</FileType>
+ </PublishPartLinked>
+ </ItemGroup>
+
+ <ItemGroup>
+ <CopyFile Include="StrongName.h">
+ <DestFolder>$(BinariesDirectory)</DestFolder>
+ </CopyFile>
+ </ItemGroup>
+
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/strongname/inc/ecmakey.h b/src/strongname/inc/ecmakey.h
new file mode 100644
index 0000000000..1948b8b3b9
--- /dev/null
+++ b/src/strongname/inc/ecmakey.h
@@ -0,0 +1,10 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+#pragma once
+
+// The byte values of the ECMA pseudo public key and its token.
+const BYTE g_rbNeutralPublicKey[] = { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 };
+const BYTE g_rbNeutralPublicKeyToken[] = { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 };
+
diff --git a/src/strongname/inc/sncoreclr.h b/src/strongname/inc/sncoreclr.h
new file mode 100644
index 0000000000..3d6020f40f
--- /dev/null
+++ b/src/strongname/inc/sncoreclr.h
@@ -0,0 +1,15 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#ifndef _SNCORECLR_H
+#define _SNCORECLR_H
+
+#if !defined(FEATURE_CORECLR)
+#error sncoreclr.h should only be used on CoreCLR builds
+#endif // !FEATURE_CORECLR
+
+void InitUtilcode();
+
+#endif // _SNCORECLR_H
diff --git a/src/strongname/inc/strongname.h b/src/strongname/inc/strongname.h
new file mode 100644
index 0000000000..5c93a1ba8b
--- /dev/null
+++ b/src/strongname/inc/strongname.h
@@ -0,0 +1,307 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+#ifndef __STRONG_NAME_H
+#define __STRONG_NAME_H
+
+// ===========================================================================
+// File: StrongName.h
+//
+// Wrappers for signing and hashing functions needed to implement strong names
+// ===========================================================================
+
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <ole2.h>
+
+#include <corerror.h>
+#include <winapifamily.h>
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+// Public key blob binary format.
+typedef struct {
+ unsigned int SigAlgID; // (ALG_ID) signature algorithm used to create the signature
+ unsigned int HashAlgID; // (ALG_ID) hash algorithm used to create the signature
+ ULONG cbPublicKey; // length of the key in bytes
+ BYTE PublicKey[1]; // variable length byte array containing the key value in format output by CryptoAPI
+} PublicKeyBlob;
+
+
+// Location in the registry (under HKLM) that strong name configuration info is
+// stored.
+#define SN_CONFIG_KEY "Software\\Microsoft\\StrongName"
+#define SN_CONFIG_CSP "CSP" // REG_SZ
+#define SN_CONFIG_MACHINE_KEYSET "MachineKeyset" // REG_DWORD
+#define SN_CONFIG_KEYSPEC "KeySpec" // REG_DWORD
+#define SN_CONFIG_HASH_ALG "HashAlgorithm" // REG_DWORD
+#define SN_CONFIG_SIGN_ALG "SignAlgorithm" // REG_DWORD
+#define SN_CONFIG_VERIFICATION "Verification" // Registry subkey
+#define SN_CONFIG_USERLIST "UserList" // REG_MULTI_SZ
+#define SN_CONFIG_CACHE_VERIFY "CacheVerify" // REG_DWORD
+
+#define SN_CONFIG_KEY_W L"Software\\Microsoft\\StrongName"
+#define SN_CONFIG_CSP_W L"CSP" // REG_SZ
+#define SN_CONFIG_PROV_TYPE_W L"ProvType" // REG_DWORD
+#define SN_CONFIG_MACHINE_KEYSET_W L"MachineKeyset" // REG_DWORD
+#define SN_CONFIG_KEYSPEC_W L"KeySpec" // REG_DWORD
+#define SN_CONFIG_HASH_ALG_W L"HashAlgorithm" // REG_DWORD
+#define SN_CONFIG_SIGN_ALG_W L"SignAlgorithm" // REG_DWORD
+#define SN_CONFIG_VERIFICATION_W L"Verification" // Registry subkey
+#define SN_CONFIG_USERLIST_W L"UserList" // REG_MULTI_SZ
+#define SN_CONFIG_TESTPUBLICKEY_W L"TestPublicKey" // REG_SZ
+#define SN_CONFIG_CACHE_VERIFY_W L"CacheVerify" // REG_DWORD
+
+// VM related registry locations (Note, these values are under HKLM\Software\Microsoft\.NETFramework, rather
+// than SN_CONFIG_KEY
+#define SN_CONFIG_BYPASS_POLICY "AllowStrongNameBypass" // REG_DWORD
+#define SN_CONFIG_BYPASS_POLICY_W L"AllowStrongNameBypass" // REG_DWORD
+
+#if defined(_MSC_VER) && !defined(USE_DEPRECATED_CLR_API_WITHOUT_WARNING)
+#define DEPRECATED_CLR_API_MESG "This API has been deprecated. Refer to http://go.microsoft.com/fwlink/?LinkId=143720 for more details."
+#define DECLARE_DEPRECATED __declspec(deprecated(DEPRECATED_CLR_API_MESG))
+#else // _MSC_VER && !USE_DEPRECATED_CLR_API_WITHOUT_WARNING
+#define DECLARE_DEPRECATED
+#endif // _MSC_VER && !USE_DEPRECATED_CLR_API_WITHOUT_WARNING
+
+#define SNAPI DECLARE_DEPRECATED BOOLEAN __stdcall
+#define SNAPI_(_type) DECLARE_DEPRECATED _type __stdcall
+
+// Return last error.
+SNAPI_(DWORD) StrongNameErrorInfo(VOID);
+
+
+// Free buffer allocated by routines below.
+SNAPI_(VOID) StrongNameFreeBuffer(BYTE *pbMemory); // [in] address of memory to free
+
+
+// Generate a new key pair for strong name use.
+SNAPI StrongNameKeyGen(LPCWSTR wszKeyContainer, // [in] desired key container name
+ DWORD dwFlags, // [in] flags (see below)
+ BYTE **ppbKeyBlob, // [out] public/private key blob
+ ULONG *pcbKeyBlob);
+
+// Generate a new key pair with the specified key size for strong name use.
+SNAPI StrongNameKeyGenEx(LPCWSTR wszKeyContainer, // [in] desired key container name, must be a non-empty string
+ DWORD dwFlags, // [in] flags (see below)
+ DWORD dwKeySize, // [in] desired key size.
+ BYTE **ppbKeyBlob, // [out] public/private key blob
+ ULONG *pcbKeyBlob);
+
+// Flags for StrongNameKeyGen.
+#define SN_LEAVE_KEY 0x00000001 // Leave key pair registered with CSP
+
+
+// Import key pair into a key container.
+SNAPI StrongNameKeyInstall(LPCWSTR wszKeyContainer,// [in] desired key container name, must be a non-empty string
+ BYTE *pbKeyBlob, // [in] public/private key pair blob
+ ULONG cbKeyBlob);
+
+
+// Delete a key pair.
+SNAPI StrongNameKeyDelete(LPCWSTR wszKeyContainer); // [in] desired key container name
+
+// Retrieve the public portion of a key pair.
+SNAPI StrongNameGetPublicKey (LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbPublicKeyBlob, // [out] public key blob
+ ULONG *pcbPublicKeyBlob);
+
+// Retrieve the public portion of a key pair.
+SNAPI StrongNameGetPublicKeyEx (LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbPublicKeyBlob, // [out] public key blob
+ ULONG *pcbPublicKeyBlob,
+ ULONG uHashAlgId,
+ ULONG uReserved); // reserved for future use
+
+// Hash and sign a manifest.
+SNAPI StrongNameSignatureGeneration(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbSignatureBlob, // [out] signature blob
+ ULONG *pcbSignatureBlob);
+
+SNAPI StrongNameSignatureGenerationEx(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ LPCWSTR wszKeyContainer, // [in] desired key container name
+ BYTE *pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ BYTE **ppbSignatureBlob, // [out] signature blob
+ ULONG *pcbSignatureBlob,
+ DWORD dwFlags); // [in] modifer flags; see below
+
+#define SN_SIGN_ALL_FILES 0x00000001 // Rehash all linked modules as well as resigning the manifest
+#define SN_TEST_SIGN 0x00000002 // Test sign the assembly
+#define SN_ECMA_SIGN 0x00000004 // Sign the assembly treating the input key as the real ECMA key
+
+// Digest signing support
+
+// Generate the digest of an input assembly, which can be signed with StrongNameDigestSign
+SNAPI StrongNameDigestGenerate(_In_z_ LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ _Outptr_result_bytebuffer_(*pcbDigestBlob) BYTE** ppbDigestBlob, // [out] digest of the assembly, free with StrongNameFreeBuffer
+ _Out_ ULONG* pcbDigestBlob, // [out] number of bytes in the assembly digest
+ DWORD dwFlags); // [in] modifier flags (see StrongNameSignatureGenerationEx)
+
+// Sign an the digest of an assembly calculated by StrongNameDigestGenerate
+SNAPI StrongNameDigestSign(_In_opt_z_ LPCWSTR wszKeyContainer, // [in] desired key container name (optional)
+ _In_reads_bytes_opt_(cbKeyBlob) BYTE* pbKeyBlob, // [in] public/private key blob (optional)
+ ULONG cbKeyBlob,
+ _In_reads_bytes_(cbDigestBlob) BYTE* pbDigestBlob, // [in] digest blob, from StrongNameDigestGenerate
+ ULONG cbDigestBlob,
+ DWORD hashAlgId, // [in] algorithm id of the hash algorithm used with pbDigestBlob
+ _Outptr_result_bytebuffer_(*pcbSignatureBlob) BYTE** ppbSignatureBlob, // [out] signature blob, freed with StrongNameFreeBuffer
+ _Out_ ULONG* pcbSignatureBlob,
+ DWORD dwFlags); // [in] modifier flags (see StrongNameSignatureGenerationEx)
+
+// Embed a digest signature generated with StrongNameDigestSign into an assembly
+SNAPI StrongNameDigestEmbed(_In_z_ LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly to update
+ _In_reads_bytes_(cbSignatureBlob) BYTE* pbSignatureBlob, // [in] signature blob for the assembly
+ ULONG cbSignatureBlob);
+
+// Create a strong name token from an assembly file.
+SNAPI StrongNameTokenFromAssembly(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BYTE **ppbStrongNameToken, // [out] strong name token
+ ULONG *pcbStrongNameToken);
+
+// Create a strong name token from an assembly file and additionally return the full public key.
+SNAPI StrongNameTokenFromAssemblyEx(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BYTE **ppbStrongNameToken, // [out] strong name token
+ ULONG *pcbStrongNameToken,
+ BYTE **ppbPublicKeyBlob, // [out] public key blob
+ ULONG *pcbPublicKeyBlob);
+
+// Create a strong name token from a public key blob.
+SNAPI StrongNameTokenFromPublicKey(BYTE *pbPublicKeyBlob, // [in] public key blob
+ ULONG cbPublicKeyBlob,
+ BYTE **ppbStrongNameToken, // [out] strong name token
+ ULONG *pcbStrongNameToken);
+
+
+// Verify a strong name/manifest against a public key blob.
+SNAPI StrongNameSignatureVerification(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ DWORD dwInFlags, // [in] flags modifying behaviour (see below)
+ DWORD *pdwOutFlags); // [out] additional output info (see below)
+
+
+// Verify a strong name/manifest against a public key blob.
+SNAPI StrongNameSignatureVerificationEx(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BOOLEAN fForceVerification, // [in] verify even if settings in the registry disable it
+ BOOLEAN *pfWasVerified); // [out] set to false if verify succeeded due to registry settings
+
+// Verify a strong name/manifest against a public key blob.
+SNAPI StrongNameSignatureVerificationEx2(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BOOLEAN fForceVerification, // [in] verify even if settings in the registry disable it
+ BYTE *pbEcmaPublicKey, // [in] mapping from the ECMA public key to the real key used for verification
+ DWORD cbEcmaPublicKey, // [in] length of the real ECMA public key
+ BOOLEAN *pfWasVerified); // [out] set to false if verify succeeded due to registry settings
+
+// Verify a strong name/manifest against a public key blob when the assembly is
+// already memory mapped.
+SNAPI StrongNameSignatureVerificationFromImage(BYTE *pbBase, // [in] base address of mapped manifest file
+ DWORD dwLength, // [in] length of mapped image in bytes
+ DWORD dwInFlags, // [in] flags modifying behaviour (see below)
+ DWORD *pdwOutFlags); // [out] additional output info (see below)
+
+// Flags for use with the verify routines.
+#define SN_INFLAG_FORCE_VER 0x00000001 // verify even if settings in the registry disable it
+#define SN_INFLAG_INSTALL 0x00000002 // verification is the first (on entry to the cache)
+#define SN_INFLAG_ADMIN_ACCESS 0x00000004 // cache protects assembly from all but admin access
+#define SN_INFLAG_USER_ACCESS 0x00000008 // cache protects user's assembly from other users
+#define SN_INFLAG_ALL_ACCESS 0x00000010 // cache provides no access restriction guarantees
+
+#define SN_INFLAG_RUNTIME 0x80000000 // internal debugging use only
+
+#define SN_OUTFLAG_WAS_VERIFIED 0x00000001 // set to false if verify succeeded due to registry settings
+#define SN_OUTFLAG_MICROSOFT_SIGNATURE 0x00000002 // set if the public key corresponds to SN_THE_KEY
+
+// Verify that two assemblies differ only by signature blob.
+SNAPI StrongNameCompareAssemblies(LPCWSTR wszAssembly1, // [in] file name of first assembly
+ LPCWSTR wszAssembly2, // [in] file name of second assembly
+ DWORD *pdwResult); // [out] result of comparison (see codes below)
+
+#define SN_CMP_DIFFERENT 0 // Assemblies contain different data
+#define SN_CMP_IDENTICAL 1 // Assemblies are exactly the same, even signatures
+#define SN_CMP_SIGONLY 2 // Assemblies differ only by signature (and checksum etc.)
+
+
+// Compute the size of buffer needed to hold a hash for a given hash algorithm.
+SNAPI StrongNameHashSize(ULONG ulHashAlg, // [in] hash algorithm
+ DWORD *pcbSize); // [out] size of the hash in bytes
+
+
+// Compute the size that needs to be allocated for a signature in an assembly.
+SNAPI StrongNameSignatureSize(BYTE *pbPublicKeyBlob, // [in] public key blob
+ ULONG cbPublicKeyBlob,
+ DWORD *pcbSize); // [out] size of the signature in bytes
+
+
+SNAPI_(DWORD) GetHashFromAssemblyFile(LPCSTR szFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash); // [OUT] length of hash byte array
+
+SNAPI_(DWORD) GetHashFromAssemblyFileW(LPCWSTR wszFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash); // [OUT] length of hash byte array
+
+SNAPI_(DWORD) GetHashFromFile(LPCSTR szFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash); // [OUT] length of hash byte array
+
+SNAPI_(DWORD) GetHashFromFileW(LPCWSTR wszFilePath, // [IN] location of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash); // [OUT] length of hash byte array
+
+SNAPI_(DWORD) GetHashFromHandle(HANDLE hFile, // [IN] handle of file to be hashed
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash); // [OUT] length of hash byte array
+
+SNAPI_(DWORD) GetHashFromBlob(BYTE *pbBlob, // [IN] pointer to memory block to hash
+ DWORD cchBlob, // [IN] length of blob
+ unsigned int *piHashAlg, // [IN/OUT] constant specifying the hash algorithm (set to 0 if you want the default)
+ BYTE *pbHash, // [OUT] hash buffer
+ DWORD cchHash, // [IN] max size of buffer
+ DWORD *pchHash); // [OUT] length of hash byte array
+
+SNAPI StrongNameGetBlob(LPCWSTR wszFilePath, // [in] valid path to the PE file for the assembly
+ BYTE *pbBlob, // [in] buffer to fill with blob
+ DWORD *pcbBlob); // [in/out] size of buffer/number of bytes put into buffer
+
+SNAPI StrongNameGetBlobFromImage(BYTE *pbBase, // [in] base address of mapped manifest file
+ DWORD dwLength, // [in] length of mapped image in bytes
+ BYTE *pbBlob, // [in] buffer to fill with blob
+ DWORD *pcbBlob); // [in/out] size of buffer/number of bytes put into buffer
+
+#undef DECLARE_DEPRECATED
+#undef DEPRECATED_CLR_API_MESG
+#undef SNAPI
+#undef SNAPI_
+#define SNAPI BOOLEAN __stdcall
+#define SNAPI_(_type) _type __stdcall
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+
+#endif
diff --git a/src/strongname/inc/strongnameholders.h b/src/strongname/inc/strongnameholders.h
new file mode 100644
index 0000000000..663fd5eaa6
--- /dev/null
+++ b/src/strongname/inc/strongnameholders.h
@@ -0,0 +1,104 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#ifndef __STRONGNAME_HOLDERS_H__
+#define __STRONGNAME_HOLDERS_H__
+
+#include <holder.h>
+#include <strongname.h>
+#include <wincrypt.h>
+
+//
+// Holder classes for types returned from and used in strong name APIs
+//
+
+// Holder for any memory allocated by the strong name APIs
+template<class T>
+void VoidStrongNameFreeBuffer(__in T *pBuffer)
+{
+ StrongNameFreeBuffer(reinterpret_cast<BYTE *>(pBuffer));
+}
+NEW_WRAPPER_TEMPLATE1(StrongNameBufferHolder, VoidStrongNameFreeBuffer<_TYPE>);
+
+#if !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+// Holder for HCRYPTPROV handles directly allocated from CAPI
+inline void ReleaseCapiProvider(HCRYPTPROV hProv)
+{
+ CryptReleaseContext(hProv, 0);
+}
+typedef Wrapper<HCRYPTPROV, DoNothing, ReleaseCapiProvider, 0> CapiProviderHolder;
+
+inline void ReleaseCapiKey(HCRYPTKEY hKey)
+{
+ CryptDestroyKey(hKey);
+}
+typedef Wrapper<HCRYPTKEY, DoNothing, ReleaseCapiKey, 0> CapiKeyHolder;
+
+inline void ReleaseCapiHash(HCRYPTHASH hHash)
+{
+ CryptDestroyHash(hHash);
+}
+typedef Wrapper<HCRYPTHASH, DoNothing, ReleaseCapiHash, 0> CapiHashHolder;
+#endif // !FEATURE_CORECLR || CROSSGEN_COMPILE
+
+#if SNAPI_INTERNAL
+
+// Context structure tracking information for a loaded assembly.
+struct SN_LOAD_CTX
+{
+ HANDLE m_hFile; // Open file handle
+ HANDLE m_hMap; // Mapping file handle
+ BYTE *m_pbBase; // Base address of mapped file
+ DWORD m_dwLength; // Length of file in bytes
+ IMAGE_NT_HEADERS32 *m_pNtHeaders; // Address of NT headers
+ IMAGE_COR20_HEADER *m_pCorHeader; // Address of COM+ 2.0 header
+ BYTE *m_pbSignature; // Address of signature blob
+ DWORD m_cbSignature; // Size of signature blob
+ BOOLEAN m_fReadOnly; // File mapped for read-only access
+ BOOLEAN m_fPreMapped; // File was already mapped for us
+ PEDecoder *m_pedecoder; // PEDecoder corresponding to this file
+ SN_LOAD_CTX() { ZeroMemory(this, sizeof(*this)); }
+};
+
+BOOLEAN LoadAssembly(SN_LOAD_CTX *pLoadCtx, LPCWSTR szFilePath, DWORD inFlags = 0, BOOLEAN fRequireSignature = TRUE);
+BOOLEAN UnloadAssembly(SN_LOAD_CTX *pLoadCtx);
+
+// Holder for loading an assembly into an SN_LOAD_CTX
+class StrongNameAssemblyLoadHolder
+{
+private:
+ SN_LOAD_CTX m_snLoadCtx;
+ bool m_fLoaded;
+
+public:
+ StrongNameAssemblyLoadHolder(LPCWSTR wszAssembly, bool fReadOnly)
+ {
+ m_snLoadCtx.m_fReadOnly = !!fReadOnly;
+ m_fLoaded = !!LoadAssembly(&m_snLoadCtx, wszAssembly);
+ }
+
+ ~StrongNameAssemblyLoadHolder()
+ {
+ if (m_fLoaded)
+ {
+ UnloadAssembly(&m_snLoadCtx);
+ }
+ }
+
+public:
+ SN_LOAD_CTX *GetLoadContext()
+ {
+ return &m_snLoadCtx;
+ }
+
+ bool IsLoaded()
+ {
+ return m_fLoaded;
+ }
+};
+
+#endif // SNAPI_INTERNAL
+
+#endif // !__STRONGNAME_HOLDERS_H__
diff --git a/src/strongname/inc/strongnameinternal.h b/src/strongname/inc/strongnameinternal.h
new file mode 100644
index 0000000000..ec5fb5da90
--- /dev/null
+++ b/src/strongname/inc/strongnameinternal.h
@@ -0,0 +1,59 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//
+// Strong name APIs which are not exposed publicly, but are built into StrongName.lib
+//
+
+#ifndef _STRONGNAME_INTERNAL_H
+#define _STRONGNAME_INTERNAL_H
+
+#include <strongname.h>
+
+#include <wincrypt.h>
+
+// NTDDI_VERSION is currently defined as XP SP2.
+// Strongname api's that use this are supported on XP SP3 and later, so we can use them.
+#ifndef ALG_SID_SHA_256
+#define ALG_SID_SHA_256 12
+#define ALG_SID_SHA_384 13
+#define ALG_SID_SHA_512 14
+#define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
+#define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)
+#define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)
+#endif //ALG_SID_SHA_256
+
+#ifdef FEATURE_STRONGNAME_TESTKEY_ALLOWED
+bool StrongNameIsTestKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey);
+bool StrongNameIsTestKey(const PublicKeyBlob &keyPublicKey);
+#endif // FEATURE_STRONGNAME_TESTKEY_ALLOWED
+
+// Determine the number of bytes in a public key
+DWORD StrongNameSizeOfPublicKey(const PublicKeyBlob &keyPublicKey);
+
+bool StrongNameIsValidPublicKey(__in_ecount(cbPublicKeyBlob) const BYTE *pbPublicKeyBlob, DWORD cbPublicKeyBlob, bool fImporKey);
+bool StrongNameIsValidPublicKey(const PublicKeyBlob &keyPublicKey, bool fImportKey);
+
+// Determine if a public key is the ECMA key
+bool StrongNameIsEcmaKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey);
+bool StrongNameIsEcmaKey(const PublicKeyBlob &keyPublicKey);
+
+bool StrongNameIsTheKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey);
+
+#if !defined(FEATURE_CORECLR) || defined(CROSSGEN_COMPILE)
+
+// Verify the format of a public key blob
+bool StrongNameIsValidKeyPair(__in_ecount(cbKeyPair) const BYTE *pbKeyPair, DWORD cbKeyPair);
+
+bool GetBytesFromHex(LPCUTF8 szHexString, ULONG cchHexString, BYTE** buffer, ULONG *cbBufferSize);
+
+bool StrongNameCryptAcquireContext(HCRYPTPROV *phProv, LPCWSTR pwszContainer, LPCWSTR pwszProvider, DWORD dwProvType, DWORD dwFlags);
+#endif // !FEATURE_CORECLR || CROSSGEN_COMPILE
+
+#ifdef FEATURE_CORECLR
+bool StrongNameIsSilverlightPlatformKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey);
+bool StrongNameIsSilverlightPlatformKey(const PublicKeyBlob &keyPublicKey);
+#endif // FEATURE_CORECLR
+
+#endif // !_STRONGNAME_INTERNAL_H
diff --git a/src/strongname/inc/thekey.h b/src/strongname/inc/thekey.h
new file mode 100644
index 0000000000..1c447b2067
--- /dev/null
+++ b/src/strongname/inc/thekey.h
@@ -0,0 +1,105 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+#pragma once
+// This file allows customization of the strongname key used to replace the ECMA key
+
+static const BYTE g_rbTheKey[] =
+{
+0x00,0x24,0x00,0x00,0x04,0x80,0x00,0x00,0x94,0x00,0x00,0x00,0x06,0x02,0x00,0x00,
+0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x04,0x00,0x00,0x01,0x00,0x01,0x00,
+0x07,0xd1,0xfa,0x57,0xc4,0xae,0xd9,0xf0,0xa3,0x2e,0x84,0xaa,0x0f,0xae,0xfd,0x0d,
+0xe9,0xe8,0xfd,0x6a,0xec,0x8f,0x87,0xfb,0x03,0x76,0x6c,0x83,0x4c,0x99,0x92,0x1e,
+0xb2,0x3b,0xe7,0x9a,0xd9,0xd5,0xdc,0xc1,0xdd,0x9a,0xd2,0x36,0x13,0x21,0x02,0x90,
+0x0b,0x72,0x3c,0xf9,0x80,0x95,0x7f,0xc4,0xe1,0x77,0x10,0x8f,0xc6,0x07,0x77,0x4f,
+0x29,0xe8,0x32,0x0e,0x92,0xea,0x05,0xec,0xe4,0xe8,0x21,0xc0,0xa5,0xef,0xe8,0xf1,
+0x64,0x5c,0x4c,0x0c,0x93,0xc1,0xab,0x99,0x28,0x5d,0x62,0x2c,0xaa,0x65,0x2c,0x1d,
+0xfa,0xd6,0x3d,0x74,0x5d,0x6f,0x2d,0xe5,0xf1,0x7e,0x5e,0xaf,0x0f,0xc4,0x96,0x3d,
+0x26,0x1c,0x8a,0x12,0x43,0x65,0x18,0x20,0x6d,0xc0,0x93,0x34,0x4d,0x5a,0xd2,0x93
+};
+
+static const BYTE g_rbTheKeyToken[] = {0xb0,0x3f,0x5f,0x7f,0x11,0xd5,0x0a,0x3a};
+
+
+#ifdef FEATURE_CORECLR
+static const BYTE g_rbTheSilverlightPlatformKey[] =
+{
+0x00,0x24,0x00,0x00,0x04,0x80,0x00,0x00,0x94,0x00,0x00,0x00,0x06,0x02,0x00,0x00,
+0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x04,0x00,0x00,0x01,0x00,0x01,0x00,
+0x8d,0x56,0xc7,0x6f,0x9e,0x86,0x49,0x38,0x30,0x49,0xf3,0x83,0xc4,0x4b,0xe0,0xec,
+0x20,0x41,0x81,0x82,0x2a,0x6c,0x31,0xcf,0x5e,0xb7,0xef,0x48,0x69,0x44,0xd0,0x32,
+0x18,0x8e,0xa1,0xd3,0x92,0x07,0x63,0x71,0x2c,0xcb,0x12,0xd7,0x5f,0xb7,0x7e,0x98,
+0x11,0x14,0x9e,0x61,0x48,0xe5,0xd3,0x2f,0xba,0xab,0x37,0x61,0x1c,0x18,0x78,0xdd,
+0xc1,0x9e,0x20,0xef,0x13,0x5d,0x0c,0xb2,0xcf,0xf2,0xbf,0xec,0x3d,0x11,0x58,0x10,
+0xc3,0xd9,0x06,0x96,0x38,0xfe,0x4b,0xe2,0x15,0xdb,0xf7,0x95,0x86,0x19,0x20,0xe5,
+0xab,0x6f,0x7d,0xb2,0xe2,0xce,0xef,0x13,0x6a,0xc2,0x3d,0x5d,0xd2,0xbf,0x03,0x17,
+0x00,0xae,0xc2,0x32,0xf6,0xc6,0xb1,0xc7,0x85,0xb4,0x30,0x5c,0x12,0x3b,0x37,0xab
+};
+
+static const BYTE g_rbTheSilverlightPlatformKeyToken[] = {0x7c,0xec,0x85,0xd7,0xbe,0xa7,0x79,0x8e};
+
+static const BYTE g_rbTheSilverlightKey[] =
+{
+0x00,0x24,0x00,0x00,0x04,0x80,0x00,0x00,0x94,0x00,0x00,0x00,0x06,0x02,0x00,0x00,
+0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x04,0x00,0x00,0x01,0x00,0x01,0x00,
+0xb5,0xfc,0x90,0xe7,0x02,0x7f,0x67,0x87,0x1e,0x77,0x3a,0x8f,0xde,0x89,0x38,0xc8,
+0x1d,0xd4,0x02,0xba,0x65,0xb9,0x20,0x1d,0x60,0x59,0x3e,0x96,0xc4,0x92,0x65,0x1e,
+0x88,0x9c,0xc1,0x3f,0x14,0x15,0xeb,0xb5,0x3f,0xac,0x11,0x31,0xae,0x0b,0xd3,0x33,
+0xc5,0xee,0x60,0x21,0x67,0x2d,0x97,0x18,0xea,0x31,0xa8,0xae,0xbd,0x0d,0xa0,0x07,
+0x2f,0x25,0xd8,0x7d,0xba,0x6f,0xc9,0x0f,0xfd,0x59,0x8e,0xd4,0xda,0x35,0xe4,0x4c,
+0x39,0x8c,0x45,0x43,0x07,0xe8,0xe3,0x3b,0x84,0x26,0x14,0x3d,0xae,0xc9,0xf5,0x96,
+0x83,0x6f,0x97,0xc8,0xf7,0x47,0x50,0xe5,0x97,0x5c,0x64,0xe2,0x18,0x9f,0x45,0xde,
+0xf4,0x6b,0x2a,0x2b,0x12,0x47,0xad,0xc3,0x65,0x2b,0xf5,0xc3,0x08,0x05,0x5d,0xa9
+};
+
+static const BYTE g_rbTheSilverlightKeyToken[] = {0x31,0xBF,0x38,0x56,0xAD,0x36,0x4E,0x35};
+
+#ifdef FEATURE_WINDOWSPHONE
+
+static const BYTE g_rbTheMicrosoftPhoneKey[] =
+{
+0x00,0x24,0x00,0x00,0x04,0x80,0x00,0x00,0x14,0x01,0x00,0x00,0x06,0x02,0x00,0x00,
+0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x08,0x00,0x00,0x01,0x00,0x01,0x00,
+0xCB,0x8F,0x76,0xDA,0xE0,0x5D,0x35,0x2C,0x11,0x7A,0x84,0x67,0xEF,0x32,0x60,0xE0,
+0x02,0x10,0x8A,0xA9,0xE7,0x09,0x56,0xE7,0x05,0xF6,0x43,0x0F,0x6C,0xBC,0xFE,0x35,
+0x9D,0x02,0x11,0x75,0x63,0x40,0x00,0x17,0xD1,0x00,0x4D,0x68,0xD1,0x3F,0xE5,0x74,
+0xA2,0x56,0x49,0x58,0x0E,0xD1,0xEE,0x22,0x5A,0xA4,0xBB,0xC0,0x93,0x06,0x2D,0xA0,
+0xB1,0x68,0xBB,0xEA,0x3F,0x57,0x95,0x50,0x8F,0xCB,0xD7,0x53,0x13,0x74,0xC7,0x45,
+0xCE,0x63,0x27,0xA9,0x1A,0xC7,0x24,0x35,0x71,0xF2,0xB4,0xE8,0xE4,0xFC,0x24,0x8C,
+0xA1,0xA2,0xF3,0xC8,0x73,0xE1,0x49,0xB3,0x43,0x0B,0x37,0xBD,0x51,0xA6,0xA3,0xAD,
+0xC9,0x5F,0x68,0x5C,0x91,0x74,0x57,0x69,0x13,0x0F,0xA1,0x0F,0xBF,0xC7,0xB2,0x28,
+0x2F,0x25,0xDF,0xFD,0x4B,0xA2,0xC0,0xBD,0x7C,0x82,0x88,0xCD,0xE4,0x80,0x6C,0x8B,
+0xDC,0x81,0x7D,0x12,0x6C,0x7E,0x54,0x36,0x10,0xD3,0x47,0x6A,0x63,0x17,0xB5,0xD5,
+0x48,0x76,0xA0,0xE3,0xB3,0xAD,0x42,0xB1,0x2C,0x51,0x38,0xDB,0x2F,0xFB,0x66,0x9F,
+0x1B,0xE6,0x31,0x4B,0xC9,0x58,0x7A,0xC1,0xAC,0xE4,0x75,0x1D,0x6C,0x58,0x84,0xDB,
+0x04,0x81,0x15,0x90,0x7C,0x09,0x0D,0xBB,0xDF,0x98,0xC6,0x5E,0xD4,0xC0,0x42,0xC3,
+0x77,0x5A,0xCA,0xA7,0xD6,0x04,0x23,0x07,0xFA,0xE2,0xAA,0xFA,0xE7,0x12,0x8E,0x17,
+0x65,0x81,0x92,0x44,0x6C,0x07,0x40,0x0D,0x22,0xC5,0xBA,0x43,0xF3,0xA1,0xE7,0xA3,
+0xE5,0xAF,0x81,0xBE,0x0E,0x65,0xA5,0x01,0x6C,0x5F,0x0C,0x62,0xA3,0xC0,0xDE,0xB3
+};
+
+static const BYTE g_rbTheMicrosoftPhoneKeyToken[] = {0x24,0xEE,0xC0,0xD8,0xC8,0x6C,0xDA,0x1E};
+
+
+static const BYTE g_rbTheMicrosoftXNAKey[] =
+{
+0x00,0x24,0x00,0x00,0x04,0x80,0x00,0x00,0x94,0x00,0x00,0x00,0x06,0x02,0x00,0x00,
+0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x04,0x00,0x00,0x01,0x00,0x01,0x00,
+0x0F,0xC5,0x99,0x3E,0x0F,0x51,0x1A,0xD5,0xE1,0x6E,0x8B,0x22,0x65,0x53,0x49,0x3E,
+0x09,0x06,0x7A,0xFC,0x41,0x03,0x9F,0x70,0xDA,0xEB,0x94,0xA9,0x68,0xD6,0x64,0xF4,
+0x0E,0x69,0xA4,0x6B,0x61,0x7D,0x15,0xD3,0xD5,0x32,0x8B,0xE7,0xDB,0xED,0xD0,0x59,
+0xEB,0x98,0x49,0x5A,0x3B,0x03,0xCB,0x4E,0xA4,0xBA,0x12,0x74,0x44,0x67,0x1C,0x3C,
+0x84,0xCB,0xC1,0xFD,0xC3,0x93,0xD7,0xE1,0x0B,0x5E,0xE3,0xF3,0x1F,0x5A,0x29,0xF0,
+0x05,0xE5,0xEE,0xD7,0xE3,0xC9,0xC8,0xAF,0x74,0xF4,0x13,0xF0,0x00,0x4F,0x0C,0x2C,
+0xAB,0xB2,0x2F,0x9D,0xD4,0xF7,0x5A,0x6F,0x59,0x97,0x84,0xE1,0xBA,0xB7,0x09,0x85,
+0xEF,0x81,0x74,0xCA,0x6C,0x68,0x42,0x78,0xBE,0x82,0xCE,0x05,0x5A,0x03,0xEB,0xAF
+};
+
+static const BYTE g_rbTheMicrosoftXNAKeyToken[] = {0xCC,0xAC,0x92,0xED,0x87,0x3B,0x18,0x5C};
+
+#endif
+// for FEATURE_WINDOWSPHONE, we can add the Microsoft.Phone key and the Xna key to the list of blessed keys...
+
+#endif // FEATURE_CORECLR
+
diff --git a/src/strongname/inc/thetestkey.h b/src/strongname/inc/thetestkey.h
new file mode 100644
index 0000000000..f644467d5f
--- /dev/null
+++ b/src/strongname/inc/thetestkey.h
@@ -0,0 +1,87 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+// This file allows customization of the test strongname key used in place of the real MS key
+
+#ifdef FEATURE_STRONGNAME_TESTKEY_ALLOWED
+
+//
+// #TestKeyStamping
+//
+// On CoreCLR, we have a requirement that only keys signed with the Microsoft public key can be considered
+// part of the platform and therefore contain critical code. This leads to an issue with testing the
+// product, since any tests which need to test platform only feautres would need to be signed by the
+// Microsoft public key, and for a variety of reasons it is not feasable to sign all of our test assemblies
+// with that key.
+//
+// Instead, we provide an extension where any assembly signed with the public key contained in the
+// g_rbTestKeyBuffer will also be considered part of the platform. The buffer is filled with a zero key,
+// which means by default non-Microsoft signatures will not be accepted. However, the slstampkey tool looks
+// for the two GUIDs in the beginning of the buffer, and can replace the key with a real one of the test
+// team's choosing. Once this modification is in place, test assemblies can be considered part of the
+// platform and can access critical APIs.
+//
+// Since this buffer is searched for in the VM using external tools, it's very important that it only appear
+// once in the final image of the runtime. If it appears multiple times, tools will be unable to determine
+// which test key buffer is the real buffer, and therefore tests which rely on containing platform code will
+// be unable to run on the build.
+//
+
+#define TEST_KEY_HEADER \
+ /* Test key buffer header 1: { cd517db8-a1b1-44bf-aa64-bf66fefa3831 } */ \
+ 0xb8, 0x7d, 0x51, 0xcd, 0xb1, 0xa1, 0xbf, 0x44, 0x64, 0xaa, 0xbf, 0x66, 0xfe, 0xfa, 0x38, 0x31, \
+ \
+ /* Test key buffer header 2: { 5f363032-eaaf-4103-b312-ab2c8e35cf58 } */ \
+ 0x32, 0x30, 0x36, 0x5f, 0xaf, 0xea, 0x03, 0x41, 0x12, 0xb3, 0xab, 0x2c, 0x8e, 0x35, 0xcf, 0x58,
+
+
+#define TEST_KEY_VALUE \
+ /* SigAlgId = */\
+ 0x00, 0x24, 0x00, 0x00, \
+ \
+ /* HashAlgId = */\
+ 0x04, 0x80, 0x00, 0x00, \
+ \
+ /* cbPublicKey = 0x94 */ \
+ 0x94, 0x00, 0x00, 0x00, \
+ \
+ /* 1024 bit public key */ \
+ 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, \
+ 0x0f, 0xc5, 0x99, 0x3e, 0x0f, 0x51, 0x1a, 0xd5, 0xe1, 0x6e, 0x8b, 0x22, 0x65, 0x53, 0x49, 0x3e, 0x09, 0x06, 0x7a, 0xfc, \
+ 0x41, 0x03, 0x9f, 0x70, 0xda, 0xeb, 0x94, 0xa9, 0x68, 0xd6, 0x64, 0xf4, 0x0e, 0x69, 0xa4, 0x6b, 0x61, 0x7d, 0x15, 0xd3, \
+ 0xd5, 0x32, 0x8b, 0xe7, 0xdb, 0xed, 0xd0, 0x59, 0xeb, 0x98, 0x49, 0x5a, 0x3b, 0x03, 0xcb, 0x4e, 0xa4, 0xba, 0x12, 0x74, \
+ 0x44, 0x67, 0x1c, 0x3c, 0x84, 0xcb, 0xc1, 0xfd, 0xc3, 0x93, 0xd7, 0xe1, 0x0b, 0x5e, 0xe3, 0xf3, 0x1f, 0x5a, 0x29, 0xf0, \
+ 0x05, 0xe5, 0xee, 0xd7, 0xe3, 0xc9, 0xc8, 0xaf, 0x74, 0xf4, 0x13, 0xf0, 0x00, 0x4f, 0x0c, 0x2c, 0xab, 0xb2, 0x2f, 0x9d, \
+ 0xd4, 0xf7, 0x5a, 0x6f, 0x59, 0x97, 0x84, 0xe1, 0xba, 0xb7, 0x09, 0x85, 0xef, 0x81, 0x74, 0xca, 0x6c, 0x68, 0x42, 0x78, \
+ 0xbe, 0x82, 0xce, 0x05, 0x5a, 0x03, 0xeb, 0xaf
+
+ //
+ // Test Public key blob
+ //
+
+ //
+ // No prestamped test key - create an empty key buffer
+ //
+#define TEST_KEY_BUFFER \
+ /* SigAlgId */ \
+ 0x00, 0x00, 0x00, 0x00, \
+ \
+ /* HashAlgId */ \
+ 0x00, 0x00, 0x00, 0x00, \
+ \
+ /* cbPublicKey = 0x94 - this needs to match the size of the public key section below */ \
+ 0x94, 0x00, 0x00, 0x00, \
+ \
+ /* 1024 bit public key - 0x94 bytes */ \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+
+#endif // FEATURE_STRONGNAME_TESTKEY_ALLOWED
diff --git a/src/strongname/strongname.vcxproj b/src/strongname/strongname.vcxproj
new file mode 100644
index 0000000000..66f370883a
--- /dev/null
+++ b/src/strongname/strongname.vcxproj
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="amd64chk|Win32">
+ <Configuration>amd64chk</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="amd64corechk|Win32">
+ <Configuration>amd64corechk</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="amd64coredbg|Win32">
+ <Configuration>amd64coredbg</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="amd64coreret|Win32">
+ <Configuration>amd64coreret</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="amd64dbg|Win32">
+ <Configuration>amd64dbg</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="amd64ret|Win32">
+ <Configuration>amd64ret</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="armcorechk|Win32">
+ <Configuration>armcorechk</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="armcoredbg|Win32">
+ <Configuration>armcoredbg</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="armcoreret|Win32">
+ <Configuration>armcoreret</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Mac.inteldbg|Win32">
+ <Configuration>Mac.inteldbg</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x86chk|Win32">
+ <Configuration>x86chk</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x86corechk|Win32">
+ <Configuration>x86corechk</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x86coredbg|Win32">
+ <Configuration>x86coredbg</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x86coreret|Win32">
+ <Configuration>x86coreret</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x86dbg|Win32">
+ <Configuration>x86dbg</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="x86ret|Win32">
+ <Configuration>x86ret</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{6AA7CBD3-6CAA-4159-B5B6-DEFE6065D41B}</ProjectGuid>
+ <RootNamespace>StrongName</RootNamespace>
+ <SccProjectName>SAK</SccProjectName>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccProvider>SAK</SccProvider>
+ <Keyword>MakeFileProj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='armcoreret|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='armcorechk|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='armcoredbg|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64coreret|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64coredbg|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64corechk|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Mac.inteldbg|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86coreret|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86coredbg|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86corechk|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64ret|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64dbg|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64chk|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86ret|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86chk|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86dbg|Win32'" Label="Configuration">
+ <ConfigurationType>Makefile</ConfigurationType>
+ <PlatformToolset>v120</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='armcoreret|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='armcorechk|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='armcoredbg|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='amd64coreret|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='amd64coredbg|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='amd64corechk|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Mac.inteldbg|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x86coreret|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x86coredbg|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x86corechk|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='amd64ret|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='amd64dbg|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='amd64chk|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x86ret|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x86chk|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='x86dbg|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>12.0.20617.1</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86dbg|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86chk|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86ret|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64chk|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64dbg|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64ret|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86corechk|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86coredbg|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='x86coreret|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Mac.inteldbg|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(SolutionDir)\..\..\..\rotor\palrt\inc;$(SolutionDir)\..\..\..\rotor\pal\inc;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64corechk|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64coredbg|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='amd64coreret|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='armcoredbg|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='armcorechk|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='armcoreret|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ <IntDir>$(Configuration)\</IntDir>
+ <NMakeBuildCommandLine />
+ <NMakeReBuildCommandLine />
+ <NMakeCleanCommandLine />
+ <NMakeOutput />
+ <NMakeIncludeSearchPath>.\inc;..\inc;..\md\inc;..\vm;$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>
+ <NMakeForcedIncludes>$(ProjectDir)..\defines\cache\defines.$(Configuration).h;$(NMakeForcedIncludes)</NMakeForcedIncludes>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="api\common.cpp" />
+ <ClCompile Include="api\StrongName.cpp" />
+ <ClCompile Include="api\StrongNameCoreClr.cpp" />
+ <ClCompile Include="api\StrongNameInternal.cpp" />
+ <ClCompile Include="tools\slstampkey\slstampkey.cpp" />
+ <ClCompile Include="tools\sn\sn.cpp" />
+ <ClCompile Include="tools\snhdr\snhdr.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api\common.h" />
+ <ClInclude Include="api\CryptApis.h" />
+ <ClInclude Include="inc\EcmaKey.h" />
+ <ClInclude Include="inc\sncoreclr.h" />
+ <ClInclude Include="inc\StrongName.h" />
+ <ClInclude Include="inc\StrongNameHolders.h" />
+ <ClInclude Include="inc\StrongNameInternal.h" />
+ <ClInclude Include="inc\TheKey.h" />
+ <ClInclude Include="inc\TheTestKey.h" />
+ <ClInclude Include="inc\WellKnownImages.h" />
+ <ClInclude Include="tools\sn\resources.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="inc\sources" />
+ <None Include="tools\slstampkey\sources" />
+ <None Include="tools\sn\sources" />
+ <None Include="tools\snhdr\sources" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="tools\slstampkey\slstampkey.rc" />
+ <ResourceCompile Include="tools\sn\sn.rc" />
+ <ResourceCompile Include="tools\snhdr\snhdr.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/strongname/strongname.vcxproj.filters b/src/strongname/strongname.vcxproj.filters
new file mode 100644
index 0000000000..77aa40e76c
--- /dev/null
+++ b/src/strongname/strongname.vcxproj.filters
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="api">
+ <UniqueIdentifier>{7388d6b8-789c-47c9-80a2-66ee17a5958c}</UniqueIdentifier>
+ <Extensions>cpp</Extensions>
+ </Filter>
+ <Filter Include="inc">
+ <UniqueIdentifier>{26401483-02d0-4bef-8fb5-30e94e81f89d}</UniqueIdentifier>
+ <Extensions>h</Extensions>
+ </Filter>
+ <Filter Include="slstampkey">
+ <UniqueIdentifier>{e15d16b5-68c0-45bf-9836-33b5790e6da5}</UniqueIdentifier>
+ <Extensions>cpp</Extensions>
+ </Filter>
+ <Filter Include="sn">
+ <UniqueIdentifier>{c014e6a5-fc76-4b23-8f0b-bd4c275b8d6b}</UniqueIdentifier>
+ <Extensions>cpp</Extensions>
+ </Filter>
+ <Filter Include="snhdr">
+ <UniqueIdentifier>{ec414528-cbc8-41ca-95bb-34b0babd892d}</UniqueIdentifier>
+ <Extensions>cpp</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="api\common.cpp">
+ <Filter>api</Filter>
+ </ClCompile>
+ <ClCompile Include="api\StrongName.cpp">
+ <Filter>api</Filter>
+ </ClCompile>
+ <ClCompile Include="api\StrongNameCoreClr.cpp">
+ <Filter>api</Filter>
+ </ClCompile>
+ <ClCompile Include="api\StrongNameInternal.cpp">
+ <Filter>api</Filter>
+ </ClCompile>
+ <ClCompile Include="tools\slstampkey\slstampkey.cpp">
+ <Filter>slstampkey</Filter>
+ </ClCompile>
+ <ClCompile Include="tools\sn\sn.cpp">
+ <Filter>sn</Filter>
+ </ClCompile>
+ <ClCompile Include="tools\snhdr\snhdr.cpp">
+ <Filter>snhdr</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api\common.h">
+ <Filter>api</Filter>
+ </ClInclude>
+ <ClInclude Include="api\CryptApis.h">
+ <Filter>api</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\EcmaKey.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\sncoreclr.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\StrongName.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\StrongNameHolders.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\StrongNameInternal.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\TheKey.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\TheTestKey.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="inc\WellKnownImages.h">
+ <Filter>inc</Filter>
+ </ClInclude>
+ <ClInclude Include="tools\sn\resources.h">
+ <Filter>sn</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="inc\sources">
+ <Filter>inc</Filter>
+ </None>
+ <None Include="tools\slstampkey\sources">
+ <Filter>slstampkey</Filter>
+ </None>
+ <None Include="tools\sn\sources">
+ <Filter>sn</Filter>
+ </None>
+ <None Include="tools\snhdr\sources">
+ <Filter>snhdr</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="tools\slstampkey\slstampkey.rc">
+ <Filter>slstampkey</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="tools\sn\sn.rc">
+ <Filter>sn</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="tools\snhdr\snhdr.rc">
+ <Filter>snhdr</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/strongname/strongname.vcxproj.vspscc b/src/strongname/strongname.vcxproj.vspscc
new file mode 100644
index 0000000000..b6d32892fd
--- /dev/null
+++ b/src/strongname/strongname.vcxproj.vspscc
@@ -0,0 +1,10 @@
+""
+{
+"FILE_VERSION" = "9237"
+"ENLISTMENT_CHOICE" = "NEVER"
+"PROJECT_FILE_RELATIVE_PATH" = ""
+"NUMBER_OF_EXCLUDED_FILES" = "0"
+"ORIGINAL_PROJECT_FILE_PATH" = ""
+"NUMBER_OF_NESTED_PROJECTS" = "0"
+"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
+}