aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/cache.cpp
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-05-03 14:41:33 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-05-11 19:11:19 -0500
commit2f4287fdcee83b30e0f7f3ce548bcdff2ee85e1f (patch)
treef2413b7c18e22ecc4398c28df5acdfd9feebd310 /src/burn/engine/cache.cpp
parentcd921db764df9578733c85c29e8c6c368f4c7e78 (diff)
downloadwix-2f4287fdcee83b30e0f7f3ce548bcdff2ee85e1f.tar.gz
wix-2f4287fdcee83b30e0f7f3ce548bcdff2ee85e1f.tar.bz2
wix-2f4287fdcee83b30e0f7f3ce548bcdff2ee85e1f.zip
Bring back Burn's implementation of signature verification.
partial #6447
Diffstat (limited to 'src/burn/engine/cache.cpp')
-rw-r--r--src/burn/engine/cache.cpp131
1 files changed, 131 insertions, 0 deletions
diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp
index 44267cbc..61416aed 100644
--- a/src/burn/engine/cache.cpp
+++ b/src/burn/engine/cache.cpp
@@ -17,6 +17,11 @@ static LPWSTR vsczDefaultUserPackageCache = NULL;
17static LPWSTR vsczDefaultMachinePackageCache = NULL; 17static LPWSTR vsczDefaultMachinePackageCache = NULL;
18static LPWSTR vsczCurrentMachinePackageCache = NULL; 18static LPWSTR vsczCurrentMachinePackageCache = NULL;
19 19
20static HRESULT CacheVerifyPayloadSignature(
21 __in BURN_PAYLOAD* pPayload,
22 __in_z LPCWSTR wzUnverifiedPayloadPath,
23 __in HANDLE hFile
24 );
20static HRESULT CalculateWorkingFolder( 25static HRESULT CalculateWorkingFolder(
21 __in_z LPCWSTR wzBundleId, 26 __in_z LPCWSTR wzBundleId,
22 __deref_out_z LPWSTR* psczWorkingFolder 27 __deref_out_z LPWSTR* psczWorkingFolder
@@ -131,6 +136,10 @@ static HRESULT VerifyHash(
131 __in LPPROGRESS_ROUTINE pfnProgress, 136 __in LPPROGRESS_ROUTINE pfnProgress,
132 __in LPVOID pContext 137 __in LPVOID pContext
133 ); 138 );
139static HRESULT VerifyPayloadAgainstCertChain(
140 __in BURN_PAYLOAD* pPayload,
141 __in PCCERT_CHAIN_CONTEXT pChainContext
142 );
134static HRESULT SendCacheBeginMessage( 143static HRESULT SendCacheBeginMessage(
135 __in PFN_BURNCACHEMESSAGEHANDLER pfnCacheMessageHandler, 144 __in PFN_BURNCACHEMESSAGEHANDLER pfnCacheMessageHandler,
136 __in LPVOID pContext, 145 __in LPVOID pContext,
@@ -1133,6 +1142,56 @@ LExit:
1133 return hr; 1142 return hr;
1134} 1143}
1135 1144
1145static HRESULT CacheVerifyPayloadSignature(
1146 __in BURN_PAYLOAD* pPayload,
1147 __in_z LPCWSTR wzUnverifiedPayloadPath,
1148 __in HANDLE hFile
1149 )
1150{
1151 HRESULT hr = S_OK;
1152 LONG er = ERROR_SUCCESS;
1153
1154 GUID guidAuthenticode = WINTRUST_ACTION_GENERIC_VERIFY_V2;
1155 WINTRUST_FILE_INFO wfi = { };
1156 WINTRUST_DATA wtd = { };
1157 CRYPT_PROVIDER_DATA* pProviderData = NULL;
1158 CRYPT_PROVIDER_SGNR* pSigner = NULL;
1159
1160 // Verify the payload assuming online.
1161 wfi.cbStruct = sizeof(wfi);
1162 wfi.pcwszFilePath = wzUnverifiedPayloadPath;
1163 wfi.hFile = hFile;
1164
1165 wtd.cbStruct = sizeof(wtd);
1166 wtd.dwUnionChoice = WTD_CHOICE_FILE;
1167 wtd.pFile = &wfi;
1168 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
1169 wtd.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
1170 wtd.dwUIChoice = WTD_UI_NONE;
1171
1172 er = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &guidAuthenticode, &wtd);
1173 if (er)
1174 {
1175 // Verify the payload assuming offline.
1176 wtd.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;
1177
1178 er = ::WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), &guidAuthenticode, &wtd);
1179 ExitOnWin32Error(er, hr, "Failed authenticode verification of payload: %ls", wzUnverifiedPayloadPath);
1180 }
1181
1182 pProviderData = ::WTHelperProvDataFromStateData(wtd.hWVTStateData);
1183 ExitOnNullWithLastError(pProviderData, hr, "Failed to get provider state from authenticode certificate.");
1184
1185 pSigner = ::WTHelperGetProvSignerFromChain(pProviderData, 0, FALSE, 0);
1186 ExitOnNullWithLastError(pSigner, hr, "Failed to get signer chain from authenticode certificate.");
1187
1188 hr = VerifyPayloadAgainstCertChain(pPayload, pSigner->pChainContext);
1189 ExitOnFailure(hr, "Failed to verify expected payload against actual certificate chain.");
1190
1191LExit:
1192 return hr;
1193}
1194
1136extern "C" void CacheCleanup( 1195extern "C" void CacheCleanup(
1137 __in BOOL fPerMachine, 1196 __in BOOL fPerMachine,
1138 __in_z LPCWSTR wzBundleId 1197 __in_z LPCWSTR wzBundleId
@@ -1563,6 +1622,10 @@ static HRESULT VerifyThenTransferPayload(
1563 1622
1564 switch (pPayload->verification) 1623 switch (pPayload->verification)
1565 { 1624 {
1625 case BURN_PAYLOAD_VERIFICATION_AUTHENTICODE:
1626 hr = CacheVerifyPayloadSignature(pPayload, wzUnverifiedPayloadPath, hFile);
1627 ExitOnFailure(hr, "Failed to verify payload signature: %ls", wzCachedPath);
1628 break;
1566 case BURN_PAYLOAD_VERIFICATION_HASH: 1629 case BURN_PAYLOAD_VERIFICATION_HASH:
1567 hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, TRUE, wzUnverifiedPayloadPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext); 1630 hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, TRUE, wzUnverifiedPayloadPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext);
1568 ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath); 1631 ExitOnFailure(hr, "Failed to verify payload hash: %ls", wzCachedPath);
@@ -1705,6 +1768,10 @@ static HRESULT VerifyFileAgainstPayload(
1705 1768
1706 switch (pPayload->verification) 1769 switch (pPayload->verification)
1707 { 1770 {
1771 case BURN_PAYLOAD_VERIFICATION_AUTHENTICODE:
1772 hr = CacheVerifyPayloadSignature(pPayload, wzVerifyPath, hFile);
1773 ExitOnFailure(hr, "Failed to verify signature of payload: %ls", pPayload->sczKey);
1774 break;
1708 case BURN_PAYLOAD_VERIFICATION_HASH: 1775 case BURN_PAYLOAD_VERIFICATION_HASH:
1709 fVerifyFileSize = TRUE; 1776 fVerifyFileSize = TRUE;
1710 1777
@@ -2144,6 +2211,70 @@ LExit:
2144 return hr; 2211 return hr;
2145} 2212}
2146 2213
2214static HRESULT VerifyPayloadAgainstCertChain(
2215 __in BURN_PAYLOAD* pPayload,
2216 __in PCCERT_CHAIN_CONTEXT pChainContext
2217 )
2218{
2219 HRESULT hr = S_OK;
2220 PCCERT_CONTEXT pChainElementCertContext = NULL;
2221
2222 BYTE rgbPublicKeyIdentifier[SHA1_HASH_LEN] = { };
2223 DWORD cbPublicKeyIdentifier = sizeof(rgbPublicKeyIdentifier);
2224 BYTE* pbThumbprint = NULL;
2225 DWORD cbThumbprint = 0;
2226
2227 // Walk up the chain looking for a certificate in the chain that matches our expected public key identifier
2228 // and thumbprint (if a thumbprint was provided).
2229 HRESULT hrChainVerification = E_NOTFOUND; // assume we won't find a match.
2230 for (DWORD i = 0; i < pChainContext->rgpChain[0]->cElement; ++i)
2231 {
2232 pChainElementCertContext = pChainContext->rgpChain[0]->rgpElement[i]->pCertContext;
2233
2234 // Get the certificate's public key identifier.
2235 if (!::CryptHashPublicKeyInfo(NULL, CALG_SHA1, 0, X509_ASN_ENCODING, &pChainElementCertContext->pCertInfo->SubjectPublicKeyInfo, rgbPublicKeyIdentifier, &cbPublicKeyIdentifier))
2236 {
2237 ExitWithLastError(hr, "Failed to get certificate public key identifier.");
2238 }
2239
2240 // Compare the certificate's public key identifier with the payload's public key identifier. If they
2241 // match, we're one step closer to the a positive result.
2242 if (pPayload->cbCertificateRootPublicKeyIdentifier == cbPublicKeyIdentifier &&
2243 0 == memcmp(pPayload->pbCertificateRootPublicKeyIdentifier, rgbPublicKeyIdentifier, cbPublicKeyIdentifier))
2244 {
2245 // If the payload specified a thumbprint for the certificate, verify it.
2246 if (pPayload->pbCertificateRootThumbprint)
2247 {
2248 hr = CertReadProperty(pChainElementCertContext, CERT_SHA1_HASH_PROP_ID, &pbThumbprint, &cbThumbprint);
2249 ExitOnFailure(hr, "Failed to read certificate thumbprint.");
2250
2251 if (pPayload->cbCertificateRootThumbprint == cbThumbprint &&
2252 0 == memcmp(pPayload->pbCertificateRootThumbprint, pbThumbprint, cbThumbprint))
2253 {
2254 // If we got here, we found that our payload public key identifier and thumbprint
2255 // matched an element in the certficate chain.
2256 hrChainVerification = S_OK;
2257 break;
2258 }
2259
2260 ReleaseNullMem(pbThumbprint);
2261 }
2262 else // no thumbprint match necessary so we're good to go.
2263 {
2264 hrChainVerification = S_OK;
2265 break;
2266 }
2267 }
2268 }
2269 hr = hrChainVerification;
2270 ExitOnFailure(hr, "Failed to find expected public key in certificate chain.");
2271
2272LExit:
2273 ReleaseMem(pbThumbprint);
2274
2275 return hr;
2276}
2277
2147static HRESULT SendCacheBeginMessage( 2278static HRESULT SendCacheBeginMessage(
2148 __in PFN_BURNCACHEMESSAGEHANDLER pfnCacheMessageHandler, 2279 __in PFN_BURNCACHEMESSAGEHANDLER pfnCacheMessageHandler,
2149 __in LPVOID pContext, 2280 __in LPVOID pContext,