With new OP-TEE and EDK2 patches (not yet upstreamed [1][2]) we can run a
secure world application which manages UEFI variables.
Leveraging the U-Boot's OP-TEE supplicant we can then store those values
in an RPMB device.
The Secure World application responsible for doing that is coming from
EDK2 (StandAloneMM). The StandAloneMM application is compiled from EDK2
and then appended in the OP-TEE binary which executes that in Secure World.
There are various advantages in using StandAloneMM directly. Apart from the
obvious ones, such as running the whole code in Secure World, we are using
the EDK2 Fault Tolerant Write protocol to protect the variables against
corruption. We also avoid adding complicated code to U-Boot for the variable
management. The only code U-Boot needs is a set OP-TEE APIs to access the new
application.
>From a user's perspective this changes nothing to the usual way UEFI variables
are treated. The user will still use 'setenv/printenv -e' to perform the
variable operations.
An 'efidebug query' command is added to retrieve information about the
container used to store UEFI variables.
Since patches for the rest of the projects are not yet upstreamed I've tried to
provide a QEMU emulation for anyone interested in testing the patchset.
1. Download precompiled TF-A, OP-TEE binaries and a DTB from
https://people.linaro.org/~ilias.apalodimas/secure_boot/
bl33.bin is a precompiled U-Boot binary. If you use that skip (2)
2. git clone --single-branch --branch rpmb_hack \
https://git.linaro.org/people/ilias.apalodimas/u-boot.git
I've included a defconfig to make your life easier
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
make qemu_tfa_mm_defconfig && make -j4
Safely ignore the warnings, they are a result of the RPMB emulation
monstrosity ...
The branch contains an extra patch which adds RPMB emulation into OP-TEE
supplicant but breaks proper RPMB hardware. The patch is a gross hack
(but can be upstreamed later for Gitlab testing if needed).
Since QEMU has no RPMB emulation providing one through the OP-TEE supplicant
was the easiest way to test the patchset.
3. Create PK, KEK etc
- PK:
openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ -keyout \
PK.key -out PK.crt -nodes -days 365
cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc PK.crt \
PK.esl; sign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth
- KEK:
openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ -keyout \
KEK.key -out KEK.crt -nodes -days 365
cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc KEK.crt \
KEK.esl; sign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth
- put them in a file and create an image
mkdir tmp && cp PK.auth KEK.auth tmp/
virt-make-fs -s 1M -t ext4 tmp certs.img
4. Launch QEMU (note tested on QEMU 3.1 and 5.0)
qemu-system-aarch64 -m 1024 -smp 2 -show-cursor -serial stdio \
-monitor null -nographic \
-cpu cortex-a57 -bios bl1.bin -machine virt,secure=on -d unimp \
-semihosting-config enable,target=native -dtb ledge-qemuarm64.dtb \
-drive if=none,file=certs.img,id=mydisk \
-device nvme,drive=mydisk,serial=foo
You can now load and test the certificates
nvme scan
load nvme 0 0x70000000 PK.auth
setenv -e -nv -bs -rt -at -i 0x70000000,$filesize PK;
load nvme 0 0x70000000 KEK.auth
setenv -e -nv -bs -rt -at -i 0x70000000,$filesize KEK;
efidebug query
printenv -e -all
This has been tested against U-Boot efi_sefltest but since StandAloneMM will
write a non-existent variable if APPEND_WRITE is specified, this test will fail.
It has also been tested for the runtime variable support (or rather absence of
it) with FWTS (https://wiki.ubuntu.com/FirmwareTestSuite).
This patchset adds the needed APIs between U-Boot and OP-TEE and StandAloneMM
to perform the variable storage.
[1] https://github.com/apalos/optee_os/tree/stmm_upstream_03_clean
[2] https://git.linaro.org/people/ilias.apalodimas/edk2-platforms.git/log/?h=patch_pcd
Ilias Apalodimas (4):
efi_loader: Implement EFI variable handling via OP-TEE
cmd: efidebug: Add support for querying UEFI variable storage
MAINTAINERS: Add maintainer for EFI variables via OP-TEE
doc: uefi.rst: Add OP-TEE variable storage config options
Sughosh Ganu (2):
charset: Add support for calculating bytes occupied by a u16 string
efi_loader: Add headers for EDK2 StandAloneMM communication
MAINTAINERS | 7 +
cmd/efidebug.c | 45 ++-
doc/uefi/uefi.rst | 10 +
include/charset.h | 11 +
include/mm_communication.h | 28 ++
include/mm_variable.h | 78 ++++
lib/charset.c | 5 +
lib/efi_loader/Kconfig | 9 +
lib/efi_loader/Makefile | 4 +
lib/efi_loader/efi_variable_tee.c | 645 ++++++++++++++++++++++++++++++
10 files changed, 841 insertions(+), 1 deletion(-)
create mode 100644 include/mm_communication.h
create mode 100644 include/mm_variable.h
create mode 100644 lib/efi_loader/efi_variable_tee.c
With new OP-TEE and EDK2 patches (not yet upstreamed [1][2]) we can run a secure world application which manages UEFI variables. Leveraging the U-Boot's OP-TEE supplicant we can then store those values in an RPMB device. The Secure World application responsible for doing that is coming from EDK2 (StandAloneMM). The StandAloneMM application is compiled from EDK2 and then appended in the OP-TEE binary which executes that in Secure World. There are various advantages in using StandAloneMM directly. Apart from the obvious ones, such as running the whole code in Secure World, we are using the EDK2 Fault Tolerant Write protocol to protect the variables against corruption. We also avoid adding complicated code to U-Boot for the variable management. The only code U-Boot needs is a set OP-TEE APIs to access the new application. >From a user's perspective this changes nothing to the usual way UEFI variables are treated. The user will still use 'setenv/printenv -e' to perform the variable operations. An 'efidebug query' command is added to retrieve information about the container used to store UEFI variables. Since patches for the rest of the projects are not yet upstreamed I've tried to provide a QEMU emulation for anyone interested in testing the patchset. 1. Download precompiled TF-A, OP-TEE binaries and a DTB from https://people.linaro.org/~ilias.apalodimas/secure_boot/ bl33.bin is a precompiled U-Boot binary. If you use that skip (2) 2. git clone --single-branch --branch rpmb_hack \ https://git.linaro.org/people/ilias.apalodimas/u-boot.git I've included a defconfig to make your life easier export CROSS_COMPILE=aarch64-linux-gnu- export ARCH=arm64 make qemu_tfa_mm_defconfig && make -j4 Safely ignore the warnings, they are a result of the RPMB emulation monstrosity ... The branch contains an extra patch which adds RPMB emulation into OP-TEE supplicant but breaks proper RPMB hardware. The patch is a gross hack (but can be upstreamed later for Gitlab testing if needed). Since QEMU has no RPMB emulation providing one through the OP-TEE supplicant was the easiest way to test the patchset. 3. Create PK, KEK etc - PK: openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ -keyout \ PK.key -out PK.crt -nodes -days 365 cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc PK.crt \ PK.esl; sign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth - KEK: openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ -keyout \ KEK.key -out KEK.crt -nodes -days 365 cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc KEK.crt \ KEK.esl; sign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth - put them in a file and create an image mkdir tmp && cp PK.auth KEK.auth tmp/ virt-make-fs -s 1M -t ext4 tmp certs.img 4. Launch QEMU (note tested on QEMU 3.1 and 5.0) qemu-system-aarch64 -m 1024 -smp 2 -show-cursor -serial stdio \ -monitor null -nographic \ -cpu cortex-a57 -bios bl1.bin -machine virt,secure=on -d unimp \ -semihosting-config enable,target=native -dtb ledge-qemuarm64.dtb \ -drive if=none,file=certs.img,id=mydisk \ -device nvme,drive=mydisk,serial=foo You can now load and test the certificates nvme scan load nvme 0 0x70000000 PK.auth setenv -e -nv -bs -rt -at -i 0x70000000,$filesize PK; load nvme 0 0x70000000 KEK.auth setenv -e -nv -bs -rt -at -i 0x70000000,$filesize KEK; efidebug query printenv -e -all This has been tested against U-Boot efi_sefltest but since StandAloneMM will write a non-existent variable if APPEND_WRITE is specified, this test will fail. It has also been tested for the runtime variable support (or rather absence of it) with FWTS (https://wiki.ubuntu.com/FirmwareTestSuite). This patchset adds the needed APIs between U-Boot and OP-TEE and StandAloneMM to perform the variable storage. [1] https://github.com/apalos/optee_os/tree/stmm_upstream_03_clean [2] https://git.linaro.org/people/ilias.apalodimas/edk2-platforms.git/log/?h=patch_pcd Ilias Apalodimas (4): efi_loader: Implement EFI variable handling via OP-TEE cmd: efidebug: Add support for querying UEFI variable storage MAINTAINERS: Add maintainer for EFI variables via OP-TEE doc: uefi.rst: Add OP-TEE variable storage config options Sughosh Ganu (2): charset: Add support for calculating bytes occupied by a u16 string efi_loader: Add headers for EDK2 StandAloneMM communication MAINTAINERS | 7 + cmd/efidebug.c | 45 ++- doc/uefi/uefi.rst | 10 + include/charset.h | 11 + include/mm_communication.h | 28 ++ include/mm_variable.h | 78 ++++ lib/charset.c | 5 + lib/efi_loader/Kconfig | 9 + lib/efi_loader/Makefile | 4 + lib/efi_loader/efi_variable_tee.c | 645 ++++++++++++++++++++++++++++++ 10 files changed, 841 insertions(+), 1 deletion(-) create mode 100644 include/mm_communication.h create mode 100644 include/mm_variable.h create mode 100644 lib/efi_loader/efi_variable_tee.c