XinJiangBBH_LBE/Plugins/Streamline/Source/StreamlineRHI/Private/StreamlineSecureLoad.cpp

481 lines
17 KiB
C++

/*
* Copyright (c) 2022 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#include "StreamlineRHIPrivate.h"
#include "Misc/Paths.h"
#define _UNICODE 1
#define UNICODE 1
#include <tchar.h>
//#include <stdio.h>
//#include <stdlib.h>
#include "Windows/AllowWindowsPlatformTypes.h"
THIRD_PARTY_INCLUDES_START
#if (NTDDI_VERSION < NTDDI_WIN8)
#pragma push_macro("NTDDI_VERSION")
#undef NTDDI_VERSION
#define NTDDI_VERSION NTDDI_WIN8
//this header cannot be directly imported because of current _WIN32_WINNT less then 0x0602 (the value assigned in UEBuildWindows.cs:139)
//the macro code added from couple interface declarations, it doesn't affect to any imported function
#include <shobjidl.h>
#include <windows.h>
#include <Softpub.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <inttypes.h>
#pragma pop_macro("NTDDI_VERSION")
#else
#include <shobjidl.h>
#endif
THIRD_PARTY_INCLUDES_END
#define GetProc(hModule, procName, proc) (((NULL == proc) && (NULL == (*((FARPROC*)&proc) = GetProcAddress(hModule, procName)))) ? FALSE : TRUE)
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 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* 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 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 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 LONG(WINAPI* PfnWinVerifyTrust)(
IN HWND hwnd,
IN GUID* pgActionID,
IN LPVOID pWVTData
);
static PfnWinVerifyTrust pfnWinVerifyTrust = NULL;
bool isSignedByNVIDIA(const wchar_t* pathToFile)
{
bool valid = false;
// Now let's make sure this is actually signed by NVIDIA
DWORD dwEncoding, dwContentType, dwFormatType;
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
DWORD dwSignerInfo;
if (!pfnCertOpenStore)
{
// We only support Win10+ so we can search for module in system32 directly
auto hModCrypt32 = LoadLibraryExW(L"crypt32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!hModCrypt32 ||
!GetProc(hModCrypt32, "CryptMsgClose", pfnCryptMsgClose) ||
!GetProc(hModCrypt32, "CertOpenStore", pfnCertOpenStore) ||
!GetProc(hModCrypt32, "CertCloseStore", pfnCertCloseStore) ||
!GetProc(hModCrypt32, "CertFreeCertificateContext", pfnCertFreeCertificateContext) ||
!GetProc(hModCrypt32, "CertFindCertificateInStore", pfnCertFindCertificateInStore) ||
!GetProc(hModCrypt32, "CryptMsgGetParam", pfnCryptMsgGetParam) ||
!GetProc(hModCrypt32, "CryptMsgUpdate", pfnCryptMsgUpdate) ||
!GetProc(hModCrypt32, "CryptMsgOpenToDecode", pfnCryptMsgOpenToDecode) ||
!GetProc(hModCrypt32, "CryptQueryObject", pfnCryptQueryObject) ||
!GetProc(hModCrypt32, "CryptDecodeObjectEx", pfnCryptDecodeObjectEx))
{
UE_LOG(LogStreamlineRHI, Log, TEXT("Unable to obtain crypt32.dll functionality - cannot validate digital signature on SL plugins."));
return false;
}
}
// Get message handle and store handle from the signed file.
auto bResult = pfnCryptQueryObject(CERT_QUERY_OBJECT_FILE,
pathToFile,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&dwEncoding,
&dwContentType,
&dwFormatType,
&hStore,
&hMsg,
NULL);
if (!bResult)
{
return false;
}
// Get signer information size.
bResult = pfnCryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
NULL,
&dwSignerInfo);
if (!bResult)
{
return false;
}
// Allocate memory for signer information.
pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
if (!pSignerInfo)
{
return false;
}
// Get Signer Information.
bResult = pfnCryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
(PVOID)pSignerInfo,
&dwSignerInfo);
if (!bResult)
{
LocalFree(pSignerInfo);
return false;
}
// Look for nested signature
constexpr const char* kOID_NESTED_SIGNATURE = "1.3.6.1.4.1.311.2.4.1";
for (DWORD i = 0; i < pSignerInfo->UnauthAttrs.cAttr; i++)
{
if (strcmp(kOID_NESTED_SIGNATURE, pSignerInfo->UnauthAttrs.rgAttr[i].pszObjId) == 0)
{
HCRYPTMSG hMsg2 = pfnCryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL);
if (hMsg2)
{
if (pfnCryptMsgUpdate(hMsg2, pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->pbData, pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->cbData,TRUE))
{
/*DWORD*/ dwSignerInfo = 0;
pfnCryptMsgGetParam(hMsg2, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo);
if (dwSignerInfo != 0)
{
PCMSG_SIGNER_INFO pSignerInfo2 = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
if (pSignerInfo2)
{
if (pfnCryptMsgGetParam(hMsg2, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo2, &dwSignerInfo))
{
CRYPT_DATA_BLOB c7Data;
c7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->pbData;
c7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->cbData;
auto hStore2 = pfnCertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 0, &c7Data);
if (!hStore2)
{
LocalFree(pSignerInfo2);
return false;
}
CERT_INFO CertInfo{};
PCCERT_CONTEXT pCertContext = NULL;
// Search for the signer certificate in the temporary certificate store.
CertInfo.Issuer = pSignerInfo2->Issuer;
CertInfo.SerialNumber = pSignerInfo2->SerialNumber;
pCertContext = pfnCertFindCertificateInStore(hStore2,
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
LocalFree(pSignerInfo2);
pfnCertCloseStore(hStore2, CERT_CLOSE_STORE_FORCE_FLAG);
return false;
}
void* decodedPublicKey{};
DWORD decodedPublicLength{};
if (pfnCryptDecodeObjectEx((PKCS_7_ASN_ENCODING | X509_ASN_ENCODING),
CNG_RSA_PUBLIC_KEY_BLOB,
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
CRYPT_ENCODE_ALLOC_FLAG,
NULL,
&decodedPublicKey,
&decodedPublicLength))
{
static uint8_t s_rsaStreamlinePublicKey[] =
{
0x52, 0x53, 0x41, 0x31, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc1, 0x8e, 0x40, 0xc3, 0xf5,
0xa7, 0x01, 0x9a, 0x37, 0x6b, 0x47, 0xa8, 0x58, 0xe8, 0xbe, 0xe3, 0x55, 0x0a, 0xee, 0x0f, 0x0d,
0x32, 0xaa, 0x12, 0xf9, 0x56, 0x7f, 0x5d, 0xfd, 0x82, 0x09, 0x33, 0x21, 0x42, 0xf2, 0xe8, 0x74,
0x98, 0x51, 0xb3, 0x88, 0x74, 0xcd, 0x00, 0x6e, 0xb1, 0x08, 0x10, 0x4b, 0xf1, 0xda, 0xd6, 0x97,
0x87, 0xd4, 0x9c, 0xb1, 0x13, 0xa8, 0xa2, 0x86, 0x15, 0x0e, 0xc1, 0xa5, 0x9c, 0xe5, 0x90, 0x9b,
0xbe, 0x69, 0xdc, 0x6a, 0x82, 0xbe, 0xb4, 0x4b, 0x4b, 0xfa, 0x95, 0x8e, 0xc1, 0xfc, 0x2b, 0x61,
0x95, 0xd1, 0x91, 0xed, 0xeb, 0x87, 0xe7, 0x09, 0x84, 0x05, 0x41, 0x03, 0xb0, 0x2d, 0xd4, 0x39,
0x7f, 0x62, 0x06, 0x56, 0x33, 0x93, 0x7e, 0x77, 0x54, 0x06, 0x77, 0x2b, 0x75, 0x05, 0xbc, 0xeb,
0x98, 0xea, 0xc0, 0xa2, 0xca, 0x98, 0x86, 0x0f, 0x10, 0x65, 0xde, 0x19, 0x2c, 0xa6, 0x1e, 0x93,
0xb0, 0x92, 0x5d, 0x5f, 0x5b, 0x6f, 0x79, 0x6d, 0x2c, 0x76, 0xa6, 0x67, 0x50, 0xaa, 0x8f, 0xc2,
0x4c, 0xf1, 0x08, 0xf7, 0xc0, 0x27, 0x29, 0xf0, 0x68, 0xf4, 0x64, 0x00, 0x1c, 0xb6, 0x28, 0x1e,
0x25, 0xb8, 0xf3, 0x8a, 0xd1, 0x6e, 0x65, 0xa3, 0x61, 0x9d, 0xf8, 0xca, 0x4a, 0x41, 0x60, 0x80,
0x62, 0xdf, 0x41, 0xa4, 0x8b, 0xdc, 0x97, 0xee, 0xeb, 0x64, 0x6f, 0xe4, 0x8f, 0x4b, 0xdf, 0x24,
0x01, 0x80, 0xd9, 0xb4, 0x0a, 0xec, 0x0d, 0x3e, 0xb7, 0x76, 0xba, 0xe9, 0xe7, 0xde, 0x07, 0xdd,
0x30, 0xc8, 0x4a, 0x14, 0x79, 0xec, 0x15, 0xed, 0x5c, 0xc6, 0xcc, 0xd4, 0xe6, 0x06, 0x3c, 0x42,
0x92, 0x10, 0xf7, 0x7c, 0x80, 0x1e, 0x78, 0xd3, 0xb4, 0x9f, 0xc2, 0x3b, 0xa8, 0x7b, 0xa0, 0xe3,
0x0c, 0xd9, 0xad, 0x2e, 0x09, 0x72, 0xe2, 0x8f, 0x54, 0x28, 0x87, 0x3c, 0xba, 0x7c, 0x97, 0x80,
0xdc, 0x09, 0xb5, 0x12, 0x34, 0x78, 0x9a, 0x26, 0xd0, 0xa3, 0xa7, 0xa7, 0x1b, 0x25, 0x19, 0xe5,
0x6e, 0xbe, 0xd7, 0x5a, 0x91, 0x32, 0xc4, 0xa9, 0x2f, 0xcc, 0xd5, 0x82, 0x4b, 0x5b, 0x9f, 0xad,
0xf3, 0x2f, 0xed, 0x4f, 0x33, 0xe1, 0x50, 0x33, 0xd6, 0x90, 0x79, 0x22, 0xe5, 0x1c, 0xc7, 0x35,
0xe7, 0x58, 0xe6, 0xb4, 0x8b, 0xc4, 0x28, 0x20, 0xec, 0xca, 0x70, 0xbb, 0x02, 0x1b, 0x48, 0xd8,
0x84, 0x51, 0x24, 0x33, 0x2a, 0x08, 0xb1, 0x15, 0x4e, 0xbc, 0x88, 0xa5, 0xe1, 0x37, 0x76, 0x70,
0xe6, 0xdf, 0x3f, 0x73, 0xfd, 0x0d, 0x8a, 0xd9, 0x0d, 0xa5, 0x35, 0xb2, 0xb4, 0x01, 0x42, 0x96,
0xc4, 0xaa, 0x1c, 0xeb, 0x68, 0x62, 0x36, 0xbf, 0xef, 0x5e, 0x2a, 0x3d, 0x18, 0x91, 0x8b, 0x92,
0x0a, 0x1e, 0xce, 0x98, 0x5b, 0x7b, 0x64, 0x42, 0x09, 0xb0, 0x1d
};
valid = decodedPublicLength == sizeof(s_rsaStreamlinePublicKey) && memcmp(s_rsaStreamlinePublicKey, decodedPublicKey, decodedPublicLength) == 0;
LocalFree(decodedPublicKey);
}
pfnCertFreeCertificateContext(pCertContext);
pfnCertCloseStore(hStore2, CERT_CLOSE_STORE_FORCE_FLAG);
}
LocalFree(pSignerInfo2);
}
}
}
pfnCryptMsgClose(hMsg2);
}
break;
}
}
LocalFree(pSignerInfo);
pfnCryptMsgClose(hMsg);
pfnCertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG);
return valid;
}
//! See https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program--verifying-the-signature-of-a-pe-file
bool slVerifyEmbeddedSignature(const FString& InPathToBinary)
{
FString PathToBinary = InPathToBinary;
FPaths::ConvertRelativePathToFull(PathToBinary);
FPaths::MakePlatformFilename(PathToBinary);
FTCHARToWChar WPathToBinary = StringCast<WIDECHAR>(*PathToBinary);
const wchar_t* pathToFile = WPathToBinary.Get();
bool valid = true;
LONG lStatus = {};
// Initialize the WINTRUST_FILE_INFO structure.
WINTRUST_FILE_INFO FileData;
memset(&FileData, 0, sizeof(FileData));
FileData.cbStruct = sizeof(WINTRUST_FILE_INFO);
FileData.pcwszFilePath = pathToFile;
FileData.hFile = NULL;
FileData.pgKnownSubject = NULL;
if (!pfnWinVerifyTrust)
{
// We only support Win10+ so we can search for module in system32 directly
auto hModWintrust = LoadLibraryExW(L"wintrust.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!hModWintrust || !GetProc(hModWintrust, "WinVerifyTrust", pfnWinVerifyTrust))
{
//printf("Unable to obtain wintrust.dll functionality - cannot validate digital signature on SL plugins.");
UE_LOG(LogStreamlineRHI, Log, TEXT("Unable to obtain wintrust.dll functionality - cannot validate digital signature on SL plugins."));
return false;
}
}
/*
WVTPolicyGUID specifies the policy to apply on the file
WINTRUST_ACTION_GENERIC_VERIFY_V2 policy checks:
1) The certificate used to sign the file chains up to a root
certificate located in the trusted root certificate store. This
implies that the identity of the publisher has been verified by
a certification authority.
2) In cases where user interface is displayed (which this example
does not do), WinVerifyTrust will check for whether the
end entity certificate is stored in the trusted publisher store,
implying that the user trusts content from this publisher.
3) The end entity certificate has sufficient permission to sign
code, as indicated by the presence of a code signing EKU or no
EKU.
*/
GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_DATA WinTrustData;
// Initialize the WinVerifyTrust input data structure.
// Default all fields to 0.
memset(&WinTrustData, 0, sizeof(WinTrustData));
WinTrustData.cbStruct = sizeof(WinTrustData);
// Use default code signing EKU.
WinTrustData.pPolicyCallbackData = NULL;
// No data to pass to SIP.
WinTrustData.pSIPClientData = NULL;
// Disable WVT UI.
WinTrustData.dwUIChoice = WTD_UI_NONE;
// No revocation checking.
WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
// Verify an embedded signature on a file.
WinTrustData.dwUnionChoice = WTD_CHOICE_FILE;
// Verify action.
WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY;
// Verification sets this value.
WinTrustData.hWVTStateData = NULL;
// Not used.
WinTrustData.pwszURLReference = NULL;
// This is not applicable if there is no UI because it changes
// the UI to accommodate running applications instead of
// installing applications.
WinTrustData.dwUIContext = 0;
// Set pFile.
WinTrustData.pFile = &FileData;
// First verify the primary signature (index 0) to determine how many secondary signatures
// are present. We use WSS_VERIFY_SPECIFIC and dwIndex to do this, also setting
// WSS_GET_SECONDARY_SIG_COUNT to have the number of secondary signatures returned.
WINTRUST_SIGNATURE_SETTINGS SignatureSettings = {};
CERT_STRONG_SIGN_PARA StrongSigPolicy = {};
SignatureSettings.cbStruct = sizeof(WINTRUST_SIGNATURE_SETTINGS);
SignatureSettings.dwFlags = WSS_GET_SECONDARY_SIG_COUNT | WSS_VERIFY_SPECIFIC;
SignatureSettings.dwIndex = 0;
WinTrustData.pSignatureSettings = &SignatureSettings;
StrongSigPolicy.cbSize = sizeof(CERT_STRONG_SIGN_PARA);
StrongSigPolicy.dwInfoChoice = CERT_STRONG_SIGN_OID_INFO_CHOICE;
static char OID[] = szOID_CERT_STRONG_SIGN_OS_CURRENT;
StrongSigPolicy.pszOID = OID;
WinTrustData.pSignatureSettings->pCryptoPolicy = &StrongSigPolicy;
// WinVerifyTrust verifies signatures as specified by the GUID and Wintrust_Data.
lStatus = pfnWinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
// First signature must be validated by the OS
valid = lStatus == ERROR_SUCCESS;
if (!valid)
{
//printf("File '%S' is NOT correctly signed - Streamline will not load unsecured modules", pathToFile);
UE_LOG(LogStreamlineRHI, Log, TEXT("File '%s' is NOT correctly signed - Streamline will not load unsecured modules for UE_BUILD_SHIPPING configurations."), WCHAR_TO_TCHAR(pathToFile));
}
else
{
// Now there has to be a secondary one
valid &= WinTrustData.pSignatureSettings->cSecondarySigs == 1;
if (!valid)
{
UE_LOG(LogStreamlineRHI, Log, TEXT("File '%s' does not have the secondary NVIDIA signature - Streamline will not load unsecured modules for UE_BUILD_SHIPPING configurations."), WCHAR_TO_TCHAR(pathToFile));
}
else
{
// The secondary signature must be from NVIDIA
valid &= isSignedByNVIDIA(pathToFile);
if (valid)
{
UE_LOG(LogStreamlineRHI, Log, TEXT("File '%s' is signed by NVIDIA and the signature was verified."), WCHAR_TO_TCHAR(pathToFile));
}
else
{
UE_LOG(LogStreamlineRHI, Log, TEXT("File '%s' is NOT correctly signed - Streamline will not load unsecured modules for UE_BUILD_SHIPPING configurations."), WCHAR_TO_TCHAR(pathToFile));
}
}
}
// Any hWVTStateData must be released by a call with close.
WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE;
lStatus = pfnWinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData);
return valid;
}
#include "Windows/HideWindowsPlatformTypes.h"