326 lines
12 KiB
C++
326 lines
12 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: vertrust.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define WIN // scope W32 API
|
|
#define MSI // scope MSI API
|
|
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
|
|
#include "setup.h" // for itvEnum
|
|
#include "common.h"
|
|
|
|
// package trust
|
|
#include "wintrust.h"
|
|
#include "softpub.h"
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// CRYPTO API -- delay load
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
#define CRYPT32_DLL "crypt32.dll"
|
|
|
|
#define CRYPTOAPI_CertDuplicateCertificateContext "CertDuplicateCertificateContext"
|
|
typedef PCCERT_CONTEXT (WINAPI* PFnCertDuplicateCertificateContext)(PCCERT_CONTEXT pCertContext);
|
|
|
|
#define CRYPTOAPI_CertCompareCertificate "CertCompareCertificate"
|
|
typedef BOOL (WINAPI* PFnCertCompareCertificate)(DWORD dwCertEncodingType, PCERT_INFO pCertId1, PCERT_INFO pCertId2);
|
|
|
|
#define CRYPTOAPI_CertFreeCertificateContext "CertFreeCertificateContext"
|
|
typedef BOOL (WINAPI* PFnCertFreeCertificateContext)(PCCERT_CONTEXT pCertContext);
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// WINTRUST API -- delay load
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
#define WINTRUST_DLL "wintrust.dll"
|
|
|
|
#define WINTRUSTAPI_WinVerifyTrust "WinVerifyTrust"
|
|
typedef HRESULT (WINAPI *PFnWinVerifyTrust)(HWND hwnd, GUID *pgActionID, WINTRUST_DATA *pWinTrustData);
|
|
|
|
#define WINTRUSTAPI_WTHelperProvDataFromStateData "WTHelperProvDataFromStateData"
|
|
typedef PCRYPT_PROVIDER_DATA (WINAPI *PFnWTHelperProvDataFromStateData)(HANDLE hStateData);
|
|
|
|
#define WINTRUSTAPI_WTHelperGetProvSignerFromChain "WTHelperGetProvSignerFromChain"
|
|
typedef PCRYPT_PROVIDER_SGNR (WINAPI *PFnWTHelperGetProvSignerFromChain)(PCRYPT_PROVIDER_DATA pProvData, DWORD idxSigner, BOOL fCounterSigner, DWORD idxCounterSigner);
|
|
|
|
#define WINTRUSTAPI_WTHelperGetProvCertFromChain "WTHelperGetProvCertFromChain"
|
|
typedef PCRYPT_PROVIDER_CERT (WINAPI* PFnWTHelperGetProvCertFromChain)(PCRYPT_PROVIDER_SGNR pSgnr, DWORD idxCert);
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// download provider
|
|
//--------------------------------------------------------------------------------------
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IsFileTrusted
|
|
//
|
|
itvEnum IsFileTrusted(LPCWSTR lpwFile, HWND hwndParent, DWORD dwUIChoice, bool *pfIsSigned, PCCERT_CONTEXT *ppcSigner)
|
|
{
|
|
char szDebugOutput[MAX_STR_LENGTH] = {0};
|
|
|
|
itvEnum itv = itvUnTrusted;
|
|
|
|
if (pfIsSigned)
|
|
*pfIsSigned = false;
|
|
if (ppcSigner)
|
|
*ppcSigner = 0;
|
|
|
|
GUID guidAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;
|
|
|
|
WINTRUST_FILE_INFO sWintrustFileInfo;
|
|
WINTRUST_DATA sWintrustData;
|
|
HRESULT hr;
|
|
|
|
memset((void*)&sWintrustFileInfo, 0x00, sizeof(WINTRUST_FILE_INFO)); // zero out
|
|
memset((void*)&sWintrustData, 0x00, sizeof(WINTRUST_DATA)); // zero out
|
|
|
|
sWintrustFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
|
|
sWintrustFileInfo.pcwszFilePath = lpwFile;
|
|
sWintrustFileInfo.hFile = NULL;
|
|
|
|
sWintrustData.cbStruct = sizeof(WINTRUST_DATA);
|
|
sWintrustData.dwUIChoice = dwUIChoice;
|
|
sWintrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
|
|
sWintrustData.dwUnionChoice = WTD_CHOICE_FILE;
|
|
sWintrustData.pFile = &sWintrustFileInfo;
|
|
sWintrustData.dwStateAction = (ppcSigner) ? WTD_STATEACTION_VERIFY : 0;
|
|
|
|
HMODULE hWinTrust = LoadLibrary(WINTRUST_DLL);
|
|
if (!hWinTrust)
|
|
{
|
|
// WinTrust is unavailable on the machine
|
|
return itvWintrustNotOnMachine;
|
|
}
|
|
PFnWinVerifyTrust pfnWinVerifyTrust = (PFnWinVerifyTrust)GetProcAddress(hWinTrust, WINTRUSTAPI_WinVerifyTrust);
|
|
PFnWTHelperProvDataFromStateData pfnWTHelperProvDataFromStateData= (PFnWTHelperProvDataFromStateData)GetProcAddress(hWinTrust, WINTRUSTAPI_WTHelperProvDataFromStateData);
|
|
PFnWTHelperGetProvSignerFromChain pfnWTHelperGetProvSignerFromChain = (PFnWTHelperGetProvSignerFromChain)GetProcAddress(hWinTrust, WINTRUSTAPI_WTHelperGetProvSignerFromChain);
|
|
PFnWTHelperGetProvCertFromChain pfnWTHelperGetProvCertFromChain = (PFnWTHelperGetProvCertFromChain)GetProcAddress(hWinTrust, WINTRUSTAPI_WTHelperGetProvCertFromChain);
|
|
if (!pfnWinVerifyTrust || !pfnWTHelperProvDataFromStateData || !pfnWTHelperGetProvSignerFromChain || !pfnWTHelperGetProvCertFromChain)
|
|
{
|
|
// WinTrust is unavailable on the machine
|
|
FreeLibrary(hWinTrust);
|
|
return itvWintrustNotOnMachine;
|
|
}
|
|
|
|
hr = pfnWinVerifyTrust(/* UI Window Handle */ (dwUIChoice == WTD_UI_NONE) ? (HWND)INVALID_HANDLE_VALUE : hwndParent, &guidAction, &sWintrustData);
|
|
DebugMsg("[WVT] WVT returned 0x%X\n", hr);
|
|
|
|
itv = (TRUST_E_PROVIDER_UNKNOWN == hr) ? itvWintrustNotOnMachine : ((S_OK == hr) ? itvTrusted : itvUnTrusted);
|
|
|
|
if (itvWintrustNotOnMachine == itv)
|
|
{
|
|
// release state data
|
|
sWintrustData.dwUIChoice = WTD_UI_NONE;
|
|
sWintrustData.dwStateAction = WTD_STATEACTION_CLOSE;
|
|
pfnWinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &guidAction, &sWintrustData);
|
|
|
|
FreeLibrary(hWinTrust);
|
|
return itv; // return immediately
|
|
}
|
|
|
|
if (pfIsSigned)
|
|
*pfIsSigned = (TRUST_E_NOSIGNATURE == hr) ? false : true;
|
|
|
|
if (TRUST_E_NOSIGNATURE == hr)
|
|
{
|
|
// release state data
|
|
sWintrustData.dwUIChoice = WTD_UI_NONE;
|
|
sWintrustData.dwStateAction = WTD_STATEACTION_CLOSE;
|
|
pfnWinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &guidAction, &sWintrustData);
|
|
|
|
FreeLibrary(hWinTrust);
|
|
return itv;
|
|
}
|
|
|
|
if (ppcSigner)
|
|
{
|
|
CRYPT_PROVIDER_DATA const *psProvData = NULL;
|
|
CRYPT_PROVIDER_SGNR *psProvSigner = NULL;
|
|
CRYPT_PROVIDER_CERT *psProvCert = NULL;
|
|
|
|
// grab the provider data
|
|
psProvData = pfnWTHelperProvDataFromStateData(sWintrustData.hWVTStateData);
|
|
if (psProvData)
|
|
{
|
|
// grab the signer data from the CRYPT_PROV_DATA
|
|
psProvSigner = pfnWTHelperGetProvSignerFromChain((PCRYPT_PROVIDER_DATA)psProvData, 0 /*first signer*/, FALSE /* not a counter signer */, 0);
|
|
if (psProvSigner)
|
|
{
|
|
// grab the signer cert from CRYPT_PROV_SGNR (pos 0 = signer cert; pos csCertChain-1 = root cert)
|
|
psProvCert = pfnWTHelperGetProvCertFromChain(psProvSigner, 0);
|
|
}
|
|
}
|
|
|
|
if (!psProvCert)
|
|
{
|
|
// some failure in obtaining the signer cert data
|
|
*ppcSigner = 0;
|
|
}
|
|
else
|
|
{
|
|
// duplicate the cert
|
|
HMODULE hCrypt32 = LoadLibrary(CRYPT32_DLL);
|
|
if (hCrypt32)
|
|
{
|
|
PFnCertDuplicateCertificateContext pfnCertDuplicateCertificateContext = (PFnCertDuplicateCertificateContext)GetProcAddress(hCrypt32, CRYPTOAPI_CertDuplicateCertificateContext);
|
|
if (pfnCertDuplicateCertificateContext)
|
|
*ppcSigner = pfnCertDuplicateCertificateContext(psProvCert->pCert);
|
|
FreeLibrary(hCrypt32);
|
|
}
|
|
}
|
|
|
|
// release state data
|
|
sWintrustData.dwUIChoice = WTD_UI_NONE;
|
|
sWintrustData.dwStateAction = WTD_STATEACTION_CLOSE;
|
|
pfnWinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &guidAction, &sWintrustData);
|
|
}
|
|
|
|
FreeLibrary(hWinTrust);
|
|
return itv;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IsPackageTrusted
|
|
//
|
|
|
|
itvEnum IsPackageTrusted(LPCSTR szSetupExe, LPCSTR szPackage, HWND hwndParent)
|
|
{
|
|
WCHAR *szwSetup = 0;
|
|
WCHAR *szwPackage = 0;
|
|
int cchWide = 0;
|
|
|
|
bool fPackageIsTrusted = false;
|
|
bool fSetupExeIsSigned = false;
|
|
bool fPackageIsSigned = false;
|
|
itvEnum itv = itvUnTrusted;
|
|
|
|
DWORD dwUILevel = 0;
|
|
|
|
char szDebugOutput[MAX_STR_LENGTH] = {0};
|
|
|
|
PCCERT_CONTEXT pcExeSigner = 0;
|
|
PCCERT_CONTEXT pcMsiSigner = 0;
|
|
|
|
HMODULE hCrypt32 = LoadLibrary(CRYPT32_DLL);
|
|
if (!hCrypt32)
|
|
{
|
|
// no crypto on the machine
|
|
return itvWintrustNotOnMachine;
|
|
}
|
|
PFnCertCompareCertificate pfnCertCompareCertificate = (PFnCertCompareCertificate)GetProcAddress(hCrypt32, CRYPTOAPI_CertCompareCertificate);
|
|
PFnCertFreeCertificateContext pfnCertFreeCertificateContext = (PFnCertFreeCertificateContext)GetProcAddress(hCrypt32, CRYPTOAPI_CertFreeCertificateContext);
|
|
if (!pfnCertCompareCertificate || !pfnCertFreeCertificateContext)
|
|
{
|
|
// no crypt on the machine
|
|
FreeLibrary(hCrypt32);
|
|
return itvWintrustNotOnMachine;
|
|
}
|
|
|
|
// convert szSetupExe to WIDE
|
|
cchWide = MultiByteToWideChar(CP_ACP, 0, szSetupExe, -1, 0, 0);
|
|
szwSetup = new WCHAR[cchWide];
|
|
if (!szwSetup)
|
|
{
|
|
// out of memory
|
|
FreeLibrary(hCrypt32);
|
|
return itvUnTrusted;
|
|
}
|
|
if (0 == MultiByteToWideChar(CP_ACP, 0, szSetupExe, -1, szwSetup, cchWide))
|
|
{
|
|
// failed to convert string
|
|
FreeLibrary(hCrypt32);
|
|
delete [] szwSetup;
|
|
return itvUnTrusted;
|
|
}
|
|
|
|
//
|
|
// step 1: silently call WinVerifyTrust on szSetupExe, ignore return value - except for ivtWintrustNotOnMachine
|
|
//
|
|
|
|
DebugMsg("[WVT] step 1: silently call WinVerifyTrust on szSetupExe, ignoring return value\n");
|
|
|
|
if (itvWintrustNotOnMachine == (itv = IsFileTrusted(szwSetup, hwndParent, WTD_UI_NONE, &fSetupExeIsSigned, &pcExeSigner)))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
DebugMsg("[WVT] fSetupExeIsSigned = %s\n", fSetupExeIsSigned ? "TRUE" : "FALSE");
|
|
|
|
// convert szPackage to WIDE
|
|
cchWide = MultiByteToWideChar(CP_ACP, 0, szPackage, -1, 0, 0);
|
|
szwPackage = new WCHAR[cchWide];
|
|
if (!szwPackage)
|
|
{
|
|
// out of memory
|
|
FreeLibrary(hCrypt32);
|
|
return itvUnTrusted;
|
|
}
|
|
if (0 == MultiByteToWideChar(CP_ACP, 0, szPackage, -1, szwPackage, cchWide))
|
|
{
|
|
// failed to convert string
|
|
FreeLibrary(hCrypt32);
|
|
return itvUnTrusted;
|
|
}
|
|
|
|
//
|
|
// step 2: silently call WinVerifyTrust on szPackage, ignore return value - except for ivtWintrustNotOnMachine
|
|
//
|
|
|
|
if (fSetupExeIsSigned)
|
|
{
|
|
DebugMsg("[WVT] step2: silently call WinVerifyTrust on szPackage, ignoring return value\n");
|
|
if (itvWintrustNotOnMachine == (itv = IsFileTrusted(szwPackage, hwndParent, WTD_UI_NONE, &fPackageIsSigned, &pcMsiSigner)))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
DebugMsg("[WVT] fPackageIsSigned = %s\n", fPackageIsSigned ? "TRUE" : "FALSE");
|
|
}
|
|
|
|
//
|
|
// step 3: call WinVerifyTrust on szPackage, return value matters; use proper UI-level
|
|
//
|
|
|
|
if ( !fSetupExeIsSigned // exe is not signed
|
|
|| !fPackageIsSigned // package is not signed
|
|
|| !pcExeSigner // exe signer cert is missing
|
|
|| !pcMsiSigner // package signer cert is missing
|
|
|| !pfnCertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pcExeSigner->pCertInfo, pcMsiSigner->pCertInfo)) // signed by different certs
|
|
{
|
|
// always show UI
|
|
DebugMsg("[WVT] step3: last call to WinVerifyTrust using full UI\n");
|
|
dwUILevel = WTD_UI_ALL;
|
|
}
|
|
else
|
|
{
|
|
// show UI only if bad
|
|
DebugMsg("[WVT] step3: last call to WinVerifyTrust showing UI only if something is wrong\n");
|
|
dwUILevel = WTD_UI_NOGOOD;
|
|
}
|
|
|
|
itv = IsFileTrusted(szwPackage, hwndParent, dwUILevel, NULL, NULL);
|
|
|
|
//
|
|
// cleanup
|
|
//
|
|
|
|
CleanUp:
|
|
if (szwPackage)
|
|
delete [] szwPackage;
|
|
if (szwSetup)
|
|
delete [] szwSetup;
|
|
|
|
if (pcExeSigner)
|
|
pfnCertFreeCertificateContext(pcExeSigner);
|
|
if (pcMsiSigner)
|
|
pfnCertFreeCertificateContext(pcMsiSigner);
|
|
|
|
FreeLibrary(hCrypt32);
|
|
|
|
return itv;
|
|
} |