From https://docs.microsoft.com/en-us/windows/win32/debug/pe-format, emphasis mine:
When included in a certificate, the image digest must exclude certain fields in the PE Image, such as the Checksum and Certificate Table entry in Optional Header Data Directories. This is because the act of adding a Certificate changes these fields and would cause a different hash value to be calculated.
The Win32 ImageGetDigestStream function provides a data stream from a target PE file with which to hash functions. This data stream remains consistent when certificates are added to or removed from a PE file. Based on the parameters that are passed to ImageGetDigestStream, other data from the PE image can be omitted from the hash computation.
The ImageGetDigestStream
function is documented at https://docs.microsoft.com/en-us/windows/win32/api/imagehlp/nf-imagehlp-imagegetdigeststream, which shows that it accepts a bitfield indicating optional file sections to include: the import data, the debug symbols, and the resource section (which is used for things like embedded image files and other large binary blobs). The executable image (code and static data) are always included.
Beyond all of that, there's some padding between sections of file, and at the end of the file, that is not used in the digest. It's conventionally zero (NULL) bytes, but can be changed as long as the total file length doesn't change. I've verified that changing the padding at the end, at least, doesn't invalidate the signature.
Based on that, some (non-exclusive) candidates for explaining the different Firefox downloads (without even looking at actual examples):
- Unique certificates in the Checksum and Certificate Table, either actually used for code signing or just there to uniquely identify the binary.
- Resource data that just isn't included in the signature (I don't know if there is any; it's certainly quite common for installers to include lots of resource data but I'd hope it would be signed).
- Padding, especially padding at the end of the file.
digicertutil
does not offer the possibility to sign only a portion of the .exe file: digicert.com/kb/images/code-signing/…