diff options
Diffstat (limited to 'src/burn/engine/cache.cpp')
| -rw-r--r-- | src/burn/engine/cache.cpp | 131 |
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; | |||
| 17 | static LPWSTR vsczDefaultMachinePackageCache = NULL; | 17 | static LPWSTR vsczDefaultMachinePackageCache = NULL; |
| 18 | static LPWSTR vsczCurrentMachinePackageCache = NULL; | 18 | static LPWSTR vsczCurrentMachinePackageCache = NULL; |
| 19 | 19 | ||
| 20 | static HRESULT CacheVerifyPayloadSignature( | ||
| 21 | __in BURN_PAYLOAD* pPayload, | ||
| 22 | __in_z LPCWSTR wzUnverifiedPayloadPath, | ||
| 23 | __in HANDLE hFile | ||
| 24 | ); | ||
| 20 | static HRESULT CalculateWorkingFolder( | 25 | static 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 | ); |
| 139 | static HRESULT VerifyPayloadAgainstCertChain( | ||
| 140 | __in BURN_PAYLOAD* pPayload, | ||
| 141 | __in PCCERT_CHAIN_CONTEXT pChainContext | ||
| 142 | ); | ||
| 134 | static HRESULT SendCacheBeginMessage( | 143 | static 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 | ||
| 1145 | static 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 | |||
| 1191 | LExit: | ||
| 1192 | return hr; | ||
| 1193 | } | ||
| 1194 | |||
| 1136 | extern "C" void CacheCleanup( | 1195 | extern "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 | ||
| 2214 | static 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 | |||
| 2272 | LExit: | ||
| 2273 | ReleaseMem(pbThumbprint); | ||
| 2274 | |||
| 2275 | return hr; | ||
| 2276 | } | ||
| 2277 | |||
| 2147 | static HRESULT SendCacheBeginMessage( | 2278 | static HRESULT SendCacheBeginMessage( |
| 2148 | __in PFN_BURNCACHEMESSAGEHANDLER pfnCacheMessageHandler, | 2279 | __in PFN_BURNCACHEMESSAGEHANDLER pfnCacheMessageHandler, |
| 2149 | __in LPVOID pContext, | 2280 | __in LPVOID pContext, |
