Rohde-Schwarz / TrustedGRUB2

DEPRECATED TPM enabled GRUB2 Bootloader
GNU General Public License v3.0
193 stars 77 forks source link

Incorrect SHA-1 hash calculation of ramdisk files #28

Closed Zepmann closed 8 years ago

Zepmann commented 8 years ago

This was tested using TrustedGRUB2 1.2.1 in debug mode on Arch Linux using the standard (latest) kernel and initramfs.

There is a bug in the SHA-1 implementation of TrustedGRUB2. If a hash is calculated over an initramfs file, the resulting SHA-1 hash is incorrect. If a hash is calculated over a file with the same size as the initramfs file but filled with random data, the SHA-1 hash is calculated correctly.

Expected behavior: SHA-1 hashes calculated by TrustedGRUB2 based on any file should be equal to the output of other SHA-1 implementations.

Actual behavior: SHA-1 hashes calculated by TrustedGRUB2 can differ compared to the output of other SHA-1 implementations.

To test this: You will need to have TrustedGRUB2 installed with the debug option for TPM operations enabled.

In binaryfiles.zip are two files. ramdisk.bin is an initramfs file. random.bin is a file filled with semi-random data (source: /dev/urandom) of the same size.

Copy these two files to your /boot partition. Add the following lines at the bottom of your Linux boot entry in /boot/grub/grub.cfg:

measure /ramdisk.bin 13
measure /random.bin 14
sleep 120

With debug enabled, you will see the SHA-1 hashes for two minutes. Look for the hashes calculated to extend PCRs 13 and 14. The SHA-1 hashes as calculated by TrustedGRUB2:

ramdisk.bin: e08917009ede788e93e54f3d4d921276980e995e
random.bin:  3485431bf315767c9010857a40dd5b01f0b22c7f

For reference, these are the SHA-1 values as calculated by GNU Core Utilities' sha1sum:

$ sha1sum /boot/ramdisk.bin
1778d21a9c7b5f6d432494941ebde5de02303d2c  /boot/ramdisk.bin
$ sha1sum -b /boot/ramdisk.bin
1778d21a9c7b5f6d432494941ebde5de02303d2c */boot/ramdisk.bin
$ sha1sum /boot/random.bin
3485431bf315767c9010857a40dd5b01f0b22c7f  /boot/random.bin
$ sha1sum -b /boot/random.bin
3485431bf315767c9010857a40dd5b01f0b22c7f */boot/random.bin

The same SHA-1 function used by Microsoft's implementation, indicating that sha1sum is correct (since if the implementation of sha1sum would be flawed, it would be unlikely that Microsoft's implementation would contain the same flaw):

C:\>fciv -sha1 ramdisk.bin
//
// File Checksum Integrity Verifier version 2.05.
//
1778d21a9c7b5f6d432494941ebde5de02303d2c ramdisk.bin

C:\>fciv -sha1 random.bin
//
// File Checksum Integrity Verifier version 2.05.
//
3485431bf315767c9010857a40dd5b01f0b22c7f random.bin

The use of the measure command in TrustedGRUB2 in the above example is for clarity. The same wrong hash is also calculated by the initrd command. Due to this, values of PCR-10 are wrong starting from the measurement of the initramfs. Note that hashes for kernel files are calculated correctly.

I also tried it with a newly generated initramfs file with some changed files inside and a newly generated random file. Again, the SHA-1 hash value calculated for the new initramfs was incorrect, whereas this value for the random data file was correctly calculated.

Correct calculation of SHA-1 hash values of startup files is vital when sealing new startup files to PCRs before a reboot and unsealing the same data after a reboot. (Re)sealing relies on two SHA-1 implementations:

  1. The implementation offered by the operating system (in my case sha1sum, which is correct).
  2. The implementation in TrustedGRUB2 (which is incorrect for ramdisk files).
neusdan commented 8 years ago

First of all thanks for this detailed bug report. Thanks to this i could very quickly reproduce this bug. I'll look into it.

Zepmann commented 8 years ago

I found the culprit. The grub_TPM_measureFile function in tpm_kern.c uses GRUB's grub_file_open function (from file.c) , which pre-processes compressed files (such as initramfs files) by decompressing them into memory before returning them. Therefore, grub_TPM_measureFile (used by GRUB commands measure, initrd, etc.) does not measure the file on the disk (as would be expected), but the decompressed data in memory. This does not affect non-compressed files, since they are not modified by GRUB when they are loaded into memory.

The attached patch has one possible solution. It adds a grub_file_open_nofilter function to file.c, which is called by grub_TPM_measureFile in tpm_kern.c (instead of grub_file_open). grub_file_open_nofilter is a copy of grub_file_open with the filter code removed. Therefore, it opens a file 'raw' into the memory. The result is as expected: the correct SHA-1 hash is now calculated over compresed (and other) files.

tgrub-1.2.1-nofilefilter.patch.zip

To apply the patch (assuming that TrustedGRUB2 is already installed): First make sure that the debug option for TPM operations is enabled in tpm.h, so the calculated SHA-1 hashes are visible during boot. Start from the TrustedGRUB2 source code directory.

Apply and install the patch:

patch -p1 < tgrub-1.2.1-nofilefilter.patch
make clean
make
make install

Install the patched TrustedGRUB2 to the MBR. Make sure that the device (/dev/sda in the example below) is correct.

grub-install --recheck --target=i386-pc --directory=/usr/lib/grub/i386-pc --no-rs-codes /dev/sda

Reboot, and you will see that SHA-1 checksums for initramfs and other compressed files are now correctly calculated.

neusdan commented 8 years ago

Thanks a lot for reporting and fixing this!

I would like to see more such well written issue reports on GitHub :+1:

neusdan commented 8 years ago

found a simpler solution to fix this