From 206b6a7efbc2e947eff900f448b86573b77ae392 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 15:32:54 -0800 Subject: Remove remainder of FEATURE_CORECLR (tool missed some files, also comments) --- src/strongname/api/strongname.cpp | 4607 +---------------------------- src/strongname/api/strongnamecoreclr.cpp | 3 - src/strongname/api/strongnameinternal.cpp | 12 +- src/strongname/inc/strongnameholders.h | 2 +- src/strongname/inc/strongnameinternal.h | 2 +- 5 files changed, 26 insertions(+), 4600 deletions(-) (limited to 'src/strongname') diff --git a/src/strongname/api/strongname.cpp b/src/strongname/api/strongname.cpp index 00b115698c..09c438b213 100644 --- a/src/strongname/api/strongname.cpp +++ b/src/strongname/api/strongname.cpp @@ -113,9 +113,6 @@ enum StrongNameCachedCsp { // allocated lazily as needed. struct SN_THREAD_CTX { DWORD m_dwLastError; -#if !defined(FEATURE_CORECLR) - HCRYPTPROV m_hProv[CachedCspCount]; -#endif // !FEATURE_CORECLR }; #endif // !DACCESS_COMPILE @@ -170,4507 +167,34 @@ struct SN_THREAD_CTX { 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) - -#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 - - - -#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(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 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 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 pbSig(NULL); - ULONG cbSig = 0; - SN_LOAD_CTX sLoadCtx; - BOOLEAN bImageLoaded = FALSE; - ALG_ID uHashAlgId; - StrongNameBufferHolder 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 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(&hashSize), &dwordSize, 0)) - { - SetStrongNameErrorInfo(HRESULT_FROM_GetLastError()); - return false; - } - - StrongNameBufferHolder 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(&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(&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 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(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(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(const_cast(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(const_cast(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 pbNewFileHash(NULL); - DWORD cbNewFileHash = 0; - DWORD cchDirectory; - DWORD cchFullFile; - CHAR szFullFile[MAX_LONGPATH + 1]; - WCHAR wszFullFile[MAX_LONGPATH + 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_LONGPATH, NULL, NULL); - if (cchDirectory >= MAX_LONGPATH) { - 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_LONGPATH); - if (cchFullFile == 0 || cchFullFile >= MAX_LONGPATH) { - 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 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(pbSignaturePublicKey.GetValue())) == SN_SIZEOF_KEY(pAssemblySignaturePublicKey) && - memcmp(static_cast(pAssemblySignaturePublicKey), - static_cast(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(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(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(pLoadCtx->m_pCorHeader) && - pbSignature > reinterpret_cast(pLoadCtx->m_pCorHeader) - size) - { - dwError = CORSEC_E_INVALID_IMAGE_FORMAT; - goto Error; - } - if (pbSignature >= reinterpret_cast(pLoadCtx->m_pCorHeader) && - pbSignature - sizeof(IMAGE_COR20_HEADER) < reinterpret_cast(pLoadCtx->m_pCorHeader)) - { - dwError = CORSEC_E_INVALID_IMAGE_FORMAT; - goto Error; - } - - pLoadCtx->m_pbSignature = pbSignature; - pLoadCtx->m_cbSignature = static_cast(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 -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_FNAME + 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_FNAME + 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 mszUserList(NULL); - DWORD cbUserList; - NewArrayHolder wszTestPublicKey(NULL); - DWORD cbTestPublicKey; - NewArrayHolder 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 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 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 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_FNAME + 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_FNAME + 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 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 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 pvBuffer = new (nothrow) BYTE[dwRetLen]; - if (pvBuffer == NULL) - { - SetLastError(E_OUTOFMEMORY); - return FALSE; - } - - if (!GetTokenInformation(hToken, TokenUser, reinterpret_cast((BYTE*)pvBuffer), dwRetLen, &dwRetLen)) { - SNLOG((W("Failed to acquire token information, error %08X\n"), GetLastError())); - CloseHandle(hToken); - return FALSE; - } - - pUser = reinterpret_cast(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(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 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 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 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 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(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____' where 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(const_cast(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 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; ixtype.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 pMetaDataImport; - IfFailRet(GetMetadataImport(pLoadCtx, &tkAssembly, &pMetaDataImport)); - - HRESULT attributeHr; - void *pAttribute; - ULONG cbAttribute; - hr = pMetaDataImport->GetCustomAttributeByName(tkAssembly, g_AssemblySignatureKeyAttribute, const_cast(&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 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 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 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_FNAME + 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 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(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 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 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 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; +// 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) - *pchHash = cchHash; +// 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) - hProv = LocateCSP(NULL, SN_IGNORE_CONTAINER, *piHashAlg); +#define SN_THE_SILVERLIGHT_KEYTOKEN() ((PublicKeyBlob*)g_rbTheSilverlightKeyToken) - if (!hProv || - (!CryptCreateHash(hProv, *piHashAlg, 0, 0, &hHash)) || - (!CryptHashData(hHash, pbBlob, cchBlob, 0)) || - (!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, pchHash, 0))) - hr = HRESULT_FROM_GetLastError(); +#ifdef FEATURE_WINDOWSPHONE +// Microsoft.Phone.* key +#define SN_THE_MICROSOFT_PHONE_KEYTOKEN() ((PublicKeyBlob*)g_rbTheMicrosoftPhoneKeyToken) -ErrExit: - END_ENTRYPOINT_NOTHROW; +#define SN_IS_THE_MICROSOFT_PHONE_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbTheMicrosoftPhoneKey) && \ + memcmp((_pk), g_rbTheMicrosoftPhoneKey, sizeof(g_rbTheMicrosoftPhoneKey)) == 0) - return hr; -} +// Microsoft.Xna.* key +#define SN_THE_MICROSOFT_XNA_KEYTOKEN() ((PublicKeyBlob*)g_rbTheMicrosoftXNAKeyToken) -#endif // #ifndef DACCESS_COMPILE +#define SN_IS_THE_MICROSOFT_XNA_KEY(_pk) (SN_SIZEOF_KEY((PublicKeyBlob*)(_pk)) == sizeof(g_rbTheMicrosoftXNAKey) && \ + memcmp((_pk), g_rbTheMicrosoftXNAKey, sizeof(g_rbTheMicrosoftXNAKey)) == 0) -#else // !defined(FEATURE_CORECLR) +#endif // FEATURE_WINDOWSPHONE #define InitStrongName() S_OK -#endif // !defined(FEATURE_CORECLR) - // Free buffer allocated by routines below. SNAPI_(VOID) StrongNameFreeBuffer(BYTE *pbMemory) // [in] address of memory to free @@ -4695,12 +219,6 @@ SN_THREAD_CTX *GetThreadContext() if (pThreadCtx == NULL) return NULL; pThreadCtx->m_dwLastError = S_OK; -#if !defined(FEATURE_CORECLR) - for (ULONG i = 0; i < CachedCspCount; i++) - { - pThreadCtx->m_hProv[i] = NULL; - } -#endif // !FEATURE_CORECLR EX_TRY { ClrFlsSetValue(TlsIdx_StrongName, pThreadCtx); @@ -4760,18 +278,8 @@ SNAPI StrongNameTokenFromPublicKey(BYTE *pbPublicKeyBlob, // [in] publ #ifndef DACCESS_COMPILE -#ifndef FEATURE_CORECLR - HCRYPTPROV hProv = NULL; - HCRYPTHASH hHash = NULL; - HCRYPTKEY hKey = NULL; - DWORD dwHashLen; - DWORD dwRetLen; - NewArrayHolder pHash(NULL); -#else // !FEATURE_CORECLR SHA1Hash sha1; BYTE *pHash = NULL; -#endif // !FEATURE_CORECLR - DWORD i; DWORD cbKeyBlob; PublicKeyBlob *pPublicKey = NULL; @@ -4814,7 +322,7 @@ SNAPI StrongNameTokenFromPublicKey(BYTE *pbPublicKeyBlob, // [in] publ 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); @@ -4846,7 +354,6 @@ SNAPI StrongNameTokenFromPublicKey(BYTE *pbPublicKeyBlob, // [in] publ } #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. @@ -4876,79 +383,11 @@ SNAPI StrongNameTokenFromPublicKey(BYTE *pbPublicKeyBlob, // [in] publ 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::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 @@ -4961,14 +400,6 @@ SNAPI StrongNameTokenFromPublicKey(BYTE *pbPublicKeyBlob, // [in] publ 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; diff --git a/src/strongname/api/strongnamecoreclr.cpp b/src/strongname/api/strongnamecoreclr.cpp index 1ed7f0e10c..b02cde3dd9 100644 --- a/src/strongname/api/strongnamecoreclr.cpp +++ b/src/strongname/api/strongnamecoreclr.cpp @@ -10,8 +10,6 @@ #include "common.h" -#if defined(FEATURE_CORECLR) - CoreClrCallbacks *GetCoreClrCallbacks(); // @@ -95,4 +93,3 @@ void InitUtilcode() InitUtilcode(*GetCoreClrCallbacks()); } -#endif // FEATURE_CORECLR && !STRONGNAME_IN_VM diff --git a/src/strongname/api/strongnameinternal.cpp b/src/strongname/api/strongnameinternal.cpp index 0ace8a7c58..56b1c0e031 100644 --- a/src/strongname/api/strongnameinternal.cpp +++ b/src/strongname/api/strongnameinternal.cpp @@ -86,7 +86,6 @@ bool StrongNameIsTheKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey) 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 @@ -135,7 +134,6 @@ bool StrongNameIsSilverlightPlatformKey(const PublicKeyBlob &keyPublicKey) return StrongNameSizeOfPublicKey(keyPublicKey) == sizeof(g_rbTheSilverlightPlatformKey) && memcmp(reinterpret_cast(&keyPublicKey), g_rbTheSilverlightPlatformKey, sizeof(g_rbTheSilverlightPlatformKey)) == 0; } -#endif //FEATURE_CORECLR //--------------------------------------------------------------------------------------- // @@ -223,7 +221,7 @@ bool StrongNameIsValidPublicKey(const PublicKeyBlob &keyPublicKey, bool fImportK return false; } -#if !defined(FEATURE_CORECLR) || (defined(CROSSGEN_COMPILE) && !defined(PLATFORM_UNIX)) +#if (defined(CROSSGEN_COMPILE) && !defined(PLATFORM_UNIX)) // Make sure the public key blob imports properly if (fImportKeys) { @@ -239,9 +237,9 @@ bool StrongNameIsValidPublicKey(const PublicKeyBlob &keyPublicKey, bool fImportK return false; } } -#else // !FEATURE_CORECLR || (CROSSGEN_COMPILE && !PLATFORM_UNIX) +#else // (CROSSGEN_COMPILE && !PLATFORM_UNIX) _ASSERTE(!fImportKeys); -#endif // !FEATURE_CORECLR || (CROSSGEN_COMPILE && !PLATFORM_UNIX) +#endif // (CROSSGEN_COMPILE && !PLATFORM_UNIX) return true; } @@ -268,7 +266,7 @@ DWORD StrongNameSizeOfPublicKey(const PublicKeyBlob &keyPublicKey) GET_UNALIGNED_VAL32(&keyPublicKey.cbPublicKey); // the number of bytes in the key } -#if !defined(FEATURE_CORECLR) || (defined(CROSSGEN_COMPILE) && !defined(PLATFORM_UNIX)) +#if (defined(CROSSGEN_COMPILE) && !defined(PLATFORM_UNIX)) //--------------------------------------------------------------------------------------- // @@ -367,5 +365,5 @@ bool StrongNameCryptAcquireContext(HCRYPTPROV *phProv, LPCWSTR pwszContainer, LP return !!WszCryptAcquireContext(phProv, pwszContainer, pwszProvider, dwProvType, dwFlags); } -#endif // !FEATURE_CORECLR || (CROSSGEN_COMPILE && !PLATFORM_UNIX) +#endif // (CROSSGEN_COMPILE && !PLATFORM_UNIX) diff --git a/src/strongname/inc/strongnameholders.h b/src/strongname/inc/strongnameholders.h index b6af80f583..1a95c87aa7 100644 --- a/src/strongname/inc/strongnameholders.h +++ b/src/strongname/inc/strongnameholders.h @@ -40,7 +40,7 @@ inline void ReleaseCapiHash(HCRYPTHASH hHash) CryptDestroyHash(hHash); } typedef Wrapper CapiHashHolder; -#endif // !FEATURE_CORECLR || CROSSGEN_COMPILE +#endif // defined(CROSSGEN_COMPILE) && !defined(PLATFORM_UNIX) #if SNAPI_INTERNAL diff --git a/src/strongname/inc/strongnameinternal.h b/src/strongname/inc/strongnameinternal.h index 5aae39daa2..7cbf5d87a8 100644 --- a/src/strongname/inc/strongnameinternal.h +++ b/src/strongname/inc/strongnameinternal.h @@ -43,7 +43,7 @@ bool StrongNameIsValidKeyPair(__in_ecount(cbKeyPair) const BYTE *pbKeyPair, DWOR 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 && !PLATFORM_UNIX) +#endif // (CROSSGEN_COMPILE && !PLATFORM_UNIX) bool StrongNameIsSilverlightPlatformKey(__in_ecount(cbKey) const BYTE *pbKey, DWORD cbKey); bool StrongNameIsSilverlightPlatformKey(const PublicKeyBlob &keyPublicKey); -- cgit v1.2.3