1366 lines
46 KiB
C
1366 lines
46 KiB
C
// 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 <Shlobj.h>
|
|
#include <WinTrust.h>
|
|
#include <wchar.h> // Needed for conversion to WCHAR for Win32 APIs that require it
|
|
#include <windows.h>
|
|
#include <strsafe.h>
|
|
|
|
#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;
|
|
}
|