diff options
| author | Bob Arnson <bob@firegiant.com> | 2021-01-31 19:28:47 -0500 |
|---|---|---|
| committer | Bob Arnson <bob@firegiant.com> | 2021-01-31 19:35:27 -0500 |
| commit | f1f1a124df59e8639c2bcbfa7d3a4b37fb348bb7 (patch) | |
| tree | 6866de4e995d3ae55affff6c70e3d93175583c65 /src/engine/cache.cpp | |
| parent | 0e41fb8be9690ca7b81ec4df0734ead1978a9cf0 (diff) | |
| download | wix-f1f1a124df59e8639c2bcbfa7d3a4b37fb348bb7.tar.gz wix-f1f1a124df59e8639c2bcbfa7d3a4b37fb348bb7.tar.bz2 wix-f1f1a124df59e8639c2bcbfa7d3a4b37fb348bb7.zip | |
Remove Burn Authenticode
Fixes https://github.com/wixtoolset/issues/issues/6301
Diffstat (limited to 'src/engine/cache.cpp')
| -rw-r--r-- | src/engine/cache.cpp | 252 |
1 files changed, 5 insertions, 247 deletions
diff --git a/src/engine/cache.cpp b/src/engine/cache.cpp index 315281bc..92a79eb9 100644 --- a/src/engine/cache.cpp +++ b/src/engine/cache.cpp | |||
| @@ -94,15 +94,6 @@ static HRESULT VerifyHash( | |||
| 94 | __in_z LPCWSTR wzUnverifiedPayloadPath, | 94 | __in_z LPCWSTR wzUnverifiedPayloadPath, |
| 95 | __in HANDLE hFile | 95 | __in HANDLE hFile |
| 96 | ); | 96 | ); |
| 97 | static HRESULT VerifyPayloadWithCatalog( | ||
| 98 | __in BURN_PAYLOAD* pPayload, | ||
| 99 | __in_z LPCWSTR wzUnverifiedPayloadPath, | ||
| 100 | __in HANDLE hFile | ||
| 101 | ); | ||
| 102 | static HRESULT VerifyPayloadAgainstChain( | ||
| 103 | __in BURN_PAYLOAD* pPayload, | ||
| 104 | __in PCCERT_CHAIN_CONTEXT pChainContext | ||
| 105 | ); | ||
| 106 | 97 | ||
| 107 | 98 | ||
| 108 | extern "C" HRESULT CacheInitialize( | 99 | extern "C" HRESULT CacheInitialize( |
| @@ -189,7 +180,7 @@ LExit: | |||
| 189 | } | 180 | } |
| 190 | 181 | ||
| 191 | extern "C" HRESULT CacheEnsureWorkingFolder( | 182 | extern "C" HRESULT CacheEnsureWorkingFolder( |
| 192 | __in_z LPCWSTR wzBundleId, | 183 | __in_z_opt LPCWSTR wzBundleId, |
| 193 | __deref_out_z_opt LPWSTR* psczWorkingFolder | 184 | __deref_out_z_opt LPWSTR* psczWorkingFolder |
| 194 | ) | 185 | ) |
| 195 | { | 186 | { |
| @@ -964,56 +955,6 @@ LExit: | |||
| 964 | return hr; | 955 | return hr; |
| 965 | } | 956 | } |
| 966 | 957 | ||
| 967 | extern "C" HRESULT CacheVerifyPayloadSignature( | ||
| 968 | __in BURN_PAYLOAD* pPayload, | ||
| 969 | __in_z LPCWSTR wzUnverifiedPayloadPath, | ||
| 970 | __in HANDLE hFile | ||
| 971 | ) | ||
| 972 | { | ||
| 973 | HRESULT hr = S_OK; | ||
| 974 | LONG er = ERROR_SUCCESS; | ||
| 975 | |||
| 976 | GUID guidAuthenticode = WINTRUST_ACTION_GENERIC_VERIFY_V2; | ||
| 977 | WINTRUST_FILE_INFO wfi = { }; | ||
| 978 | WINTRUST_DATA wtd = { }; | ||
| 979 | CRYPT_PROVIDER_DATA* pProviderData = NULL; | ||
| 980 | CRYPT_PROVIDER_SGNR* pSigner = NULL; | ||
| 981 | |||
| 982 | // Verify the payload assuming online. | ||
| 983 | wfi.cbStruct = sizeof(wfi); | ||
| 984 | wfi.pcwszFilePath = wzUnverifiedPayloadPath; | ||
| 985 | wfi.hFile = hFile; | ||
| 986 | |||
| 987 | wtd.cbStruct = sizeof(wtd); | ||
| 988 | wtd.dwUnionChoice = WTD_CHOICE_FILE; | ||
| 989 | wtd.pFile = &wfi; | ||
| 990 | wtd.dwStateAction = WTD_STATEACTION_VERIFY; | ||
| 991 | wtd.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; | ||
| 992 | wtd.dwUIChoice = WTD_UI_NONE; | ||
| 993 | |||
| 994 | er = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &guidAuthenticode, &wtd); | ||
| 995 | if (er) | ||
| 996 | { | ||
| 997 | // Verify the payload assuming offline. | ||
| 998 | wtd.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; | ||
| 999 | |||
| 1000 | er = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &guidAuthenticode, &wtd); | ||
| 1001 | ExitOnWin32Error(er, hr, "Failed authenticode verification of payload: %ls", wzUnverifiedPayloadPath); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | pProviderData = WTHelperProvDataFromStateData(wtd.hWVTStateData); | ||
| 1005 | ExitOnNullWithLastError(pProviderData, hr, "Failed to get provider state from authenticode certificate."); | ||
| 1006 | |||
| 1007 | pSigner = WTHelperGetProvSignerFromChain(pProviderData, 0, FALSE, 0); | ||
| 1008 | ExitOnNullWithLastError(pSigner, hr, "Failed to get signer chain from authenticode certificate."); | ||
| 1009 | |||
| 1010 | hr = VerifyPayloadAgainstChain(pPayload, pSigner->pChainContext); | ||
| 1011 | ExitOnFailure(hr, "Failed to verify expected payload against actual certificate chain."); | ||
| 1012 | |||
| 1013 | LExit: | ||
| 1014 | return hr; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | extern "C" void CacheCleanup( | 958 | extern "C" void CacheCleanup( |
| 1018 | __in BOOL fPerMachine, | 959 | __in BOOL fPerMachine, |
| 1019 | __in_z LPCWSTR wzBundleId | 960 | __in_z LPCWSTR wzBundleId |
| @@ -1098,7 +1039,7 @@ extern "C" void CacheUninitialize() | |||
| 1098 | // Internal functions. | 1039 | // Internal functions. |
| 1099 | 1040 | ||
| 1100 | static HRESULT CalculateWorkingFolder( | 1041 | static HRESULT CalculateWorkingFolder( |
| 1101 | __in_z LPCWSTR /*wzBundleId*/, | 1042 | __in_z_opt LPCWSTR /*wzBundleId*/, |
| 1102 | __deref_out_z LPWSTR* psczWorkingFolder | 1043 | __deref_out_z LPWSTR* psczWorkingFolder |
| 1103 | ) | 1044 | ) |
| 1104 | { | 1045 | { |
| @@ -1387,18 +1328,7 @@ static HRESULT VerifyThenTransferPayload( | |||
| 1387 | ExitWithLastError(hr, "Failed to open payload in working path: %ls", wzUnverifiedPayloadPath); | 1328 | ExitWithLastError(hr, "Failed to open payload in working path: %ls", wzUnverifiedPayloadPath); |
| 1388 | } | 1329 | } |
| 1389 | 1330 | ||
| 1390 | // If the payload has a certificate root public key identifier provided, verify the certificate. | 1331 | if (pPayload->pbHash) // the payload should have a hash we can use to verify it. |
| 1391 | if (pPayload->pbCertificateRootPublicKeyIdentifier) | ||
| 1392 | { | ||
| 1393 | hr = CacheVerifyPayloadSignature(pPayload, wzUnverifiedPayloadPath, hFile); | ||
| 1394 | ExitOnFailure(hr, "Failed to verify payload signature: %ls", wzCachedPath); | ||
| 1395 | } | ||
| 1396 | else if (pPayload->pCatalog) // If catalog files are specified, attempt to verify the file with a catalog file | ||
| 1397 | { | ||
| 1398 | hr = VerifyPayloadWithCatalog(pPayload, wzUnverifiedPayloadPath, hFile); | ||
| 1399 | ExitOnFailure(hr, "Failed to verify payload signature: %ls", wzCachedPath); | ||
| 1400 | } | ||
| 1401 | else if (pPayload->pbHash) // the payload should have a hash we can use to verify it. | ||
| 1402 | { | 1332 | { |
| 1403 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, wzUnverifiedPayloadPath, hFile); | 1333 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, wzUnverifiedPayloadPath, hFile); |
| 1404 | ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath); | 1334 | ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath); |
| @@ -1466,18 +1396,7 @@ static HRESULT VerifyFileAgainstPayload( | |||
| 1466 | ExitOnRootFailure(hr, "Failed to open payload at path: %ls", wzVerifyPath); | 1396 | ExitOnRootFailure(hr, "Failed to open payload at path: %ls", wzVerifyPath); |
| 1467 | } | 1397 | } |
| 1468 | 1398 | ||
| 1469 | // If the payload has a certificate root public key identifier provided, verify the certificate. | 1399 | if (pPayload->pbHash) // the payload should have a hash we can use to verify it. |
| 1470 | if (pPayload->pbCertificateRootPublicKeyIdentifier) | ||
| 1471 | { | ||
| 1472 | hr = CacheVerifyPayloadSignature(pPayload, wzVerifyPath, hFile); | ||
| 1473 | ExitOnFailure(hr, "Failed to verify signature of payload: %ls", pPayload->sczKey); | ||
| 1474 | } | ||
| 1475 | else if (pPayload->pCatalog) // If catalog files are specified, attempt to verify the file with a catalog file | ||
| 1476 | { | ||
| 1477 | hr = VerifyPayloadWithCatalog(pPayload, wzVerifyPath, hFile); | ||
| 1478 | ExitOnFailure(hr, "Failed to verify catalog signature of payload: %ls", pPayload->sczKey); | ||
| 1479 | } | ||
| 1480 | else if (pPayload->pbHash) // the payload should have a hash we can use to verify it. | ||
| 1481 | { | 1400 | { |
| 1482 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, wzVerifyPath, hFile); | 1401 | hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, wzVerifyPath, hFile); |
| 1483 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); | 1402 | ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey); |
| @@ -1517,7 +1436,7 @@ LExit: | |||
| 1517 | 1436 | ||
| 1518 | static HRESULT ResetPathPermissions( | 1437 | static HRESULT ResetPathPermissions( |
| 1519 | __in BOOL fPerMachine, | 1438 | __in BOOL fPerMachine, |
| 1520 | __in LPCWSTR wzPath | 1439 | __in_z LPCWSTR wzPath |
| 1521 | ) | 1440 | ) |
| 1522 | { | 1441 | { |
| 1523 | HRESULT hr = S_OK; | 1442 | HRESULT hr = S_OK; |
| @@ -1863,164 +1782,3 @@ LExit: | |||
| 1863 | 1782 | ||
| 1864 | return hr; | 1783 | return hr; |
| 1865 | } | 1784 | } |
| 1866 | |||
| 1867 | static HRESULT VerifyPayloadWithCatalog( | ||
| 1868 | __in BURN_PAYLOAD* pPayload, | ||
| 1869 | __in_z LPCWSTR wzUnverifiedPayloadPath, | ||
| 1870 | __in HANDLE hFile | ||
| 1871 | ) | ||
| 1872 | { | ||
| 1873 | HRESULT hr = S_FALSE; | ||
| 1874 | DWORD er = ERROR_SUCCESS; | ||
| 1875 | WINTRUST_DATA WinTrustData = { }; | ||
| 1876 | WINTRUST_CATALOG_INFO WinTrustCatalogInfo = { }; | ||
| 1877 | GUID gSubSystemDriver = WINTRUST_ACTION_GENERIC_VERIFY_V2; | ||
| 1878 | LPWSTR sczLowerCaseFile = NULL; | ||
| 1879 | LPWSTR pCurrent = NULL; | ||
| 1880 | LPWSTR sczName = NULL; | ||
| 1881 | DWORD dwHashSize = 0; | ||
| 1882 | DWORD dwTagSize; | ||
| 1883 | LPBYTE pbHash = NULL; | ||
| 1884 | |||
| 1885 | // Get lower case file name. Older operating systems need a lower case file | ||
| 1886 | // to match in the catalog | ||
| 1887 | hr = StrAllocString(&sczLowerCaseFile, wzUnverifiedPayloadPath, 0); | ||
| 1888 | ExitOnFailure(hr, "Failed to allocate memory"); | ||
| 1889 | |||
| 1890 | // Go through each character doing the lower case of each letter | ||
| 1891 | pCurrent = sczLowerCaseFile; | ||
| 1892 | while ('\0' != *pCurrent) | ||
| 1893 | { | ||
| 1894 | *pCurrent = (WCHAR)_tolower(*pCurrent); | ||
| 1895 | pCurrent++; | ||
| 1896 | } | ||
| 1897 | |||
| 1898 | // Get file hash | ||
| 1899 | CryptCATAdminCalcHashFromFileHandle(hFile, &dwHashSize, pbHash, 0); | ||
| 1900 | er = ::GetLastError(); | ||
| 1901 | if (ERROR_INSUFFICIENT_BUFFER == er) | ||
| 1902 | { | ||
| 1903 | pbHash = (LPBYTE)MemAlloc(dwHashSize, TRUE); | ||
| 1904 | if (!CryptCATAdminCalcHashFromFileHandle(hFile, &dwHashSize, pbHash, 0)) | ||
| 1905 | { | ||
| 1906 | ExitWithLastError(hr, "Failed to get file hash."); | ||
| 1907 | } | ||
| 1908 | } | ||
| 1909 | else | ||
| 1910 | { | ||
| 1911 | ExitOnWin32Error(er, hr, "Failed to get file hash."); | ||
| 1912 | } | ||
| 1913 | |||
| 1914 | // Make the hash into a string. This is the member tag for the catalog | ||
| 1915 | dwTagSize = (dwHashSize * 2) + 1; | ||
| 1916 | hr = StrAlloc(&sczName, dwTagSize); | ||
| 1917 | ExitOnFailure(hr, "Failed to allocate string."); | ||
| 1918 | hr = StrHexEncode(pbHash, dwHashSize, sczName, dwTagSize); | ||
| 1919 | ExitOnFailure(hr, "Failed to encode file hash."); | ||
| 1920 | |||
| 1921 | // Set up the WinVerifyTrust structures assuming online. | ||
| 1922 | WinTrustData.cbStruct = sizeof(WINTRUST_DATA); | ||
| 1923 | WinTrustData.dwUIChoice = WTD_UI_NONE; | ||
| 1924 | WinTrustData.dwUnionChoice = WTD_CHOICE_CATALOG; | ||
| 1925 | WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY; | ||
| 1926 | WinTrustData.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; | ||
| 1927 | WinTrustData.pCatalog = &WinTrustCatalogInfo; | ||
| 1928 | |||
| 1929 | WinTrustCatalogInfo.cbStruct = sizeof(WINTRUST_CATALOG_INFO); | ||
| 1930 | WinTrustCatalogInfo.pbCalculatedFileHash = pbHash; | ||
| 1931 | WinTrustCatalogInfo.cbCalculatedFileHash = dwHashSize; | ||
| 1932 | WinTrustCatalogInfo.hMemberFile = hFile; | ||
| 1933 | WinTrustCatalogInfo.pcwszMemberTag = sczName; | ||
| 1934 | WinTrustCatalogInfo.pcwszMemberFilePath = sczLowerCaseFile; | ||
| 1935 | WinTrustCatalogInfo.pcwszCatalogFilePath = pPayload->pCatalog->sczLocalFilePath; | ||
| 1936 | |||
| 1937 | hr = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &gSubSystemDriver, &WinTrustData); | ||
| 1938 | if (hr) | ||
| 1939 | { | ||
| 1940 | // Set up the WinVerifyTrust structures assuming online. | ||
| 1941 | WinTrustData.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; | ||
| 1942 | |||
| 1943 | er = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &gSubSystemDriver, &WinTrustData); | ||
| 1944 | |||
| 1945 | // WinVerifyTrust returns 0 for success, a few different Win32 error codes if it can't | ||
| 1946 | // find the provider, and any other error code is provider specific, so may not | ||
| 1947 | // be an actual Win32 error code | ||
| 1948 | ExitOnWin32Error(er, hr, "Could not verify file %ls.", wzUnverifiedPayloadPath); | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | // Need to close the WinVerifyTrust action | ||
| 1952 | WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE; | ||
| 1953 | er = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &gSubSystemDriver, &WinTrustData); | ||
| 1954 | ExitOnWin32Error(er, hr, "Could not close verify handle."); | ||
| 1955 | |||
| 1956 | LExit: | ||
| 1957 | ReleaseStr(sczLowerCaseFile); | ||
| 1958 | ReleaseStr(sczName); | ||
| 1959 | ReleaseMem(pbHash); | ||
| 1960 | |||
| 1961 | return hr; | ||
| 1962 | } | ||
| 1963 | |||
| 1964 | static HRESULT VerifyPayloadAgainstChain( | ||
| 1965 | __in BURN_PAYLOAD* pPayload, | ||
| 1966 | __in PCCERT_CHAIN_CONTEXT pChainContext | ||
| 1967 | ) | ||
| 1968 | { | ||
| 1969 | HRESULT hr = S_OK; | ||
| 1970 | PCCERT_CONTEXT pChainElementCertContext = NULL; | ||
| 1971 | |||
| 1972 | BYTE rgbPublicKeyIdentifier[SHA1_HASH_LEN] = { }; | ||
| 1973 | DWORD cbPublicKeyIdentifier = sizeof(rgbPublicKeyIdentifier); | ||
| 1974 | BYTE* pbThumbprint = NULL; | ||
| 1975 | DWORD cbThumbprint = 0; | ||
| 1976 | |||
| 1977 | // Walk up the chain looking for a certificate in the chain that matches our expected public key identifier | ||
| 1978 | // and thumbprint (if a thumbprint was provided). | ||
| 1979 | HRESULT hrChainVerification = E_NOTFOUND; // assume we won't find a match. | ||
| 1980 | for (DWORD i = 0; i < pChainContext->rgpChain[0]->cElement; ++i) | ||
| 1981 | { | ||
| 1982 | pChainElementCertContext = pChainContext->rgpChain[0]->rgpElement[i]->pCertContext; | ||
| 1983 | |||
| 1984 | // Get the certificate's public key identifier. | ||
| 1985 | if (!::CryptHashPublicKeyInfo(NULL, CALG_SHA1, 0, X509_ASN_ENCODING, &pChainElementCertContext->pCertInfo->SubjectPublicKeyInfo, rgbPublicKeyIdentifier, &cbPublicKeyIdentifier)) | ||
| 1986 | { | ||
| 1987 | ExitWithLastError(hr, "Failed to get certificate public key identifier."); | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | // Compare the certificate's public key identifier with the payload's public key identifier. If they | ||
| 1991 | // match, we're one step closer to the a positive result. | ||
| 1992 | if (pPayload->cbCertificateRootPublicKeyIdentifier == cbPublicKeyIdentifier && | ||
| 1993 | 0 == memcmp(pPayload->pbCertificateRootPublicKeyIdentifier, rgbPublicKeyIdentifier, cbPublicKeyIdentifier)) | ||
| 1994 | { | ||
| 1995 | // If the payload specified a thumbprint for the certificate, verify it. | ||
| 1996 | if (pPayload->pbCertificateRootThumbprint) | ||
| 1997 | { | ||
| 1998 | hr = CertReadProperty(pChainElementCertContext, CERT_SHA1_HASH_PROP_ID, &pbThumbprint, &cbThumbprint); | ||
| 1999 | ExitOnFailure(hr, "Failed to read certificate thumbprint."); | ||
| 2000 | |||
| 2001 | if (pPayload->cbCertificateRootThumbprint == cbThumbprint && | ||
| 2002 | 0 == memcmp(pPayload->pbCertificateRootThumbprint, pbThumbprint, cbThumbprint)) | ||
| 2003 | { | ||
| 2004 | // If we got here, we found that our payload public key identifier and thumbprint | ||
| 2005 | // matched an element in the certficate chain. | ||
| 2006 | hrChainVerification = S_OK; | ||
| 2007 | break; | ||
| 2008 | } | ||
| 2009 | |||
| 2010 | ReleaseNullMem(pbThumbprint); | ||
| 2011 | } | ||
| 2012 | else // no thumbprint match necessary so we're good to go. | ||
| 2013 | { | ||
| 2014 | hrChainVerification = S_OK; | ||
| 2015 | break; | ||
| 2016 | } | ||
| 2017 | } | ||
| 2018 | } | ||
| 2019 | hr = hrChainVerification; | ||
| 2020 | ExitOnFailure(hr, "Failed to find expected public key in certificate chain."); | ||
| 2021 | |||
| 2022 | LExit: | ||
| 2023 | ReleaseMem(pbThumbprint); | ||
| 2024 | |||
| 2025 | return hr; | ||
| 2026 | } | ||
