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 '')
-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 | } | ||