Manually Verifying Hashes of Installed Files

Background

Some people choose to use a security feature which verifies files on /boot (which are typically unencrypted) before using them. One example is PureBoot, which verifies the hashes of all files on /boot against a file signed by the user’s GPG key. The correct usage of this feature is to sign the files immediately after they are installed/updated (under the assumption that the update process is secure) so that future tampering can be detected. However, an operational mistake may leave the files unsigned and unattended for an unacceptable period of time. This guide explains how to manually verify the files.

Required Equipment

  • A trusted ISO (or other media which can be booted, as this cannot be done with the untrusted files in /boot)
  • A trusted copy of the QubesOS signing key for the relevant version (or the QMSK, which can be used to establish trust in a downloaded signing key)
  • An internet connection

Process

For each package, we have to:

  1. Download the relevant RPM and buildinfo files from the QubesOS server
  2. Verify both files
  3. Extract the binaries & compare their hashes

The process will use an example of an updated (and currently untrusted) hypervisor, consisting of the following files:

  • /boot/xen-4.17.2.gz
  • /boot/efi/EFI/qubes/xen-4.17.2.efi
  • /boot/efi/EFI/quebs/xen.efi

Download the relevant files

We can manually download RPM and buildinfo files from https://yum.qubes-os.org. For example, at time of writing the packages for 4.2 are found at Index of /r4.2/current/host/fc37/rpm/ (if you need to check files that were installed to dom0 or domU, replace host with dom0 or vm, repsectively). A single buildinfo file might contain hashes for multiple RPM packages. For example, in this case we need the buildinfo file xen-4.17.2-8.fc37.x86_64.buildinfo to verify the RPM file xen-hypervisor-4.17.2-8.fc37.x86_64.rpm.

Verify both files

The buildinfo package should be signed by the release signing key for the relevant QubesOS release. It can be checked just like any other GPG-signed file:

gpg --verify xen-4.17.2-8.fc37.x86_64.buildinfo

Then check the hash of the RPM file and check that it matches the hash listed in the buildinfo file (buildinfo is a plaintext format, so you can just grep the file for the hash):

grep $(sha256sum xen-hypervisor-4.17.2-8.fc37.x86_64.rpm | cut -f1) xen-4.17.2-8.fc37.x86_64.buildinfo

Extract the binaries

RPM files can be unpacked using the rpm2cpio utility:

rpm2cpio xen-hypervisor-4.17.2-8.fc37.x86_64.rpm | cpio -imvd

Then, the hashes should match (replace {boot-drive} with the drive designation for your boot partition, such as sda1, and leave out the curly braces):

mount /dev/{boot-drive} /mnt
sha256sum boot/xen-4.17.2.gz /mnt/xen-4.17.2.gz
sha256sum boot/efi/EFI/qubes/xen-4.17.2.efi /mnt/efi/EFI/qubes/xen-4.17.2.efi /mnt/efi/EFI/qubes/xen.efi

Note that xen.efi is a copy of xen-4.17.2.efi, and the copy is not stored literally within the RPM, but since they hash to the same value we can be confident that they are not malicious.

5 Likes

Here is a second method for verifying the RPM file if the buildinfo file isn’t available. This method can also be useful if you’re not sure which package contains the file that you need to verify because filelists.xml provides the entire list of files that each package provides.

This method requires downloading 2 new files containing repostiory metadata - repomd.xml and <hash>-filelists.xml (where <hash> is a SHA-256 hash).

First, download repomd.xml and it’s signature, contained in repomd.xml.asc. These can be found in the repodata directory rather than the rpm directory in https://yum.qubes-os.org - for example, /r4.2/current/dom0/fc37/repodata. Verification is similar to verifying the buildinfo file, except you give it the the .asc file as this contains the detached signature. Make sure that the main file (repomd.xml) is in the same directory so that GPG can find it automatically. It should be signed by the QubesOS release signing key.

gpg --verify repomd.xml.asc

Next, open the file and look for the entry starting with <data type="filelists">. This entry will contain 2 sub-entries with relevant hashes. The first one is the <checksum type="sha256"> sub-entry. This is the hash that is used in the filename <hash>-filelists.xml. This can be downloaded from the same repodata directory. However, this file is compressed. Download it and decompress it with zstd:

zstd -d 27dfd52cb4fa97c5b3e74d47bfd75cc607f670c15549b207e3bfd797731b8a6d-filelists.xml.zst

Now you can check the hash of the RPM with a similar command used to search the buildinfo file:

grep $(sha256sum xen-hypervisor-4.17.5-2.fc37.x86_64.rpm | cut -f1) <hash>-filelists.xml
1 Like