// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright (c) 2020-2021 NVIDIA Corporation. All rights reserved. #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include // Needed for conversion to WCHAR for Win32 APIs that require it #include #include #include "GfnSdk_SecureLoadLibrary.h" #define NV_NVIDIA_CERT_NAME "nvidia " // Internal function forward declarations static BOOL gfnInternalFileExists(LPCWSTR szFileName); static BOOL gfnInternalContainsAbsolutePath(LPCWSTR szFileName); static HANDLE gfnInternalLockFileForGenericReadAccess(LPCWSTR szFilePath); static LPWSTR gfnInternalCreateUnicodeStringFromAscii(LPCSTR szAscii); typedef enum tagSignatureType { SignatureTypeAny, SignatureTypeGfn, SignatureTypeNvidia } SignatureType; static BOOL gfnInternalVerifyFileSignature(LPCWSTR fileName, SignatureType signatureType); static BOOL gfnInternalVerifyFileSignatureInfo( PCMSG_SIGNER_INFO pSignerInfo, HCERTSTORE hStore, LPCWSTR fileName, DWORD index, SignatureType signatureType); static HMODULE gfnInternalSecureLoadLibraryW(LPCWSTR filePath, DWORD dwFlags, SignatureType signatureType); static HMODULE gfnInternalSecureLoadLibraryA(LPCSTR filePath, DWORD dwFlags, SignatureType signatureType); // Just emphasising that LocalFree ignores NULL args: #define SafeLocalFree(x) LocalFree(x) // Close HANDLE without changing last OS error: #define SafeCloseHandle(x) \ if ((NULL != (x)) && (INVALID_HANDLE_VALUE != (x))) \ { \ DWORD lastError = GetLastError(); \ CloseHandle(x); (x) = INVALID_HANDLE_VALUE; \ SetLastError(lastError); \ } // =================================================================== // Public API functions are defined in this section // =================================================================== HMODULE gfnSecureLoadClientLibraryW(LPCWSTR filePath, DWORD dwFlags) { return gfnInternalSecureLoadLibraryW(filePath, dwFlags, SignatureTypeNvidia); } HMODULE gfnSecureLoadClientLibraryA(LPCSTR filePath, DWORD dwFlags) { return gfnInternalSecureLoadLibraryA(filePath, dwFlags, SignatureTypeNvidia); } HMODULE gfnSecureLoadCloudLibraryW(LPCWSTR filePath, DWORD dwFlags) { return gfnInternalSecureLoadLibraryW(filePath, dwFlags, SignatureTypeNvidia); } HMODULE gfnSecureLoadCloudLibraryA(LPCSTR filePath, DWORD dwFlags) { return gfnInternalSecureLoadLibraryA(filePath, dwFlags, SignatureTypeNvidia); } BOOL gfnCheckLibraryGfnSignatureW(LPCWSTR filePath) { return gfnInternalVerifyFileSignature(filePath, SignatureTypeGfn); } BOOL gfnCheckLibraryGfnSignatureA(LPCSTR filePath) { BOOL isSigned = FALSE; LPWSTR unicodeFilePath = NULL; if (!filePath) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } unicodeFilePath = gfnInternalCreateUnicodeStringFromAscii(filePath); if (!!unicodeFilePath) { isSigned = gfnInternalVerifyFileSignature(unicodeFilePath, SignatureTypeGfn); } SafeLocalFree(unicodeFilePath); return isSigned; } BOOL gfnCheckLibraryNvSignatureW(LPCWSTR filePath) { return gfnInternalVerifyFileSignature(filePath, SignatureTypeNvidia); } BOOL gfnCheckLibraryNvSignatureA(LPCSTR filePath) { BOOL isSigned = FALSE; LPWSTR unicodeFilePath = NULL; if (!filePath) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } unicodeFilePath = gfnInternalCreateUnicodeStringFromAscii(filePath); if (!!unicodeFilePath) { isSigned = gfnInternalVerifyFileSignature(unicodeFilePath, SignatureTypeNvidia); } SafeLocalFree(unicodeFilePath); return isSigned; } // =================================================================== // Internal functions defined below. Do not use directly. // =================================================================== static HMODULE gfnInternalSecureLoadLibraryW(LPCWSTR filePath, DWORD dwFlags, SignatureType signatureType) { HANDLE hFileLock = INVALID_HANDLE_VALUE; HMODULE pResult = NULL; SetLastError(ERROR_SUCCESS); // filePath must specifiy an absolute path. if (!gfnInternalContainsAbsolutePath(filePath)) { SetLastError(ERROR_BAD_ARGUMENTS); } else if (!gfnInternalFileExists(filePath)) { SetLastError(ERROR_MOD_NOT_FOUND); } else if (INVALID_HANDLE_VALUE == (hFileLock = gfnInternalLockFileForGenericReadAccess(filePath))) { SetLastError(ERROR_SHARING_VIOLATION); } else { BOOL bSignatureVerified = gfnInternalVerifyFileSignature(filePath, signatureType); if (!bSignatureVerified) { SetLastError((DWORD)CRYPT_E_NO_MATCH); } else { pResult = LoadLibraryExW(filePath, NULL, dwFlags); } SafeCloseHandle(hFileLock); } return pResult; } static HMODULE gfnInternalSecureLoadLibraryA(LPCSTR filePath, DWORD dwFlags, SignatureType signatureType) { // Defering to UNICODE version to reduce complexity/redundancy HMODULE hResult = NULL; LPWSTR unicodeFilePath = NULL; if (!filePath) { SetLastError(ERROR_INVALID_PARAMETER); return NULL; } unicodeFilePath = gfnInternalCreateUnicodeStringFromAscii(filePath); if (unicodeFilePath) { hResult = gfnInternalSecureLoadLibraryW(unicodeFilePath, dwFlags, signatureType); } SafeLocalFree(unicodeFilePath); return hResult; } #pragma warning(disable: 4706) // Don't warn about assignments within conditional expressions static HMODULE hModCrypt32 = NULL; typedef BOOL(WINAPI* PfnCryptMsgClose)(IN HCRYPTMSG hCryptMsg); static PfnCryptMsgClose pfnCryptMsgClose = NULL; typedef BOOL(WINAPI* PfnCertCloseStore)(IN HCERTSTORE hCertStore, DWORD dwFlags); static PfnCertCloseStore pfnCertCloseStore = NULL; typedef BOOL(WINAPI* PfnCertFreeCertificateContext)(IN PCCERT_CONTEXT pCertContext); static PfnCertFreeCertificateContext pfnCertFreeCertificateContext = NULL; typedef PCCERT_CONTEXT(WINAPI* PfnCertFindCertificateInStore)( IN HCERTSTORE hCertStore, IN DWORD dwCertEncodingType, IN DWORD dwFindFlags, IN DWORD dwFindType, IN const void* pvFindPara, IN PCCERT_CONTEXT pPrevCertContext ); static PfnCertFindCertificateInStore pfnCertFindCertificateInStore = NULL; typedef BOOL(WINAPI* PfnCryptMsgGetParam)( IN HCRYPTMSG hCryptMsg, IN DWORD dwParamType, IN DWORD dwIndex, OUT void* pvData, IN OUT DWORD* pcbData ); static PfnCryptMsgGetParam pfnCryptMsgGetParam = NULL; typedef BOOL(WINAPI* PfnCryptQueryObject)( DWORD dwObjectType, const void* pvObject, DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, DWORD dwFlags, DWORD* pdwMsgAndCertEncodingType, DWORD* pdwContentType, DWORD* pdwFormatType, HCERTSTORE* phCertStore, HCRYPTMSG* phMsg, const void** ppvContext ); static PfnCryptQueryObject pfnCryptQueryObject = NULL; typedef BOOL(WINAPI* PfnCryptDecodeObjectEx)( IN DWORD dwCertEncodingType, IN LPCSTR lpszStructType, IN const BYTE* pbEncoded, IN DWORD cbEncoded, IN DWORD dwFlags, IN PCRYPT_DECODE_PARA pDecodePara, OUT void* pvStructInfo, IN OUT DWORD* pcbStructInfo ); static PfnCryptDecodeObjectEx pfnCryptDecodeObjectEx = NULL; typedef PCCERT_CONTEXT(WINAPI* PfnCertGetIssuerCertificateFromStore)( IN HCERTSTORE hCertStore, IN PCCERT_CONTEXT pSubjectContext, IN OPTIONAL PCCERT_CONTEXT pPrevIssuerContext, IN OUT DWORD* pdwFlags ); static PfnCertGetIssuerCertificateFromStore pfnCertGetIssuerCertificateFromStore = NULL; typedef DWORD(WINAPI* PfnCertGetNameStringA)( IN PCCERT_CONTEXT pCertContext, IN DWORD dwType, IN DWORD dwFlags, IN void* pvTypePara, OUT OPTIONAL LPSTR pszNameString, IN DWORD cchNameString ); static PfnCertGetNameStringA pfnCertGetNameStringA = NULL; typedef LONG(WINAPI* PfnWinVerifyTrust)(IN HWND hWnd, IN GUID* pgActionID, IN LPVOID pWVTData); static PfnWinVerifyTrust pfnWinVerifyTrust = NULL; typedef LONG(APIENTRY* PfnRegOpenKeyExW)( IN HKEY hKey, IN LPCWSTR lpSubKey, IN DWORD ulOptions, IN REGSAM samDesired, OUT PHKEY phkResult ); static PfnRegOpenKeyExW pfnRegOpenKeyExW = NULL; typedef LONG(APIENTRY* PfnRegQueryValueExW)( IN HKEY hKey, IN LPCWSTR lpValueName, IN LPDWORD lpReserved, OUT LPDWORD lpType, OUT LPBYTE lpData, IN OUT LPDWORD lpcbData ); static PfnRegQueryValueExW pfnRegQueryValueExW = NULL; typedef LONG(APIENTRY* PfnRegCloseKey)(IN HKEY hKey); static PfnRegCloseKey pfnRegCloseKey = NULL; typedef HRESULT(WINAPI* PfnSHGetFolderPath_W)(HWND, int, HANDLE, DWORD, LPWSTR); static PfnSHGetFolderPath_W pfnSHGetFolderPath = NULL; typedef SC_HANDLE(WINAPI* PfnOpenSCManagerW)( IN LPCWSTR lpMachineName, IN LPCWSTR lpDatabaseName, IN DWORD dwDesiredAccess ); static PfnOpenSCManagerW pfnOpenSCManagerW = NULL; typedef SC_HANDLE(WINAPI* PfnOpenServiceW)( IN SC_HANDLE hSCManager, IN LPCWSTR lpServiceName, IN DWORD dwDesiredAccess ); static PfnOpenServiceW pfnOpenServiceW = NULL; typedef BOOL(WINAPI* PfnQueryServiceStatus)( IN SC_HANDLE hService, OUT LPSERVICE_STATUS lpServiceStatus ); static PfnQueryServiceStatus pfnQueryServiceStatus = NULL; typedef BOOL(WINAPI* PfnCloseServiceHandle)( IN SC_HANDLE hSCObject ); static PfnCloseServiceHandle pfnCloseServiceHandle = NULL; typedef HCRYPTMSG(WINAPI* PfnCryptMsgOpenToDecode)( IN DWORD dwMsgEncodingType, IN DWORD dwFlags, IN DWORD dwMsgType, IN HCRYPTPROV_LEGACY hCryptProv, IN PCERT_INFO pRecipientInfo, IN PCMSG_STREAM_INFO pStreamInfo ); static PfnCryptMsgOpenToDecode pfnCryptMsgOpenToDecode = NULL; typedef BOOL(WINAPI* PfnCryptMsgUpdate)( IN HCRYPTMSG hCryptMsg, IN const BYTE* pbData, IN DWORD cbData, IN BOOL fFinal ); static PfnCryptMsgUpdate pfnCryptMsgUpdate = NULL; typedef HCERTSTORE(WINAPI* PfnCertOpenStore)( IN LPCSTR lpszStoreProvider, IN DWORD dwEncodingType, IN HCRYPTPROV_LEGACY hCryptProv, IN DWORD dwFlags, IN const void* pvPara ); static PfnCertOpenStore pfnCertOpenStore = NULL; typedef BOOL(WINAPI* PfnCertGetCertificateChain)( IN HCERTCHAINENGINE hChainEngine, IN PCCERT_CONTEXT pCertContext, IN LPFILETIME pTime, IN HCERTSTORE hAdditionalStore, IN PCERT_CHAIN_PARA pChainPara, IN DWORD dwFlags, IN LPVOID pvReserved, OUT PCCERT_CHAIN_CONTEXT* ppChainContext ); PfnCertGetCertificateChain pfnCertGetCertificateChain = NULL; typedef VOID(WINAPI* PfnCertFreeCertificateChain)( IN PCCERT_CHAIN_CONTEXT pChainContext ); static PfnCertFreeCertificateChain pfnCertFreeCertificateChain = NULL; typedef LONG(WINAPI* PfnCertVerifyTimeValidity)( IN LPFILETIME pTimeToVerify, IN PCERT_INFO pCertInfo); static PfnCertVerifyTimeValidity pfnCertVerifyTimeValidity = NULL; static BOOL gfnInternalFileExists(LPCWSTR szFileName) { DWORD fileAttributes = GetFileAttributesW(szFileName); const DWORD nonFileAttributes = FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_DIRECTORY; return ((INVALID_FILE_ATTRIBUTES == fileAttributes) || (fileAttributes & nonFileAttributes)) ? FALSE : TRUE; } static BOOL gfnInternalContainsAbsolutePath(LPCWSTR szFileName) { if (!szFileName) { return FALSE; } if ((szFileName[0] == '\\') || (szFileName[0] == '/')) { return TRUE; } if ((isalpha(szFileName[0]) && (szFileName[1] == ':')) && ((szFileName[2] == '\\') || (szFileName[2] == '/'))) { return TRUE; } return FALSE; } static HANDLE gfnInternalLockFileForGenericReadAccess(LPCWSTR szFilePath) { return CreateFileW( szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); } static LPWSTR gfnInternalCreateUnicodeStringFromAscii(LPCSTR szAscii) { LPWSTR pResult = NULL; UINT i = 0; if (!!szAscii) { if (pResult = (LPWSTR)LocalAlloc(LPTR, (strlen(szAscii) + 1) * sizeof(WCHAR))) { for (i = 0; i < strlen(szAscii); ++i) { pResult[i] = szAscii[i]; } } } return pResult; } LPWSTR gfnInternalCreateSystemFilePath(LPCWSTR szFileName) { LPWSTR pResult = NULL; UINT i; if (!!szFileName) { DWORD dwLength = GetSystemDirectoryW(pResult, 0); pResult = (LPWSTR)LocalAlloc(LPTR, (dwLength + 1 + wcslen(szFileName)) * sizeof(WCHAR)); if (!pResult) { return NULL; } dwLength = GetSystemDirectoryW(pResult, dwLength); if (pResult[dwLength - 1] != '\\') { pResult[dwLength++] = '\\'; } for (i = 0; i < wcslen(szFileName); ++i) { pResult[dwLength + i] = szFileName[i]; } } return pResult; } typedef enum { eWindowsVistaBuild = 6000, eWindows7Build = 7600, eWindows8Build = 9200, eWindows8Point1Build = 9600, eWindows10TH1Build = 10240, eWindows10TH2Build = 10586, eWindows10RS1DriverStoreSwitch = 14308, eWindows10RS4Build = 17130 } KnownWindowsBuildNumbers; #define VALID_LOADLIBRARYEX_FLAGS ~(LOAD_LIBRARY_SEARCH_APPLICATION_DIR |\ LOAD_LIBRARY_SEARCH_DEFAULT_DIRS |\ LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |\ LOAD_LIBRARY_SEARCH_USER_DIRS |\ LOAD_WITH_ALTERED_SEARCH_PATH) static HMODULE gfnInternalLoadSystemLibrary(const LPCWSTR fileName, DWORD dwFlags) { LPWSTR systemFilePath = NULL; HMODULE hRet; static DWORD dwBuildNumber = 0; dwFlags &= VALID_LOADLIBRARYEX_FLAGS; if (dwBuildNumber == 0) { OSVERSIONINFOEXW osvi; DWORDLONG dwlConditionMask = VerSetConditionMask(0, VER_BUILDNUMBER, VER_GREATER_EQUAL); memset(&osvi, 0, sizeof(osvi)); osvi.dwBuildNumber = eWindows8Build; dwBuildNumber = VerifyVersionInfoW(&osvi, VER_BUILDNUMBER, dwlConditionMask) ? eWindows8Build : eWindows7Build; } if (dwBuildNumber >= eWindows8Build) { dwFlags |= LOAD_LIBRARY_SEARCH_SYSTEM32; } else // Win7 { dwFlags &= ~LOAD_LIBRARY_SEARCH_SYSTEM32; systemFilePath = gfnInternalCreateSystemFilePath(fileName); } hRet = LoadLibraryExW(systemFilePath ? systemFilePath : fileName, NULL, dwFlags); SafeLocalFree(systemFilePath); return hRet; } static BOOL gfnInternalCheckCert( const PCCERT_CONTEXT pCert, BOOL bRootCheck, LPCSTR name, size_t publicKeySize, const BYTE* publicKey) { if (name != NULL) { char szCertName[256] = ""; pfnCertGetNameStringA( pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, bRootCheck ? CERT_NAME_ISSUER_FLAG : 0, NULL, szCertName, sizeof(szCertName)); if (strcmp(szCertName, name) != 0) { return FALSE; } } if (publicKeySize > 0 && publicKey != NULL) { const CRYPT_BIT_BLOB* pPublicKey = &pCert->pCertInfo->SubjectPublicKeyInfo.PublicKey; if (pPublicKey->cbData != publicKeySize) { return FALSE; } else if (pPublicKey->cUnusedBits != 0) { return FALSE; } else if (memcmp(pPublicKey->pbData, publicKey, publicKeySize) != 0) { return FALSE; } } return TRUE; } static BOOL gfnInternalIsPeNvidiaSigned(PCCERT_CONTEXT pCertContext) { char szName[256]; szName[0] = 0; pfnCertGetNameStringA(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, szName, sizeof(szName)); return (_strnicmp(szName, NV_NVIDIA_CERT_NAME, strlen(NV_NVIDIA_CERT_NAME)) == 0); } static BOOL gfnInternalIsPeGfnSigned(PCCERT_CONTEXT pCertContext) { typedef struct tagCertInfo { LPCSTR subject; size_t publicKeySize; const BYTE* publicKey; } CertInfo; typedef struct tagCertChainInfo { const CertInfo certs[4]; } CertChainInfo; static const BYTE c_prodL1IntermediatePublicKey[] = { 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb9, 0x12, 0xcc, 0x1c, 0x99, 0x18, 0x50, 0xaa, 0x2f, 0x78, 0xfd, 0x89, 0x67, 0x8d, 0x54, 0xa9, 0x3d, 0x7f, 0x4d, 0xc0, 0x97, 0xa6, 0x76, 0xb0, 0xd4, 0x94, 0x8a, 0xe0, 0x98, 0xca, 0xc8, 0x9e, 0x0f, 0x21, 0xd8, 0xd4, 0x2a, 0x88, 0xa9, 0x0d, 0x53, 0xdb, 0xe6, 0x0a, 0x60, 0x82, 0xc9, 0xed, 0x2a, 0x8d, 0xf1, 0x5f, 0x9e, 0x78, 0xeb, 0x3b, 0x8d, 0x4a, 0xfc, 0xfb, 0x3d, 0xa6, 0xbf, 0x24, 0x3e, 0xc2, 0x6f, 0x61, 0x77, 0xa3, 0xc2, 0xfd, 0x5d, 0xa1, 0xe6, 0xb3, 0x99, 0x55, 0x1a, 0x51, 0xcc, 0xf1, 0x44, 0xcc, 0x59, 0x8a, 0x31, 0xba, 0x20, 0xb2, 0x63, 0x9f, 0x0c, 0xed, 0x62, 0xaa, 0xbe, 0x0e, 0xa0, 0x4e, 0xe7, 0x44, 0x6b, 0x77, 0xa1, 0xc7, 0xca, 0x88, 0x5b, 0x20, 0x26, 0x2d, 0x39, 0xaf, 0x1f, 0x58, 0x69, 0xce, 0x13, 0xd4, 0xe7, 0x75, 0xac, 0xb8, 0xc1, 0x44, 0xbe, 0xd9, 0x89, 0x97, 0xb7, 0x5c, 0xa7, 0xfd, 0x15, 0xdd, 0x0e, 0x3b, 0x4c, 0xe1, 0x21, 0xab, 0xd5, 0xe3, 0x61, 0x41, 0xaf, 0xcb, 0xcb, 0x64, 0x92, 0x1e, 0x4d, 0x49, 0x56, 0x21, 0x6a, 0x86, 0xc5, 0xd8, 0x93, 0x81, 0x13, 0xdc, 0x1a, 0xd0, 0x30, 0x5b, 0x08, 0xdd, 0x59, 0x10, 0xcb, 0xf1, 0x88, 0xfa, 0x2b, 0xf8, 0x27, 0x2e, 0x5f, 0xa1, 0x8b, 0x9a, 0xce, 0xda, 0x8f, 0xc6, 0x40, 0x71, 0x35, 0x5d, 0x53, 0xe8, 0xf9, 0xa2, 0x55, 0x03, 0x09, 0x55, 0x49, 0x3d, 0xce, 0x9f, 0xe4, 0x13, 0x6c, 0xe9, 0xe6, 0xb1, 0xff, 0xa4, 0xa0, 0x45, 0x8a, 0xd0, 0xeb, 0xae, 0xa6, 0x85, 0xcb, 0x59, 0x67, 0x1e, 0x53, 0xe3, 0x53, 0x4e, 0x02, 0xb5, 0xd9, 0x1a, 0x5f, 0x95, 0xec, 0x40, 0x6f, 0xd7, 0x36, 0x7b, 0x8d, 0xd9, 0x9e, 0xb8, 0xc3, 0xdf, 0xb0, 0x2b, 0x50, 0x05, 0xd5, 0x1f, 0x61, 0x3f, 0x1d, 0x68, 0xa1, 0x05, 0x73, 0x01, 0xa9, 0x41, 0x6b, 0xde, 0xcf, 0xc6, 0xe9, 0xce, 0xf6, 0xf8, 0x59, 0x6c, 0xd4, 0x56, 0xeb, 0xff, 0x02, 0xc9, 0x43, 0x19, 0xf6, 0xf3, 0x80, 0xc9, 0x13, 0x51, 0x6c, 0x3c, 0xe3, 0xaf, 0x7a, 0x1c, 0x36, 0x74, 0x1b, 0xb0, 0xa5, 0xf8, 0xed, 0xe2, 0x01, 0xf5, 0x20, 0xed, 0xa3, 0x9b, 0xed, 0xec, 0x84, 0x44, 0x61, 0xe0, 0x01, 0x5d, 0x80, 0xe9, 0x08, 0xfc, 0xed, 0x6e, 0x7f, 0x6a, 0x95, 0xfd, 0xce, 0xef, 0x84, 0xb1, 0x8d, 0x1b, 0x38, 0x38, 0x11, 0xd2, 0x60, 0x48, 0x27, 0x52, 0xe5, 0x5e, 0xc5, 0x75, 0xa5, 0x9c, 0xb8, 0xff, 0xea, 0x68, 0xbc, 0x11, 0xf4, 0x1e, 0x5d, 0x15, 0x4b, 0xe6, 0x78, 0x45, 0xb9, 0x33, 0x67, 0x8c, 0x8c, 0x0f, 0xf9, 0x0c, 0x72, 0xa4, 0xf2, 0x1a, 0xd7, 0x11, 0x4a, 0x22, 0xca, 0xb2, 0xda, 0xc7, 0x4c, 0x76, 0xe7, 0xb5, 0xf3, 0x7c, 0xe6, 0xd9, 0x74, 0xb5, 0x08, 0x4b, 0x0d, 0x43, 0x05, 0x17, 0x18, 0xb2, 0xd9, 0x21, 0x3b, 0x39, 0x52, 0x9d, 0x45, 0x04, 0x6a, 0xcd, 0xfe, 0x60, 0x04, 0xc1, 0xf1, 0xbc, 0x2a, 0x3a, 0x5f, 0xab, 0xa2, 0x8c, 0xd2, 0xcc, 0x35, 0xe6, 0xdb, 0x01, 0xb4, 0x4c, 0x95, 0x9b, 0x72, 0x7c, 0x86, 0x4c, 0x5d, 0x23, 0x40, 0x89, 0x7d, 0x1e, 0x0f, 0xb1, 0xa0, 0xc8, 0xe1, 0x50, 0x7e, 0xd9, 0x92, 0x48, 0xbc, 0x7f, 0xa9, 0xc5, 0xc8, 0x5c, 0x4b, 0xc6, 0x1d, 0x81, 0xc2, 0x01, 0xe3, 0xd4, 0x25, 0x6f, 0x99, 0x95, 0x8b, 0xc4, 0x97, 0xb9, 0xf5, 0x8e, 0x0a, 0xe9, 0xc4, 0x83, 0xac, 0xc2, 0x15, 0xca, 0x7c, 0x86, 0xd0, 0xa1, 0x96, 0xc8, 0xd1, 0x6e, 0x39, 0xb8, 0xa8, 0xdb, 0x93, 0xc4, 0x28, 0x15, 0xb3, 0x02, 0x5f, 0x46, 0xfc, 0xae, 0xf3, 0x35, 0x01, 0xa7, 0x43, 0x66, 0x3e, 0xc3, 0xf6, 0x45, 0x02, 0x03, 0x01, 0x00, 0x01 }; static const BYTE c_prodRootPublicKey[] = { 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb1, 0x4b, 0x86, 0xd8, 0x96, 0x29, 0x3a, 0x5d, 0xd7, 0xf0, 0x07, 0x07, 0xe7, 0x35, 0xbc, 0x3f, 0xe0, 0x0b, 0x01, 0x52, 0xc2, 0x43, 0x75, 0xfe, 0x74, 0x7a, 0x25, 0xfb, 0x55, 0x82, 0xe4, 0xa8, 0x04, 0x38, 0x57, 0xa0, 0x7d, 0x99, 0xae, 0xde, 0xa8, 0xe6, 0xcb, 0x59, 0x06, 0x4b, 0x65, 0x8a, 0x1c, 0x19, 0x46, 0xd5, 0x85, 0x62, 0xe6, 0x3a, 0xaa, 0xc6, 0xef, 0x46, 0xa2, 0xea, 0x53, 0x7f, 0x3c, 0xdc, 0x55, 0xf3, 0x6b, 0x40, 0xc1, 0xbb, 0x6b, 0xbb, 0xf4, 0x96, 0xe1, 0x96, 0x63, 0xe9, 0xd7, 0x1d, 0x8b, 0xc6, 0x1a, 0xff, 0x98, 0x28, 0x9c, 0x91, 0x90, 0x09, 0xad, 0x24, 0x37, 0x52, 0x4b, 0xa7, 0x75, 0x08, 0x8a, 0x8b, 0x35, 0x4d, 0x10, 0x37, 0x6c, 0x61, 0x8d, 0x1d, 0xb4, 0x9c, 0xee, 0xc9, 0x76, 0xe2, 0x0b, 0x7c, 0xcd, 0xc1, 0x60, 0x5c, 0xcf, 0x5f, 0x79, 0x07, 0x02, 0x3d, 0xa8, 0x9a, 0x6f, 0x4e, 0x18, 0xe5, 0x51, 0xdc, 0xbd, 0xef, 0xbb, 0xac, 0x51, 0xf6, 0x9d, 0xd2, 0x49, 0x10, 0xcc, 0x30, 0x0f, 0x43, 0xa0, 0x64, 0xf3, 0xbe, 0xfb, 0x3f, 0xbd, 0xa3, 0x54, 0x60, 0xf1, 0x91, 0x59, 0xd3, 0x60, 0x60, 0x7b, 0xb7, 0x49, 0xa1, 0x29, 0x47, 0xd5, 0x6f, 0xe8, 0x3f, 0xbb, 0x67, 0x91, 0x54, 0x87, 0x81, 0x75, 0x3b, 0x27, 0x46, 0xd0, 0x3b, 0xf6, 0x55, 0xf1, 0x9a, 0x48, 0x7f, 0x06, 0xee, 0x9c, 0x9b, 0xea, 0xa4, 0xe1, 0x23, 0x87, 0x00, 0xfe, 0x61, 0xca, 0x42, 0x9c, 0xb7, 0xdb, 0x5d, 0x85, 0xa8, 0x9d, 0x13, 0x15, 0x86, 0x30, 0xeb, 0x97, 0xc8, 0x31, 0xbe, 0x36, 0xb2, 0x11, 0x2d, 0xa8, 0x9f, 0x91, 0x31, 0x62, 0xa8, 0xec, 0x2d, 0x4b, 0x8f, 0xcc, 0x28, 0x2e, 0x49, 0x6e, 0xe2, 0xd3, 0x01, 0xf7, 0x00, 0x30, 0x1f, 0xfd, 0xb7, 0x56, 0xe1, 0x80, 0x6c, 0x56, 0x9c, 0xcb, 0x3c, 0xeb, 0x4e, 0x01, 0xf7, 0x6e, 0x16, 0x70, 0xb5, 0xce, 0x02, 0x7a, 0x30, 0xda, 0xea, 0x8e, 0xb3, 0x92, 0xd4, 0x20, 0xfd, 0xae, 0x64, 0x4a, 0xdf, 0x32, 0xe1, 0x44, 0xb0, 0xef, 0xae, 0x6d, 0x6a, 0x44, 0xa5, 0x8f, 0xc5, 0xf5, 0xd1, 0x4f, 0xa4, 0x5a, 0x4b, 0xa5, 0x93, 0xbc, 0x59, 0xc2, 0x6c, 0xb9, 0x84, 0x2c, 0xf2, 0x4f, 0xcf, 0x20, 0x14, 0xa0, 0xb1, 0xfa, 0x78, 0xa2, 0xe0, 0xc4, 0xda, 0x59, 0x04, 0x4d, 0x8f, 0xbd, 0xf4, 0x59, 0xdb, 0xf1, 0xc8, 0x34, 0x0b, 0x42, 0x69, 0x25, 0x00, 0xda, 0x65, 0xe3, 0x3d, 0x1e, 0x2e, 0x39, 0x50, 0xb8, 0x11, 0xa0, 0x72, 0x84, 0x9b, 0x12, 0x5d, 0x18, 0x16, 0x91, 0xfe, 0x0f, 0xf1, 0xac, 0x44, 0x11, 0xd2, 0x53, 0x41, 0x75, 0x62, 0x1e, 0xed, 0xea, 0x41, 0xdd, 0xe0, 0x07, 0x85, 0x43, 0x44, 0x61, 0x2b, 0x57, 0x30, 0xb8, 0x17, 0xd2, 0x2a, 0x5a, 0x0d, 0xed, 0xcd, 0xf4, 0x44, 0x05, 0x25, 0xb7, 0x05, 0x52, 0xa6, 0x1c, 0x74, 0xac, 0x5e, 0x1a, 0x8d, 0x61, 0xc1, 0x60, 0x6f, 0x9a, 0xff, 0xdf, 0x0c, 0xbd, 0xf6, 0x67, 0x53, 0x5e, 0x8d, 0x8b, 0x19, 0xda, 0x58, 0xe5, 0x72, 0xa8, 0xcf, 0x29, 0xf2, 0x95, 0x24, 0xdc, 0x53, 0x46, 0x6f, 0x7f, 0x0d, 0x4e, 0x56, 0x45, 0x28, 0xfa, 0x5d, 0x66, 0x41, 0x5d, 0x49, 0xa2, 0x02, 0x95, 0x20, 0x88, 0xd3, 0x22, 0x0e, 0x83, 0xe3, 0x75, 0xa0, 0xf9, 0xb8, 0x04, 0x25, 0x58, 0xea, 0xf6, 0xf8, 0x49, 0x1c, 0xd3, 0xc6, 0xe1, 0x85, 0xf1, 0x02, 0x5b, 0x9f, 0x63, 0x66, 0xd8, 0xbb, 0x74, 0x48, 0x89, 0xf6, 0xaf, 0xd2, 0x80, 0x11, 0x82, 0x84, 0x90, 0x39, 0xa0, 0xc1, 0xf6, 0x69, 0x12, 0xb7, 0x26, 0xf9, 0xe1, 0xa9, 0x2e, 0xe3, 0xb1, 0xe1, 0x03, 0xf8, 0xda, 0x13, 0x02, 0x03, 0x01, 0x00, 0x01 }; static const CertChainInfo c_validChains[] = { { { { "GFN SDK - Code Signing Leaf (prod)", 0, NULL }, { "GFN SDK - Code Signing Zone All CA 01", 0, NULL }, { "GFN SDK - Code Signing L1 Intermediate CA 01", sizeof(c_prodL1IntermediatePublicKey), c_prodL1IntermediatePublicKey }, { "GFN Root CA 01", sizeof(c_prodRootPublicKey), c_prodRootPublicKey } } } }; BOOL bMatch = FALSE; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_ENHKEY_USAGE EnhkeyUsage; CERT_USAGE_MATCH CertUsage; CERT_CHAIN_PARA ChainPara; EnhkeyUsage.cUsageIdentifier = 0; EnhkeyUsage.rgpszUsageIdentifier = NULL; CertUsage.dwType = USAGE_MATCH_TYPE_AND; CertUsage.Usage = EnhkeyUsage; ChainPara.cbSize = sizeof(CERT_CHAIN_PARA); ChainPara.RequestedUsage = CertUsage; // There should be only one chain with 4 certificates in it. BOOL bResult = pfnCertGetCertificateChain( HCCE_LOCAL_MACHINE, pCertContext, NULL, NULL, &ChainPara, 0, NULL, &pChainContext); if (bResult && pChainContext->cChain == 1 && pChainContext->rgpChain[0]->cElement == _countof(c_validChains[0].certs)) { for (size_t i = 0; i < _countof(c_validChains); i++) { for (size_t j = 0; j < _countof(c_validChains[i].certs); j++) { const CertInfo* pCertInfo = &c_validChains[i].certs[j]; const PCCERT_CONTEXT pCurrentCertContext = pChainContext->rgpChain[0]->rgpElement[j]->pCertContext; bMatch = gfnInternalCheckCert( pCurrentCertContext, FALSE, pCertInfo->subject, pCertInfo->publicKeySize, pCertInfo->publicKey); if (!bMatch) { break; } if (pfnCertVerifyTimeValidity(NULL, pCurrentCertContext->pCertInfo) != 0) { bMatch = FALSE; break; } } if (bMatch) { break; } } } if (pChainContext != NULL) { pfnCertFreeCertificateChain(pChainContext); } if (bMatch) { SetLastError(ERROR_SUCCESS); } return bMatch; } #define gfnInternalGetModule(moduleName, hModule) (((NULL == hModule) && (NULL == (hModule = gfnInternalLoadSystemLibrary(moduleName, 0)))) ? FALSE : TRUE) #define gfnInternalGetProc(hModule, procName, proc) (((NULL == proc) && (NULL == (*((FARPROC*)&proc) = GetProcAddress(hModule, procName)))) ? FALSE : TRUE) static HMODULE hModCryptNet = NULL; static HMODULE hModCryptBase = NULL; static HMODULE hModWinTrust = NULL; static HMODULE hModGDI32 = NULL; static HMODULE hModAdvapi32 = NULL; static HMODULE hModShell32 = NULL; #define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING) static BOOL gfnInteralPreloadCryptDlls() { BOOL ret = gfnInternalGetModule(L"cryptnet.dll", hModCryptNet); if (!ret && GetLastError() != ERROR_MOD_NOT_FOUND) { ret = TRUE; } gfnInternalGetModule(L"cryptbase.dll", hModCryptBase); return ret; } static BOOL gfnInternalGetSignerInfoTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, FILETIME* pFiletime) { #ifndef szOID_RSA_signingTime #define szOID_RSA_signingTime "1.2.840.113549.1.9.5" #endif DWORD dwSize = sizeof(FILETIME), n; for (n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++) { if (lstrcmpA(pSignerInfo->AuthAttrs.rgAttr[n].pszObjId, szOID_RSA_signingTime)) continue; return pfnCryptDecodeObjectEx(ENCODING, szOID_RSA_signingTime, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData, 0, NULL, (PVOID)pFiletime, &dwSize); } return FALSE; } static BOOL gfnInternalVerifyTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, HCERTSTORE hStore, FILETIME* pFiletime) { BOOL bReturn = FALSE; BOOL bResult; DWORD dwSize; DWORD n; PCMSG_SIGNER_INFO pCounterSignerInfo = NULL; PCCERT_CONTEXT pCertContext = NULL; CERT_INFO CertInfo; FILETIME ft; for (n = 0; n < pSignerInfo->UnauthAttrs.cAttr && !bReturn; ++n) { if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RSA_counterSign)) { continue; } bResult = pfnCryptDecodeObjectEx(ENCODING, PKCS7_SIGNER_INFO, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (PVOID)&pCounterSignerInfo, &dwSize); if (!bResult) { goto VerifyTimeStampSignerInfoDone; } CertInfo.Issuer = pCounterSignerInfo->Issuer; CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber; pCertContext = pfnCertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL); if (!pCertContext) { goto VerifyTimeStampSignerInfoDone; } // We check the timestamp here. We allow a grace period of 2 seconds between signing and countersigning timestamp. // FILETIME is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). // So, we add the value (2 * 10^9) / 100 which is 2 * 10^7. This equals adding 2 sec to the time. if (gfnInternalGetSignerInfoTimeStamp(pCounterSignerInfo, &ft)) { ULARGE_INTEGER t1, t2; t1.LowPart = pFiletime->dwLowDateTime; t1.HighPart = pFiletime->dwHighDateTime; t2.LowPart = ft.dwLowDateTime; t2.HighPart = ft.dwHighDateTime; bReturn = t1.QuadPart <= (t2.QuadPart + 2 * 10000000ull); } pfnCertFreeCertificateContext(pCertContext); } VerifyTimeStampSignerInfoDone: SafeLocalFree(pCounterSignerInfo); return bReturn; } // // ASN.1 Parsing for the timestamps // http://luca.ntop.org/Teaching/Appunti/asn1.html // static DWORD gfnInternalPopASN1Sequence(const PBYTE pBuffer, PBYTE pTag, PBYTE* ppSeq, PDWORD pdwSeqSize) { DWORD dwPosition = 0, dwSeqSize = 0; *pTag = pBuffer[dwPosition++]; dwSeqSize = pBuffer[dwPosition++]; if (dwSeqSize & 0x80) { int i = dwSeqSize & 0x7F; dwSeqSize = 0; while (i-- > 0) dwSeqSize = (dwSeqSize << 8) | pBuffer[dwPosition++]; } *pdwSeqSize = dwSeqSize; *ppSeq = &pBuffer[dwPosition]; return dwPosition + dwSeqSize; } static ULONGLONG gfnInternalParseASN1Timestamp(const char* pTimestamp, size_t timestampSize) { const char FORMAT_PREFIX[] = "YYYYMMDDhhmmss"; size_t i; ULONGLONG time = 0; for (i = 0; i < sizeof(FORMAT_PREFIX) - 1; i++) { if (i >= timestampSize || pTimestamp[i] < '0' || pTimestamp[i] > '9') { return 0ULL; } time = time * 10 + pTimestamp[i] - '0'; } if (i >= timestampSize && pTimestamp[i] == '.') { const char FORMAT_MS[] = "sss"; size_t j; for (i++, j = 0; j < sizeof(FORMAT_MS) - 1; i++, j++) { if (i >= timestampSize || pTimestamp[i] < '0' || pTimestamp[i] > '9') { return 0ULL; } } } if (i >= timestampSize || pTimestamp[i] != 'Z') { return 0ULL; } return time; } static ULONGLONG gfnInternalParseASN1TimestampOID(const PBYTE pBuffer, DWORD dwBufferSize, BOOL bFoundOid) { const BYTE OID_TIMESAMP_TOKEN[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x04 }; const BYTE TAG_OID = 0x06; const BYTE TAG_OCTET_STRING = 0x04; const BYTE TAG_GENERALIZED_TIME = 0x18; DWORD dwPosition = 0; while (dwPosition < dwBufferSize) { PBYTE pCurrentSeq; DWORD dwSeqSize; BYTE Tag; dwPosition += gfnInternalPopASN1Sequence(&pBuffer[dwPosition], &Tag, &pCurrentSeq, &dwSeqSize); if (Tag & 0x20) { ULONGLONG t = gfnInternalParseASN1TimestampOID(pCurrentSeq, dwSeqSize, bFoundOid); if (t) return t; continue; } Tag &= 0x1F; if (!bFoundOid) { if (Tag == TAG_OID && dwSeqSize == sizeof(OID_TIMESAMP_TOKEN) && !memcmp(pCurrentSeq, OID_TIMESAMP_TOKEN, dwSeqSize)) { dwPosition += gfnInternalPopASN1Sequence(&pBuffer[dwPosition], &Tag, &pCurrentSeq, &dwSeqSize); if (Tag & 0x20) gfnInternalPopASN1Sequence(pCurrentSeq, &Tag, &pCurrentSeq, &dwSeqSize); if (Tag == TAG_OCTET_STRING) return gfnInternalParseASN1TimestampOID(pCurrentSeq, dwSeqSize, TRUE); } } else if (Tag == TAG_GENERALIZED_TIME) { return gfnInternalParseASN1Timestamp((const char*)pCurrentSeq, (size_t)dwSeqSize); } } return 0ULL; } static BOOL gfnInternalVerifyTimeStampRFC3161(PCMSG_SIGNER_INFO pSignerInfo, FILETIME* pFiletime) { BOOL bReturn = FALSE; BOOL bResult; DWORD dwSize; DWORD n; PCRYPT_CONTENT_INFO pCounterSignerInfo = NULL; ULONGLONG tSign, tCounterSign; for (n = 0; n < pSignerInfo->UnauthAttrs.cAttr; ++n) { #ifndef szOID_RFC3161_counterSign #define szOID_RFC3161_counterSign "1.3.6.1.4.1.311.3.3.1" #endif if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_RFC3161_counterSign)) { continue; } bResult = pfnCryptDecodeObjectEx(ENCODING, PKCS_CONTENT_INFO, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData, pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (PVOID)&pCounterSignerInfo, &dwSize); if (bResult) { tCounterSign = gfnInternalParseASN1TimestampOID(pCounterSignerInfo->Content.pbData, pCounterSignerInfo->Content.cbData, FALSE); if (tCounterSign > 0) { SYSTEMTIME st; FileTimeToSystemTime(pFiletime, &st); tSign = st.wSecond * 1ull + st.wMinute * 100ull + st.wHour * 10000ull + st.wDay * 1000000ull + st.wMonth * 100000000ull + st.wYear * 10000000000ull; // We allow a grace period of 2 seconds between signing and countersigning timestamp. bReturn = tSign <= (tCounterSign + 2); } } break; } SafeLocalFree(pCounterSignerInfo); return bReturn; } #ifndef WINTRUST_ACTION_GENERIC_VERIFY_V2 #define WINTRUST_ACTION_GENERIC_VERIFY_V2 \ { 0xaac56b, \ 0xcd44, \ 0x11d0, \ { 0x8c, 0xc2, 0x0, 0xc0, 0x4f, 0xc2, 0x95, 0xee } \ } #endif static LONG gfnInternalVerifySingleSignature(LPCWSTR fileName, DWORD index) { WINTRUST_FILE_INFO FileData; WINTRUST_DATA WinTrustData; GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2; UNREFERENCED_PARAMETER(index); memset(&FileData, 0, sizeof(FileData)); FileData.cbStruct = sizeof(WINTRUST_FILE_INFO); FileData.pcwszFilePath = fileName; memset(&WinTrustData, 0, sizeof(WinTrustData)); WinTrustData.cbStruct = sizeof(WinTrustData); WinTrustData.dwUIChoice = WTD_UI_NONE; WinTrustData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN; WinTrustData.dwUnionChoice = WTD_CHOICE_FILE; WinTrustData.dwStateAction = WTD_STATEACTION_IGNORE; WinTrustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; WinTrustData.pFile = &FileData; return pfnWinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &WVTPolicyGUID, &WinTrustData); } static BOOL gfnInternalCryptMsgGetParam( HCRYPTMSG hCryptMsg, PCMSG_SIGNER_INFO* ppSignerInfo, DWORD* pdwSignerInfo) { BOOL bResult = pfnCryptMsgGetParam( hCryptMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, pdwSignerInfo); if (!bResult || *pdwSignerInfo == 0) { return FALSE; } *ppSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, *pdwSignerInfo); if (*ppSignerInfo == NULL) { return FALSE; } bResult = pfnCryptMsgGetParam( hCryptMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)*ppSignerInfo, pdwSignerInfo); if (!bResult) { LocalFree(*ppSignerInfo); *ppSignerInfo = NULL; } return bResult; } static CONST UCHAR SG_ProtoCoded[] = { 0x30, 0x82, }; static CONST UCHAR SG_SignedData[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, }; #define XCH_WORD_LITEND(num) \ (WORD)(((((WORD)num) & 0xFF00) >> 8) | ((((WORD)num) & 0x00FF) << 8)) #define _8BYTE_ALIGN(offset, base) \ (((offset + base + 7) & 0xFFFFFFF8L) - (base & 0xFFFFFFF8L)) // Big Endian -> Little Endian BOOL gfnInternalVerifyFileSignature(LPCWSTR fileName, SignatureType signatureType) { HCERTSTORE hStore = NULL; HCRYPTMSG hMsg = NULL; PCMSG_SIGNER_INFO pSignerInfo = NULL; DWORD dwSignerInfo; BOOL bResult = FALSE; DWORD dwError = ERROR_SUCCESS; DWORD n; DWORD index = 0; PBYTE pbCurrData = NULL; DWORD cbCurrData = 0x00; SetLastError(ERROR_SUCCESS); if (!gfnInternalFileExists(fileName)) { dwError = ERROR_FILE_NOT_FOUND; goto verifyFileSignatureDone; } if (!gfnInternalGetModule(L"crypt32.dll", hModCrypt32) || !gfnInternalGetProc(hModCrypt32, "CryptMsgClose", pfnCryptMsgClose) || !gfnInternalGetProc(hModCrypt32, "CertCloseStore", pfnCertCloseStore) || !gfnInternalGetProc(hModCrypt32, "CertFreeCertificateContext", pfnCertFreeCertificateContext) || !gfnInternalGetProc(hModCrypt32, "CertFindCertificateInStore", pfnCertFindCertificateInStore) || !gfnInternalGetProc(hModCrypt32, "CryptMsgGetParam", pfnCryptMsgGetParam) || !gfnInternalGetProc(hModCrypt32, "CryptQueryObject", pfnCryptQueryObject) || !gfnInternalGetProc(hModCrypt32, "CertGetNameStringA", pfnCertGetNameStringA) || !gfnInternalGetProc(hModCrypt32, "CryptMsgOpenToDecode", pfnCryptMsgOpenToDecode) || !gfnInternalGetProc(hModCrypt32, "CryptMsgUpdate", pfnCryptMsgUpdate) || !gfnInternalGetProc(hModCrypt32, "CryptDecodeObjectEx", pfnCryptDecodeObjectEx) || !gfnInternalGetProc(hModCrypt32, "CertGetIssuerCertificateFromStore", pfnCertGetIssuerCertificateFromStore) || !gfnInternalGetProc(hModCrypt32, "CertOpenStore", pfnCertOpenStore) || !gfnInternalGetProc(hModCrypt32, "CertGetCertificateChain", pfnCertGetCertificateChain) || !gfnInternalGetProc(hModCrypt32, "CertFreeCertificateChain", pfnCertFreeCertificateChain) || !gfnInternalGetProc(hModCrypt32, "CertVerifyTimeValidity", pfnCertVerifyTimeValidity) || !gfnInteralPreloadCryptDlls()) { dwError = ERROR_MOD_NOT_FOUND; goto verifyFileSignatureDone; } bResult = pfnCryptQueryObject(CERT_QUERY_OBJECT_FILE, fileName, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, &hStore, &hMsg, NULL); if (!bResult) { dwError = GetLastError(); goto verifyFileSignatureDone; } // Extract the primary signer bResult = gfnInternalCryptMsgGetParam(hMsg, &pSignerInfo, &dwSignerInfo); if (!bResult) { dwError = GetLastError(); goto verifyFileSignatureDone; } bResult = gfnInternalVerifyFileSignatureInfo(pSignerInfo, hStore, fileName, index, signatureType); if (bResult) { dwError = ERROR_SUCCESS; goto verifyFileSignatureDone; } // The remaining signatures (if any) are stored in szOID_NESTED_SIGNATURE attribute in UnauthAttrs bResult = FALSE; for (n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++) { if (!lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId, szOID_NESTED_SIGNATURE)) { break; } } if (n >= pSignerInfo->UnauthAttrs.cAttr) { goto verifyFileSignatureDone; } pbCurrData = pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData; cbCurrData = pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData; // All nested signatures are stored sequentially in an 8 bytes aligned way. // According to the size of primary signature parse the nested signatures one by one while (pbCurrData > (BYTE*)pSignerInfo && pbCurrData < (BYTE*)pSignerInfo + dwSignerInfo) { HCRYPTMSG hNestedMsg = pfnCryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, 0, NULL, 0); if (!hNestedMsg) // Fatal Error { goto verifyFileSignatureDone; } // NOTE: The size in 30 82 xx doesnt contain its own size. // HEAD: // 0000: 30 82 04 df ; SEQUENCE (4df Bytes) // 0004: 06 09 ; OBJECT_ID(9 Bytes) // 0006: | 2a 86 48 86 f7 0d 01 07 02 // | ; 1.2.840.113549.1.7.2 PKCS 7 SignedData if (memcmp(pbCurrData + 0, SG_ProtoCoded, sizeof(SG_ProtoCoded)) || memcmp(pbCurrData + 6, SG_SignedData, sizeof(SG_SignedData))) { break; } cbCurrData = XCH_WORD_LITEND(*(WORD*)(pbCurrData + 2)) + 4; PBYTE pbNextData = pbCurrData; pbNextData += _8BYTE_ALIGN(cbCurrData, (ULONG_PTR)pbCurrData); bResult = pfnCryptMsgUpdate(hNestedMsg, pbCurrData, cbCurrData, TRUE); pbCurrData = pbNextData; if (bResult) { PCMSG_SIGNER_INFO pNestedSignerInfo = NULL; DWORD dwNestedObjSize = 0; bResult = gfnInternalCryptMsgGetParam(hNestedMsg, &pNestedSignerInfo, &dwNestedObjSize); if (bResult) { HCERTSTORE hNestedCertStoreHandle = pfnCertOpenStore( CERT_STORE_PROV_MSG, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0, hNestedMsg); if (hNestedCertStoreHandle != NULL) { bResult = gfnInternalVerifyFileSignatureInfo( pNestedSignerInfo, hNestedCertStoreHandle, fileName, ++index, signatureType); pfnCertCloseStore(hNestedCertStoreHandle, 0); } } } pfnCryptMsgClose(hNestedMsg); if (bResult) { dwError = ERROR_SUCCESS; goto verifyFileSignatureDone; } } verifyFileSignatureDone: SafeLocalFree(pSignerInfo); if (hStore != NULL) { pfnCertCloseStore(hStore, 0); } if (hMsg != NULL) { pfnCryptMsgClose(hMsg); } SetLastError(dwError); return bResult; } static BOOL gfnInternalVerifyFileSignatureInfo( PCMSG_SIGNER_INFO pSignerInfo, HCERTSTORE hStore, LPCWSTR fileName, DWORD index, SignatureType signatureType) { CERT_INFO CertInfo; PCCERT_CONTEXT pCertContext = NULL; BOOL bResult = FALSE; DWORD dwError = ERROR_SUCCESS; FILETIME signingtime; CertInfo.Issuer = pSignerInfo->Issuer; CertInfo.SerialNumber = pSignerInfo->SerialNumber; pCertContext = pfnCertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&CertInfo, NULL); if (!pCertContext) { dwError = GetLastError(); goto verifyFileSignatureInfoDone; } if (signatureType == SignatureTypeNvidia) { if (!gfnInternalIsPeNvidiaSigned(pCertContext)) { goto verifyFileSignatureInfoDone; } dwError = GetLastError(); if (ERROR_SUCCESS != dwError) { goto verifyFileSignatureInfoDone; } if (!gfnInternalGetSignerInfoTimeStamp(pSignerInfo, &signingtime)) { memset(&signingtime, 0, sizeof(signingtime)); } bResult = gfnInternalVerifyTimeStampSignerInfo(pSignerInfo, hStore, &signingtime) || gfnInternalVerifyTimeStampRFC3161(pSignerInfo, &signingtime); if (!bResult) { dwError = GetLastError(); if (ERROR_SUCCESS == dwError) dwError = (DWORD)TRUST_E_TIME_STAMP; goto verifyFileSignatureInfoDone; } } else if (signatureType == SignatureTypeGfn) { if (!gfnInternalIsPeGfnSigned(pCertContext)) { dwError = GetLastError(); goto verifyFileSignatureInfoDone; } } bResult = FALSE; if (!gfnInternalGetModule(L"wintrust.dll", hModWinTrust) || !gfnInternalGetProc(hModWinTrust, "WinVerifyTrust", pfnWinVerifyTrust)) { dwError = ERROR_MOD_NOT_FOUND; goto verifyFileSignatureInfoDone; } else { dwError = (DWORD)gfnInternalVerifySingleSignature(fileName, index); if (dwError == ERROR_SUCCESS) { bResult = TRUE; } } verifyFileSignatureInfoDone: if (pCertContext != NULL) { pfnCertFreeCertificateContext(pCertContext); } SetLastError(dwError); return bResult; }