Fix PE/COFF checksum calculation

Only count the cert_table header once when performing the calculation
and counting buffer sizes.

The problem entered because of a mismerge of multiple signature
support and "be1f3d8 Update the PE checksum field using the
somewhat-underdocumented algorithm, so that we match the Microsoft
implementation in our signature generation.".  Originally
image->cert_table held the full certificate table including the
Microsoft _WINH_CERTIFICATE header and image->sigbuf pointed to the
pkcs11 signature inside, so the two had to be checksummed separately.
After multiple signature support, image->sigbuf points to the full
certificate table because we now need the headers to decide where one
signature ends and the next begins, so the correct checksum only needs
to sum over the entire image->sigbuf.

Signed-off-by: Steve McIntyre <93sam@debian.org>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
Steve McIntyre 2019-04-19 23:14:46 +01:00 committed by James Bottomley
parent 216dbd3331
commit 0dc3d4b521

View file

@ -162,7 +162,6 @@ static void image_pecoff_update_checksum(struct image *image)
{ {
bool is_signed = image->sigsize && image->sigbuf; bool is_signed = image->sigsize && image->sigbuf;
uint32_t checksum; uint32_t checksum;
struct cert_table_header *cert_table = image->cert_table;
/* We carefully only include the signature data in the checksum (and /* We carefully only include the signature data in the checksum (and
* in the file length) if we're outputting the signature. Otherwise, * in the file length) if we're outputting the signature. Otherwise,
@ -180,16 +179,13 @@ static void image_pecoff_update_checksum(struct image *image)
(void *)(image->checksum + 1)); (void *)(image->checksum + 1));
if (is_signed) { if (is_signed) {
checksum = csum_bytes(checksum,
cert_table, sizeof(*cert_table));
checksum = csum_bytes(checksum, image->sigbuf, image->sigsize); checksum = csum_bytes(checksum, image->sigbuf, image->sigsize);
} }
checksum += image->data_size; checksum += image->data_size;
if (is_signed) if (is_signed)
checksum += sizeof(*cert_table) + image->sigsize; checksum += image->sigsize;
*(image->checksum) = cpu_to_le32(checksum); *(image->checksum) = cpu_to_le32(checksum);
} }