Prototyping UEFI Secure Boot on QEMU/VersatileExpress

This page documents the steps I took to wire up all the bits and pieces that are required to enable UEFI Secure Boot in Tianocore/EDK2 running on a QEMU-emulated VersatileExpress RTSM Cortex-A15.

Preparing an EFISTUB kernel

In principle, this page should apply to any kind of UEFI application launched from the UEFI boot environment, but the point of all of this is booting Linux so we will go with booting a zImage.

The ARM platform support (BDS layer) in Tianocore/EDK2 allows booting zImages directly. However, this is not the preferred way, and not actually supported at all if you want to use UEFI Secure Boot. Instead, we will use native UEFI boot, which needs the kernel image to be wrapped in a UEFI PE/COFF wrapper.

The code that implements this wrapper has been proposed for merging upstream, but can be found here in the mean time:

https://git.linaro.org/people/ard.biesheuvel/linux-arm.git/shortlog/refs/tags/arm32-efi-for-v4.5

Build a Versatile Express zImage using the following commands

$ make vexpress_defconfig
$ make menuconfig [to enable CONFIG_EFISTUB]
$ make zImage
$ make dtbs

The resulting zImage can be found in  arch/arm/boot/zImage . Copy or symlink arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb to fdt.dtb

Getting the signing tools

In order to sign the zImage, a modified version of sbsigntool is required, as the upstream version does not support signing ARM, Thumb or Aarch64 binaries.

You can find this modified version here:

https://git.linaro.org/people/ard.biesheuvel/sbsigntool.git

Build using ./configure; make  etc.

Creating the keys and certificates

The easiest way to create a set of keys to use with UEFI Secure Boot is to grab a copy of James Bottomley's efitools

Code can be found here:

http://git.kernel.org/cgit/linux/kernel/git/jejb/efitools.git

and depends on the packages gnu-efi and libfile-slurp-perl (Debian/Ubuntu)

After building, you will need to hold on to the following files to use in the subsequent steps

DB.key
DB.crt
DB.auth
KEK.auth
PK.auth

Signing the zImage

Sign the zImage as follows:

sbsign --key DB.key --cert DB.crt --output zImage.signed zImage

Building QEMU

Some changes are needed to QEMU that are currently in the process of being upstreamed.

Code can be found here:

http://git.linaro.org/people/peter.maydell/qemu-arm.git/commit/84291fe7a34f

and can be built using

./configure --target-list=arm-softmmu
make

The resulting binary is

arm-softmmu/qemu-system-arm

Obtaining Tianocore/EDK2

Get the source code from here:

https://git.linaro.org/people/ard.biesheuvel/uefi-next.git/shortlog/refs/heads/linaro-topic-authenticated-boot

The following steps need to be carried out once to prepare the build environment

$ unset ARCH CROSS_COMPILE
$ make -C BaseTools

Next, follow the instructions in CryptoPkg/Library/OpensslLib/Patch-HOWTO.txt for obtaining and installing the OpenSSL crypto sources.

Building Tianocore/EDK2

This sets up the shell environment before building

$ source edksetup.sh `pwd`/BaseTools
$ export CROSS_COMPILE=arm-linux-gnueabihf-

Now the actual UEFI build can be carried out using this command

$ build -a ARM -p ArmPlatformPkg/ArmVExpressPkg/ArmVExpress-RTSM-A15.dsc -t ARMLINUXGCC

The resulting binary needs to be padded to 64 megabytes before it can be booted by QEMU:

$ cat Build/ArmVExpress-RTSM-A15/DEBUG_ARMLINUXGCC/FV/RTSM_VE_CORTEX-A15_EFI.fd /dev/zero | \
    dd iflag=fullblock of=flash.img count=64 bs=1M

Note that the persistent data is kept inside the same image. Installed certificates and other variable data will be lost if you regenerate flash.img

Booting the emulator

Before booting the emulator, make sure the following files are present in the current working directory:

flash.img
zImage.signed
fdt.dtb
KEK.auth
DB.auth
PK.auth

The emulator can be started with the following command:

qemu-system-arm  -semihosting -M vexpress-a15 -m 2G -pflash flash.img -nographic

Installing the certificates

At boot, after some time (and a timeout), you will get the following menu:

[a] Boot Manager
[b] Shell
[c] Reboot
[d] Shutdown

If you haven't done so before, you can install the certificates by entering submenu [a], which reveals the following menu

[1] Add Boot Device Entry
[2] Update Boot Device Entry
[3] Remove Boot Device Entry
[4] Update FDT path
[5] Enable UEFI Secure Boot (needs {PK|KEK|DB}.auth)
[6] Return to main menu
Choice:

Choose option [5] and choose volume [1] 'SemihostFs' to enroll the certificates that are present in the current directory. After this has completed, UEFI Secure Boot will be enabled. You can verify this by choosing the shell from the main menu, and entering

setvar SecureBoot

which should return

8BE4DF61-93CA-11D2-AA0D-00E098032B8C - SecureBoot - 0001 Bytes
01

Booting the signed kernel

Finally, we can boot the signed zImage by issuing the following command from the shell

zImage.signed dtb=fdt.dtb console=ttyAMA0,38400n8

NOTE: in order to boot into a full blown Linux system, you will need to pass an SD image to QEMU using the -sd option, and pass the root= option to the kernel. For instance, you could use this SD image (un'gzip it first) and pass root=/dev/mmcblk0p2 to the kernel.

Verifying UEFI Secure Boot

Booting an unsigned zImage, or a zImage that has been modified after signing, should result in a message like the following:

Shell> zImage           
Loading driver at 0x000B699C000 EntryPoint=0x000B699C138
Loading driver at 0x000B699C000 EntryPoint=0x000B699C138 
Unloading driver at 0x000B699C000
Error reported: Security Violation

ardbiesheuvel/UefiSecureBootPrototype (last modified 2015-12-31 08:52:30)