TrenchBoot Anti Evil Maid - Phase 4


If you haven’t read the previous TrenchBoot AEM blog posts ([1], [2], [3]) or our project plan yet, it may be a good reading to catch up on what the TrenchBoot AEM project is about.

What’s new in TrenchBoot AEM?

The most significant change is obviously the ability to use AEM on AMD platforms. Contrary to TXT, which uses SINIT ACMs signed by Intel, on AMD the first piece of code executed after Dynamic Launch Event is fully controlled by the user. Other than two 16-bit fields at the very beginning, format of DCE (DRTM Configuration Environment) is decided by the implementation. Most notably, this includes hand-offs (both GRUB2->DCE and DCE->Xen) and the set and order of measurements performed by DCE. In case of AEM, this could allow us to skip early measurement done in Xen, but to keep code as similar as possible with TXT we decided to not do this.

The DCE implementation used by this project is called Secure Kernel Loader (or SKL), and the source code can be found here.

Unfortunately, TCG, Intel and AMD all use different names for the same component or event. Hopefully, the following table can help with navigating between those names and abbreviations.

TCG Intel AMD What it means in case of AEM
DL_Event (Dynamic Launch Event) SINIT SKINIT CPU instruction specific to vendor, executed by GRUB2
DCE (DRTM Configuration Environment) SINIT ACM (Authenticated Code Module) SL (Secure Loader) ACM for Intel, SKL for AMD
DCE Preamble n/a n/a GRUB2 - software that prepares and initializes DL_Event
DLME (Dynamically Launched Measured Environment) MLE (Measured Launch Environment) SK (Security Kernel) Xen, DLME definition also covers dom0 kernel and initramfs

Apart from addition of SKL and supporting it both in GRUB2 as well as in Xen, few other, usually smaller changes were made:

  • Script for dumping DRTM TPM event log was enhanced to support event log header as defined by TCG for TPM1.2 before the one specific to TXT. SKL puts TXT header as part of vendor info in TCG header, this gives a good compromise between two very similar formats - entries are identical, but headers are not.
  • Scriptlet that creates grub.cfg file now searches for SKL, in addition to SINIT ACMs.
  • GRUB2 is now able to choose best slaunch_module from all passed ones. This should allow users to put all ACMs and SKL in /boot directory, without having to choose the proper one.
  • This release is published in a form of repository to (hopefully) make installation process easier.

List of pull requests created and merged as part of this phase:


To install, you have to first add a new repository and import a public part of a key that was used to sign RPM packages. To add a new repository, create in dom0 as root /etc/yum.repos.d/aem.repo with the following content:

name = Anti Evil Maid based on TrenchBoot
baseurl =
gpgcheck = 1
gpgkey =
enabled = 1

Content of aem.repo

To download and import a signing key:

qvm-run --pass-io sys-net 'curl -L' > RPM-GPG-KEY-tb-aem
sudo rpm --import RPM-GPG-KEY-tb-aem

Importing signing key

Now it should be possible to download and install packages from our repository. As some of the packages are also available in standard QubesOS repositories, potentially in newer versions, those must be temporarily disabled during invocation of qubes-dom0-update, as shown in the following commands.

If any of the packages that are part of AEM are updated in standard repos, you will have to choose between using new versions or having working AEM, at least until new AEM release is published or the code gets merged upstream. If you decide to restore AEM after an update broke it, you will have to repeat the installation of overwritten package with --action=reinstall added to qubes-dom0-update, if it wasn’t present before.

Start by installing prerequisite packages. Those are not part of newly added repository, but qubes-dom0-current-testing:

sudo qubes-dom0-update --enablerepo=qubes-dom0-current-testing \
    oathtool \
    openssl \
    qrencode \
    tpm-extra \
    trousers-changer \

Next set of new packages comes from AEM repository, to avoid conflicts other repositories are disabled for this call:

sudo qubes-dom0-update --disablerepo="*" --enablerepo=aem \
    grub2-tools-extra \

This is followed by reinstalling additional packages. A reinstall is required because currently installed version is equal (or it may be higher in the future) than those provided by AEM.

sudo qubes-dom0-update --disablerepo="*" --enablerepo=aem --action=reinstall \
    python3-xen \
    xen \
    xen-hypervisor \
    xen-libs \
    xen-licenses \
    xen-runtime \
    grub2-common \
    grub2-pc \
    grub2-pc-modules \
    grub2-tools \

Depending on your starting point, it is possible that some of the above packages were updated in previous step. Reinstalling them isn’t necessary, but it also doesn’t hurt, other than taking a bit more time. It can only happen soon after release, because AEM packages are based on testing QubesOS repositories. After given package version gets out of testing into the main repo, reinstall is required. To keep instructions simple, you may assume that it is always required.

Another possible error is Installed package (...) not available. The reason for it is the same as above, but solution is different: instead of reinstalling, you have to update mentioned packages by changing --action=reinstall to --action=update in the call. If there are multiple packages mentioned, all of them must be updated in the same invocation of qubes-dom0-update.

Both of those problems will disappear in time - firstly when current testing lands in main repo, and then permanently after AEM based on TrenchBoot is fully merged to QubesOS. Until that happens, bear with us.

Booting on legacy systems (AEM currently doesn’t support UEFI) requires manual installation of GRUB2 to the MBR of disk where Qubes OS is stored. In our case it is /dev/sda, yours may be different so watch out! Remember that GRUB2 must be installed on disk and not on partition, so don’t use sda1, nvme0n1p1 etc.

sudo grub2-install /dev/sda

Finally, anti-evil-maid package may be installed:

sudo qubes-dom0-update --disablerepo="*" --enablerepo=aem anti-evil-maid

Now you should provision AEM by following instructions from previous phase.


To help with testing, anti-evil-maid-dump-evt-log was given new functionality. Now, in addition to printing entries from event log, it also calculates and prints expected values of PCR 17 and 18. This can be easily compared with actual values, which can be read from /sys/class/tpm/tpm0/pcr-sha{1,256}/1[78]:

Output of anti-evil-maid-dump-evt-log

Keep in mind that just because replayed values match current PCR values does not mean that they are correct. It tells that whatever was measured to PCRs was also written to the event log, no more, no less. It may be used for debugging or catching the error early, but no security-related decision should be based on contents of event log.

Digests stored in PCRs are all that matters. Sealing and unsealing operations are based on those values. From security perspective, the event log has any value only if PCRs hold proper digests.

Next steps

While this phase marks the end of the plan we published, we will not stop there. We will continue with upstreaming the changes, first to QubesOS repositories with patches, then to source repositories of components taking part in AEM.

We also have plans for next phase, which will focus on enabling AEM for UEFI. It will also focus on (re)testing the solution on all used platforms, to check if everything still works as it should after recent changes.

How you can help

By testing, of course! Install AEM, see if it performs as it should and report any encountered problem in trenchboot-issues repository.

Spreading the word is another way of helping. The more people know about AEM the better. We may not be able to test it on every possible configuration, but perhaps others have platforms that we don’t.

You can also stay updated on our project’s progress by visiting our GitHub milestones, and join our discussions in the public Matrix channel, where everyone can participate and share their thoughts.

Krystian Hebel
Firmware Engineer interested mostly in things deliberately omitted from documentation. Thinks C is high-level language, can write something in Verilog but doesn't know how to read it yet.