@joebigelow / wix-1 / commits / cd921db7

Enforce payload and container verification.

Sean Hall committed May 3, 2021 at 12:23 UTC cd921db764df9578733c85c29e8c6c368f4c7e78
9 files changed +209 -92
src/burn/engine/apply.cpp
+2 -2
@@ -1410,12 +1410,12 @@ static HRESULT AcquireContainerOrPayload(
1410 fMinimumFileSize = TRUE;
1411 qwFileSize = pContainer->qwAttachedOffset + pContainer->qwFileSize;
1412 }
1413 - else if (pContainer->pbHash && pContext->wzLayoutDirectory)
1413 + else
1414 {
1415 qwFileSize = pContainer->qwFileSize;
1416 }
1417 }
1418 - else if (pPayload->pbHash)
1418 + else if (BURN_PAYLOAD_VERIFICATION_HASH == pPayload->verification || BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE == pPayload->verification)
1419 {
1420 qwFileSize = pPayload->qwFileSize;
1421 }
src/burn/engine/cache.cpp
+80 -15
@@ -114,10 +114,16 @@ static HRESULT RemoveBundleOrPackage(
114 __in_z LPCWSTR wzBundleOrPackageId,
115 __in_z LPCWSTR wzCacheId
116 );
117 +static HRESULT VerifyFileSize(
118 + __in HANDLE hFile,
119 + __in DWORD64 qwFileSize,
120 + __in_z LPCWSTR wzUnverifiedPayloadPath
121 + );
122 static HRESULT VerifyHash(
123 __in BYTE* pbHash,
124 __in DWORD cbHash,
125 __in DWORD64 qwFileSize,
126 + __in BOOL fVerifyFileSize,
127 __in_z LPCWSTR wzUnverifiedPayloadPath,
128 __in HANDLE hFile,
129 __in BURN_CACHE_STEP cacheStep,
@@ -1513,11 +1519,16 @@ static HRESULT VerifyThenTransferContainer(
1519 ExitWithLastError(hr, "Failed to open container in working path: %ls", wzUnverifiedContainerPath);
1520 }
1521
1516 - // Container should have a hash we can use to verify with.
1517 - if (pContainer->pbHash)
1522 +
1523 + switch (pContainer->verification)
1524 {
1519 - hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, wzUnverifiedContainerPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext);
1525 + case BURN_CONTAINER_VERIFICATION_HASH:
1526 + hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, TRUE, wzUnverifiedContainerPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext);
1527 ExitOnFailure(hr, "Failed to verify container hash: %ls", wzCachedPath);
1528 + break;
1529 + default:
1530 + ExitOnRootFailure(hr = E_INVALIDARG, "Container has no verification information: %ls", pContainer->sczId);
1531 + break;
1532 }
1533
1534 LogStringLine(REPORT_STANDARD, "%ls container from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedContainerPath, wzCachedPath);
@@ -1550,10 +1561,16 @@ static HRESULT VerifyThenTransferPayload(
1561 ExitWithLastError(hr, "Failed to open payload in working path: %ls", wzUnverifiedPayloadPath);
1562 }
1563
1553 - if (pPayload->pbHash) // the payload should have a hash we can use to verify it.
1564 + switch (pPayload->verification)
1565 {
1555 - hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, wzUnverifiedPayloadPath, hFile, BURN_CACHE_STEP_HASH, pfnCacheMessageHandler, pfnProgress, pContext);
1566 + case BURN_PAYLOAD_VERIFICATION_HASH:
1567 + 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);
1569 + break;
1570 + case BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE: __fallthrough;
1571 + default:
1572 + ExitOnRootFailure(hr = E_INVALIDARG, "Payload has no verification information: %ls", pPayload->sczKey);
1573 + break;
1574 }
1575
1576 LogStringLine(REPORT_STANDARD, "%ls payload from working path '%ls' to path '%ls'", fMove ? L"Moving" : L"Copying", wzUnverifiedPayloadPath, wzCachedPath);
@@ -1627,10 +1644,15 @@ static HRESULT VerifyFileAgainstContainer(
1644 ExitOnRootFailure(hr, "Failed to open container at path: %ls", wzVerifyPath);
1645 }
1646
1630 - if (pContainer->pbHash) // the container should have a hash we can use to verify it.
1647 + switch (pContainer->verification)
1648 {
1632 - hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext);
1649 + case BURN_CONTAINER_VERIFICATION_HASH:
1650 + hr = VerifyHash(pContainer->pbHash, pContainer->cbHash, pContainer->qwFileSize, TRUE, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext);
1651 ExitOnFailure(hr, "Failed to verify hash of container: %ls", pContainer->sczId);
1652 + break;
1653 + default:
1654 + ExitOnRootFailure(hr = E_INVALIDARG, "Container has no verification information: %ls", pContainer->sczId);
1655 + break;
1656 }
1657
1658 if (fAlreadyCached)
@@ -1667,6 +1689,7 @@ static HRESULT VerifyFileAgainstPayload(
1689 {
1690 HRESULT hr = S_OK;
1691 HANDLE hFile = INVALID_HANDLE_VALUE;
1692 + BOOL fVerifyFileSize = FALSE;
1693
1694 // Get the payload on disk actual hash.
1695 hFile = ::CreateFileW(wzVerifyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
@@ -1680,10 +1703,33 @@ static HRESULT VerifyFileAgainstPayload(
1703 ExitOnRootFailure(hr, "Failed to open payload at path: %ls", wzVerifyPath);
1704 }
1705
1683 - if (pPayload->pbHash) // the payload should have a hash we can use to verify it.
1706 + switch (pPayload->verification)
1707 {
1685 - hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext);
1708 + case BURN_PAYLOAD_VERIFICATION_HASH:
1709 + fVerifyFileSize = TRUE;
1710 +
1711 + hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, fVerifyFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext);
1712 ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey);
1713 +
1714 + break;
1715 + case BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE:
1716 + fVerifyFileSize = 0 != pPayload->qwFileSize;
1717 +
1718 + if (pPayload->pbHash)
1719 + {
1720 + hr = VerifyHash(pPayload->pbHash, pPayload->cbHash, pPayload->qwFileSize, fVerifyFileSize, wzVerifyPath, hFile, cacheStep, pfnCacheMessageHandler, pfnProgress, pContext);
1721 + ExitOnFailure(hr, "Failed to verify hash of payload: %ls", pPayload->sczKey);
1722 + }
1723 + else if (fVerifyFileSize)
1724 + {
1725 + hr = VerifyFileSize(hFile, pPayload->qwFileSize, wzVerifyPath);
1726 + ExitOnFailure(hr, "Failed to verify file size for path: %ls", wzVerifyPath);
1727 + }
1728 +
1729 + break;
1730 + default:
1731 + ExitOnRootFailure(hr = E_INVALIDARG, "Payload has no verification information: %ls", pPayload->sczKey);
1732 + break;
1733 }
1734
1735 if (fAlreadyCached)
@@ -2015,10 +2061,32 @@ LExit:
2061 return hr;
2062 }
2063
2064 +static HRESULT VerifyFileSize(
2065 + __in HANDLE hFile,
2066 + __in DWORD64 qwFileSize,
2067 + __in_z LPCWSTR wzUnverifiedPayloadPath
2068 + )
2069 +{
2070 + HRESULT hr = S_OK;
2071 + LONGLONG llSize = 0;
2072 +
2073 + hr = FileSizeByHandle(hFile, &llSize);
2074 + ExitOnFailure(hr, "Failed to get file size for path: %ls", wzUnverifiedPayloadPath);
2075 +
2076 + if (static_cast<DWORD64>(llSize) != qwFileSize)
2077 + {
2078 + ExitOnRootFailure(hr = ERROR_FILE_CORRUPT, "File size mismatch for path: %ls, expected: %llu, actual: %lld", wzUnverifiedPayloadPath, qwFileSize, llSize);
2079 + }
2080 +
2081 +LExit:
2082 + return hr;
2083 +}
2084 +
2085 static HRESULT VerifyHash(
2086 __in BYTE* pbHash,
2087 __in DWORD cbHash,
2088 __in DWORD64 qwFileSize,
2089 + __in BOOL fVerifyFileSize,
2090 __in_z LPCWSTR wzUnverifiedPayloadPath,
2091 __in HANDLE hFile,
2092 __in BURN_CACHE_STEP cacheStep,
@@ -2032,19 +2100,16 @@ static HRESULT VerifyHash(
2100 HRESULT hr = S_OK;
2101 BYTE rgbActualHash[SHA512_HASH_LEN] = { };
2102 DWORD64 qwHashedBytes = 0;
2035 - LONGLONG llSize = 0;
2103 LPWSTR pszExpected = NULL;
2104 LPWSTR pszActual = NULL;
2105
2106 hr = SendCacheBeginMessage(pfnCacheMessageHandler, pContext, cacheStep);
2107 ExitOnFailure(hr, "Aborted cache verify hash begin.");
2108
2042 - hr = FileSizeByHandle(hFile, &llSize);
2043 - ExitOnFailure(hr, "Failed to get file size for path: %ls", wzUnverifiedPayloadPath);
2044 -
2045 - if (static_cast<DWORD64>(llSize) != qwFileSize)
2109 + if (fVerifyFileSize)
2110 {
2047 - ExitOnFailure(hr = ERROR_FILE_CORRUPT, "File size mismatch for path: %ls, expected: %llu, actual: %lld", wzUnverifiedPayloadPath, qwFileSize, llSize);
2111 + hr = VerifyFileSize(hFile, qwFileSize, wzUnverifiedPayloadPath);
2112 + ExitOnFailure(hr, "Failed to verify file size for path: %ls", wzUnverifiedPayloadPath);
2113 }
2114
2115 // TODO: create a cryp hash file that sends progress.
src/burn/engine/container.cpp
+27 -23
@@ -50,16 +50,9 @@ extern "C" HRESULT ContainersParseFromXml(
50 hr = XmlGetAttributeEx(pixnNode, L"Id", &pContainer->sczId);
51 ExitOnFailure(hr, "Failed to get @Id.");
52
53 - // @Primary
54 - hr = XmlGetYesNoAttribute(pixnNode, L"Primary", &pContainer->fPrimary);
55 - if (E_NOTFOUND != hr)
56 - {
57 - ExitOnFailure(hr, "Failed to get @Primary.");
58 - }
59 -
53 // @Attached
54 hr = XmlGetYesNoAttribute(pixnNode, L"Attached", &pContainer->fAttached);
62 - if (E_NOTFOUND != hr || pContainer->fPrimary) // if it is a primary container, it has to be attached
55 + if (E_NOTFOUND != hr)
56 {
57 ExitOnFailure(hr, "Failed to get @Attached.");
58 }
@@ -87,10 +80,7 @@ extern "C" HRESULT ContainersParseFromXml(
80 {
81 // @FilePath
82 hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pContainer->sczFilePath);
90 - if (E_NOTFOUND != hr)
91 - {
92 - ExitOnFailure(hr, "Failed to get @FilePath.");
93 - }
83 + ExitOnFailure(hr, "Failed to get @FilePath.");
84 }
85
86 // The source path starts as the file path.
@@ -99,23 +89,32 @@ extern "C" HRESULT ContainersParseFromXml(
89
90 // @DownloadUrl
91 hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pContainer->downloadSource.sczUrl);
102 - if (E_NOTFOUND != hr || (!pContainer->fPrimary && !pContainer->sczSourcePath)) // if the package is not a primary package, it must have a source path or a download url
92 + if (E_NOTFOUND != hr)
93 {
104 - ExitOnFailure(hr, "Failed to get @DownloadUrl. Either @SourcePath or @DownloadUrl needs to be provided.");
94 + ExitOnFailure(hr, "Failed to get @DownloadUrl.");
95 }
96
97 // @Hash
98 hr = XmlGetAttributeEx(pixnNode, L"Hash", &pContainer->sczHash);
109 - if (SUCCEEDED(hr))
110 - {
111 - hr = StrAllocHexDecode(pContainer->sczHash, &pContainer->pbHash, &pContainer->cbHash);
112 - ExitOnFailure(hr, "Failed to hex decode the Container/@Hash.");
113 - }
114 - else if (E_NOTFOUND != hr)
99 + ExitOnFailure(hr, "Failed to get @Hash.");
100 +
101 + hr = StrAllocHexDecode(pContainer->sczHash, &pContainer->pbHash, &pContainer->cbHash);
102 + ExitOnFailure(hr, "Failed to hex decode the Container/@Hash.");
103 +
104 + // @FileSize
105 + hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz);
106 + ExitOnFailure(hr, "Failed to get @FileSize.");
107 +
108 + hr = StrStringToUInt64(scz, 0, &pContainer->qwFileSize);
109 + ExitOnFailure(hr, "Failed to parse @FileSize.");
110 +
111 + if (!pContainer->qwFileSize)
112 {
116 - ExitOnFailure(hr, "Failed to get @Hash.");
113 + ExitOnRootFailure(hr = E_INVALIDDATA, "File size is required when verifying by hash for container: %ls", pContainer->sczId);
114 }
115
116 + pContainer->verification = BURN_CONTAINER_VERIFICATION_HASH;
117 +
118 // prepare next iteration
119 ReleaseNullObject(pixnNode);
120 }
@@ -136,6 +135,7 @@ extern "C" HRESULT ContainersInitialize(
135 )
136 {
137 HRESULT hr = S_OK;
138 + DWORD64 qwSize = 0;
139
140 if (pContainers->rgContainers)
141 {
@@ -147,8 +147,13 @@ extern "C" HRESULT ContainersInitialize(
147 // manifest contained and get the offset to the container.
148 if (pContainer->fAttached)
149 {
150 - hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &pContainer->qwFileSize, &pContainer->fActuallyAttached);
150 + hr = SectionGetAttachedContainerInfo(pSection, pContainer->dwAttachedIndex, pContainer->type, &pContainer->qwAttachedOffset, &qwSize, &pContainer->fActuallyAttached);
151 ExitOnFailure(hr, "Failed to get attached container information.");
152 +
153 + if (qwSize != pContainer->qwFileSize)
154 + {
155 + ExitOnFailure(hr, "Attached container '%ls' size '%llu' didn't match size from manifest: '%llu'", pContainer->sczId, qwSize, pContainer->qwFileSize);
156 + }
157 }
158 }
159 }
@@ -195,7 +200,6 @@ extern "C" HRESULT ContainerOpenUX(
200
201 // open attached container
202 container.type = BURN_CONTAINER_TYPE_CABINET;
198 - container.fPrimary = TRUE;
203 container.fAttached = TRUE;
204 container.dwAttachedIndex = 0;
205
src/burn/engine/container.h
+7 -1
@@ -52,6 +52,12 @@ enum BURN_CAB_OPERATION
52 BURN_CAB_OPERATION_CLOSE,
53 };
54
55 +enum BURN_CONTAINER_VERIFICATION
56 +{
57 + BURN_CONTAINER_VERIFICATION_NONE,
58 + BURN_CONTAINER_VERIFICATION_HASH,
59 +};
60 +
61
62 // structs
63
@@ -59,7 +65,6 @@ typedef struct _BURN_CONTAINER
65 {
66 LPWSTR sczId;
67 BURN_CONTAINER_TYPE type;
62 - BOOL fPrimary;
68 BOOL fAttached;
69 DWORD dwAttachedIndex;
70 DWORD64 qwFileSize;
@@ -69,6 +74,7 @@ typedef struct _BURN_CONTAINER
74
75 BYTE* pbHash;
76 DWORD cbHash;
77 + BURN_CONTAINER_VERIFICATION verification;
78 DWORD64 qwAttachedOffset;
79 BOOL fActuallyAttached; // indicates whether an attached container is attached or missing.
80
src/burn/engine/payload.cpp
+77 -50
@@ -27,6 +27,8 @@ extern "C" HRESULT PayloadsParseFromXml(
27 IXMLDOMNode* pixnNode = NULL;
28 DWORD cNodes = 0;
29 LPWSTR scz = NULL;
30 + BOOL fChainPayload = pContainers && pLayoutPayloads; // These are required when parsing chain payloads.
31 + BOOL fValidFileSize = FALSE;
32
33 // select payload nodes
34 hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes);
@@ -51,6 +53,7 @@ extern "C" HRESULT PayloadsParseFromXml(
53 for (DWORD i = 0; i < cNodes; ++i)
54 {
55 BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i];
56 + fValidFileSize = FALSE;
57
58 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
59 ExitOnFailure(hr, "Failed to get next node.");
@@ -63,27 +66,36 @@ extern "C" HRESULT PayloadsParseFromXml(
66 hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath);
67 ExitOnFailure(hr, "Failed to get @FilePath.");
68
66 - // @Packaging
67 - hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz);
68 - ExitOnFailure(hr, "Failed to get @Packaging.");
69 + // @SourcePath
70 + hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath);
71 + ExitOnFailure(hr, "Failed to get @SourcePath.");
72
70 - if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1))
73 + if (!fChainPayload)
74 {
75 + // All non-chain payloads are embedded in the UX container.
76 pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED;
77 }
74 - else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1))
75 - {
76 - pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL;
77 - }
78 else
79 {
80 - hr = E_INVALIDARG;
81 - ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz);
82 - }
80 + // @Packaging
81 + hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz);
82 + ExitOnFailure(hr, "Failed to get @Packaging.");
83
84 - // @Container
85 - if (pContainers)
86 - {
84 + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1))
85 + {
86 + pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED;
87 + }
88 + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1))
89 + {
90 + pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL;
91 + }
92 + else
93 + {
94 + hr = E_INVALIDARG;
95 + ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz);
96 + }
97 +
98 + // @Container
99 hr = XmlGetAttributeEx(pixnNode, L"Container", &scz);
100 if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
101 {
@@ -93,52 +105,67 @@ extern "C" HRESULT PayloadsParseFromXml(
105 hr = ContainerFindById(pContainers, scz, &pPayload->pContainer);
106 ExitOnFailure(hr, "Failed to to find container: %ls", scz);
107 }
96 - }
108
98 - // @LayoutOnly
99 - hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly);
100 - if (E_NOTFOUND != hr)
101 - {
102 - ExitOnFailure(hr, "Failed to get @LayoutOnly.");
103 - }
109 + // @LayoutOnly
110 + hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly);
111 + if (E_NOTFOUND != hr)
112 + {
113 + ExitOnFailure(hr, "Failed to get @LayoutOnly.");
114 + }
115
105 - // @SourcePath
106 - hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath);
107 - ExitOnFailure(hr, "Failed to get @SourcePath.");
116 + // @DownloadUrl
117 + hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl);
118 + if (E_NOTFOUND != hr)
119 + {
120 + ExitOnFailure(hr, "Failed to get @DownloadUrl.");
121 + }
122
109 - // @DownloadUrl
110 - hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl);
111 - if (E_NOTFOUND != hr)
112 - {
113 - ExitOnFailure(hr, "Failed to get @DownloadUrl.");
114 - }
123 + // @FileSize
124 + hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz);
125 + if (E_NOTFOUND != hr)
126 + {
127 + ExitOnFailure(hr, "Failed to get @FileSize.");
128
116 - // @FileSize
117 - hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz);
118 - if (E_NOTFOUND != hr)
119 - {
120 - ExitOnFailure(hr, "Failed to get @FileSize.");
129 + hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize);
130 + ExitOnFailure(hr, "Failed to parse @FileSize.");
131
122 - hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize);
123 - ExitOnFailure(hr, "Failed to parse @FileSize.");
124 - }
132 + fValidFileSize = TRUE;
133 + }
134 +
135 + // @Hash
136 + hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz);
137 + if (E_NOTFOUND != hr)
138 + {
139 + ExitOnFailure(hr, "Failed to get @Hash.");
140
126 - // @Hash
127 - hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz);
128 - ExitOnFailure(hr, "Failed to get @Hash.");
141 + hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash);
142 + ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash.");
143
130 - hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash);
131 - ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash.");
144 + if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification)
145 + {
146 + pPayload->verification = BURN_PAYLOAD_VERIFICATION_HASH;
147 + }
148 + }
149
133 - if (pPayload->fLayoutOnly && pLayoutPayloads)
134 - {
135 - hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pLayoutPayloads->rgItems), pLayoutPayloads->cItems + 1, sizeof(BURN_PAYLOAD_GROUP_ITEM), 5);
136 - ExitOnFailure(hr, "Failed to allocate memory for layout payloads.");
150 + if (BURN_PAYLOAD_VERIFICATION_NONE == pPayload->verification)
151 + {
152 + ExitOnRootFailure(hr = E_INVALIDDATA, "There was no verification information for payload: %ls", pPayload->sczKey);
153 + }
154 + else if (BURN_PAYLOAD_VERIFICATION_HASH == pPayload->verification && !fValidFileSize)
155 + {
156 + ExitOnRootFailure(hr = E_INVALIDDATA, "File size is required when verifying by hash for payload: %ls", pPayload->sczKey);
157 + }
158
138 - pLayoutPayloads->rgItems[pLayoutPayloads->cItems].pPayload = pPayload;
139 - ++pLayoutPayloads->cItems;
159 + if (pPayload->fLayoutOnly)
160 + {
161 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pLayoutPayloads->rgItems), pLayoutPayloads->cItems + 1, sizeof(BURN_PAYLOAD_GROUP_ITEM), 5);
162 + ExitOnFailure(hr, "Failed to allocate memory for layout payloads.");
163
141 - pLayoutPayloads->qwTotalSize += pPayload->qwFileSize;
164 + pLayoutPayloads->rgItems[pLayoutPayloads->cItems].pPayload = pPayload;
165 + ++pLayoutPayloads->cItems;
166 +
167 + pLayoutPayloads->qwTotalSize += pPayload->qwFileSize;
168 + }
169 }
170
171 // prepare next iteration
src/burn/engine/payload.h
+8
@@ -23,6 +23,13 @@ enum BURN_PAYLOAD_STATE
23 BURN_PAYLOAD_STATE_CACHED,
24 };
25
26 +enum BURN_PAYLOAD_VERIFICATION
27 +{
28 + BURN_PAYLOAD_VERIFICATION_NONE,
29 + BURN_PAYLOAD_VERIFICATION_HASH,
30 + BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE,
31 +};
32 +
33
34 // structs
35
@@ -36,6 +43,7 @@ typedef struct _BURN_PAYLOAD
43
44 BYTE* pbHash;
45 DWORD cbHash;
46 + BURN_PAYLOAD_VERIFICATION verification;
47
48 LPWSTR sczSourcePath;
49 BURN_CONTAINER* pContainer;
src/burn/engine/pseudobundle.cpp
+5
@@ -69,6 +69,11 @@ extern "C" HRESULT PseudoBundleInitialize(
69 memcpy_s(pPayload->pbHash, pPayload->cbHash, pbHash, cbHash);
70 }
71
72 + if (BOOTSTRAPPER_RELATION_UPDATE == relationType)
73 + {
74 + pPayload->verification = BURN_PAYLOAD_VERIFICATION_UPDATE_BUNDLE;
75 + }
76 +
77 pPackage->Exe.fPseudoBundle = TRUE;
78
79 pPackage->type = BURN_PACKAGE_TYPE_EXE;
src/burn/test/BurnUnitTest/CacheTest.cpp
+2
@@ -71,6 +71,8 @@ namespace Bootstrapper
71 payload.sczFilePath = L"CacheSignatureTest.File";
72 payload.pbHash = pb;
73 payload.cbHash = cb;
74 + payload.qwFileSize = 27;
75 + payload.verification = BURN_PAYLOAD_VERIFICATION_HASH;
76
77 hr = CacheCompletePayload(package.fPerMachine, &payload, package.sczCacheId, sczPayloadPath, FALSE, CacheTestEventRoutine, CacheTestProgressRoutine, &context);
78 Assert::Equal(S_OK, hr);
src/burn/test/BurnUnitTest/PlanTest.cpp
+1 -1
@@ -71,7 +71,7 @@ namespace Bootstrapper
71 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
72
73 Assert::Equal(107082ull, pPlan->qwEstimatedSize);
74 - Assert::Equal(506145ull, pPlan->qwCacheSizeTotal);
74 + Assert::Equal(522548ull, pPlan->qwCacheSizeTotal);
75
76 fRollback = FALSE;
77 dwIndex = 0;