diff mbox series

[v4,14/14] qemu: arm64: Add documentation for capsule update

Message ID 20201230135712.5289-15-sughosh.ganu@linaro.org
State Accepted
Commit c35df7c9e43eaf5f8bf2113a58ea257291988589
Headers show
Series qemu: arm64: Add support for uefi capsule update on qemu arm platform | expand

Commit Message

Sughosh Ganu Dec. 30, 2020, 1:57 p.m. UTC
Add documentation highlighting the steps for using the uefi capsule
update feature for updating the u-boot firmware image.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>

---

Changes since V3: None

 doc/board/emulation/index.rst               |   1 +
 doc/board/emulation/qemu_capsule_update.rst | 210 ++++++++++++++++++++
 2 files changed, 211 insertions(+)
 create mode 100644 doc/board/emulation/qemu_capsule_update.rst

-- 
2.17.1

Comments

Heinrich Schuchardt March 2, 2021, 11:14 a.m. UTC | #1
On 30.12.20 14:57, Sughosh Ganu wrote:
> Add documentation highlighting the steps for using the uefi capsule

> update feature for updating the u-boot firmware image.

>

> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>

> ---

>

> Changes since V3: None

>

>  doc/board/emulation/index.rst               |   1 +

>  doc/board/emulation/qemu_capsule_update.rst | 210 ++++++++++++++++++++

>  2 files changed, 211 insertions(+)

>  create mode 100644 doc/board/emulation/qemu_capsule_update.rst

>

> diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst

> index 1adefee155..a09ead1c35 100644

> --- a/doc/board/emulation/index.rst

> +++ b/doc/board/emulation/index.rst

> @@ -10,3 +10,4 @@ Emulation

>     qemu-mips

>     qemu-riscv

>     qemu-x86

> +   qemu_capsule_update

> diff --git a/doc/board/emulation/qemu_capsule_update.rst b/doc/board/emulation/qemu_capsule_update.rst

> new file mode 100644

> index 0000000000..9fec75f8f1

> --- /dev/null

> +++ b/doc/board/emulation/qemu_capsule_update.rst

> @@ -0,0 +1,210 @@

> +.. SPDX-License-Identifier: GPL-2.0+

> +.. Copyright (C) 2020, Linaro Limited

> +

> +Enabling UEFI Capsule Update feature

> +------------------------------------

> +

> +Support has been added for the UEFI capsule update feature which

> +enables updating the U-Boot image using the UEFI firmware management

> +protocol (fmp). The capsules are not passed to the firmware through

> +the UpdateCapsule runtime service. Instead, capsule-on-disk

> +functionality is used for fetching the capsule from the EFI System

> +Partition (ESP) by placing the capsule file under the

> +\EFI\UpdateCapsule directory.

> +

> +Currently, support has been added on the QEMU ARM64 virt platform for

> +updating the U-Boot binary as a raw image when the platform is booted

> +in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this

> +configuration, the QEMU platform needs to be booted with

> +'secure=off'. The U-Boot binary placed on the first bank of the NOR

> +flash at offset 0x0. The U-Boot environment is placed on the second

> +NOR flash bank at offset 0x4000000.

> +

> +The capsule update feature is enabled with the following configuration

> +settings::

> +

> +    CONFIG_MTD=y

> +    CONFIG_FLASH_CFI_MTD=y

> +    CONFIG_CMD_MTDPARTS=y

> +    CONFIG_CMD_DFU=y

> +    CONFIG_DFU_MTD=y

> +    CONFIG_PCI_INIT_R=y

> +    CONFIG_EFI_CAPSULE_ON_DISK=y

> +    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y

> +    CONFIG_EFI_CAPSULE_FIRMWARE=y

> +    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y

> +    CONFIG_EFI_CAPSULE_FMP_HEADER=y

> +

> +In addition, the following config needs to be disabled(QEMU ARM specific)::

> +

> +    CONFIG_TFABOOT

> +

> +The capsule file can be generated by using the GenerateCapsule.py

> +script in EDKII::

> +

> +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

> +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \

> +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose --update-image-index \

> +    <val> --verbose <u-boot.bin>

> +

> +The above is a wrapper script(GenerateCapsule) which eventually calls

> +the actual GenerateCapsule.py script.

> +

> +As per the UEFI specification, the capsule file needs to be placed on

> +the EFI System Partition, under the \EFI\UpdateCapsule directory. The

> +EFI System Partition can be a virtio-blk-device.

> +

> +Before initiating the firmware update, the efi variables BootNext,

> +BootXXXX and OsIndications need to be set. The BootXXXX variable needs

> +to be pointing to the EFI System Partition which contains the capsule

> +file. The BootNext, BootXXXX and OsIndications variables can be set

> +using the following commands::

> +

> +    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>

> +    => efidebug boot next 0

> +    => setenv -e -nv -bs -rt -v OsIndications =0x04

> +    => saveenv

> +

> +Finally, the capsule update can be initiated with the following

> +command::

> +

> +    => efidebug capsule disk-update

> +

> +The updated U-Boot image will be booted on subsequent boot.

> +

> +Enabling Capsule Authentication

> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> +

> +The UEFI specification defines a way of authenticating the capsule to

> +be updated by verifying the capsule signature. The capsule signature

> +is computed and prepended to the capsule payload at the time of

> +capsule generation. This signature is then verified by using the

> +public key stored as part of the X509 certificate. This certificate is

> +in the form of an efi signature list (esl) file, which is embedded as

> +part of the platform's device tree blob using the mkeficapsule

> +utility.

> +

> +On the QEMU virt platforms, the device-tree is generated on the fly

> +based on the devices configured. This device tree is then passed on to

> +the various software components booting on the platform, including

> +U-Boot. Therefore, on the QEMU virt platform, the signatute is

> +embedded on an overlay. This overlay is then applied at runtime to the

> +base platform device-tree. Steps needed for embedding the esl file in

> +the overlay are highlighted below.

> +

> +The capsule authentication feature can be enabled through the

> +following config, in addition to the configs listed above for capsule

> +update::

> +

> +    CONFIG_EFI_CAPSULE_AUTHENTICATE=y

> +

> +The public and private keys used for the signing process are generated

> +and used by the steps highlighted below::

> +

> +    1. Install utility commands on your host

> +       * OPENSSL

> +       * efitools

> +

> +    2. Create signing keys and certificate files on your host

> +

> +        $ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ \

> +            -keyout CRT.key -out CRT.crt -nodes -days 365

> +        $ cert-to-efi-sig-list CRT.crt CRT.esl

> +

> +        $ openssl x509 -in CRT.crt -out CRT.cer -outform DER

> +        $ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem

> +

> +        $ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt

> +        $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem

> +

> +The capsule file can be generated by using the GenerateCapsule.py

> +script in EDKII::

> +

> +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

> +      <capsule_file_name> --monotonic-count <val> --fw-version \

> +      <val> --lsv <val> --guid \

> +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \

> +      --update-image-index <val> --signer-private-cert \

> +      /path/to/CRT.pem --trusted-public-cert \

> +      /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \

> +      <u-boot.bin>

> +

> +Place the capsule generated in the above step on the EFI System

> +Partition under the EFI/UpdateCapsule directory

> +

> +For embedding the public key certificate, the following steps need to

> +be followed::

> +

> +    1. Generate a skeleton overlay dts file, with a single fragment

> +       node and an empty __overlay__ node

> +

> +       A typical skeleton overlay file will look like this

> +

> +       /dts-v1/;

> +       /plugin/;

> +

> +       / {

> +               fragment@0 {

> +                       target-path = "/";

> +                       __overlay__ {

> +                       };

> +               };

> +       };

> +

> +

> +    2. Convert the dts to a corresponding dtb with the following


Shouldn't this be dtbo?

> +       command

> +        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \

> +        <dts_file>

> +

> +    3. Run the dtb file generated above through the mkeficapsule tool

> +       in U-Boot

> +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>

> +

> +Running the above command results in the creation of a 'signature'

> +node in the dtb, under which the public key is stored as a

> +'capsule-key' property. The '-O' option is to be used since the

> +public key certificate(esl) file is being embedded in an overlay.

> +

> +The dtb file embedded with the certificate is now to be placed on an

> +EFI System Partition. This would then be loaded and "merged" with the

> +base platform flattened device-tree(dtb) at runtime.

> +

> +Build U-Boot with the following steps(QEMU ARM64)::

> +

> +    $ make qemu_arm64_defconfig

> +    $ make menuconfig

> +        Disable CONFIG_TFABOOT

> +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE

> +        Enable all configs needed for capsule update(listed above)

> +    $ make all

> +

> +Boot the platform and perform the following steps on the U-Boot

> +command line::

> +

> +    1. Enable capsule authentication by setting the following env

> +       variable

> +

> +        => setenv capsule_authentication_enabled 1

> +        => saveenv

> +

> +    2. Load the overlay dtb to memory and merge it with the base fdt

> +

> +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>

> +        => fdt addr $fdtcontroladdr

> +        => fdt resize <size_of_ov_dtb_file>

> +        => fdt apply <$fdtovaddr>


Having the public key on the disk means that any public key can be
placed here and we get zero security.

We need to build the public key into U-Boot.

Could you, please, investigate how we can adjust the build process
accordingly.

Best regards

Heinrich

> +

> +    3. Set the following environment and UEFI boot variables

> +

> +        => setenv -e -nv -bs -rt -v OsIndications =0x04

> +        => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>

> +        => efidebug boot next 0

> +        => saveenv

> +

> +    4. Finally, the capsule update can be initiated with the following

> +       command

> +

> +        => efidebug capsule disk-update

> +

> +On subsequent reboot, the platform should boot the updated U-Boot binary.

>
Sughosh Ganu March 2, 2021, 2:48 p.m. UTC | #2
hi Heinrich,

On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> On 30.12.20 14:57, Sughosh Ganu wrote:

> > Add documentation highlighting the steps for using the uefi capsule

> > update feature for updating the u-boot firmware image.

> >

> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>

> > ---

> >

> > Changes since V3: None

> >

> >  doc/board/emulation/index.rst               |   1 +

> >  doc/board/emulation/qemu_capsule_update.rst | 210 ++++++++++++++++++++

> >  2 files changed, 211 insertions(+)

> >  create mode 100644 doc/board/emulation/qemu_capsule_update.rst

> >

> > diff --git a/doc/board/emulation/index.rst

> b/doc/board/emulation/index.rst

> > index 1adefee155..a09ead1c35 100644

> > --- a/doc/board/emulation/index.rst

> > +++ b/doc/board/emulation/index.rst

> > @@ -10,3 +10,4 @@ Emulation

> >     qemu-mips

> >     qemu-riscv

> >     qemu-x86

> > +   qemu_capsule_update

> > diff --git a/doc/board/emulation/qemu_capsule_update.rst

> b/doc/board/emulation/qemu_capsule_update.rst

> > new file mode 100644

> > index 0000000000..9fec75f8f1

> > --- /dev/null

> > +++ b/doc/board/emulation/qemu_capsule_update.rst

> > @@ -0,0 +1,210 @@

> > +.. SPDX-License-Identifier: GPL-2.0+

> > +.. Copyright (C) 2020, Linaro Limited

> > +

> > +Enabling UEFI Capsule Update feature

> > +------------------------------------

> > +

> > +Support has been added for the UEFI capsule update feature which

> > +enables updating the U-Boot image using the UEFI firmware management

> > +protocol (fmp). The capsules are not passed to the firmware through

> > +the UpdateCapsule runtime service. Instead, capsule-on-disk

> > +functionality is used for fetching the capsule from the EFI System

> > +Partition (ESP) by placing the capsule file under the

> > +\EFI\UpdateCapsule directory.

> > +

> > +Currently, support has been added on the QEMU ARM64 virt platform for

> > +updating the U-Boot binary as a raw image when the platform is booted

> > +in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this

> > +configuration, the QEMU platform needs to be booted with

> > +'secure=off'. The U-Boot binary placed on the first bank of the NOR

> > +flash at offset 0x0. The U-Boot environment is placed on the second

> > +NOR flash bank at offset 0x4000000.

> > +

> > +The capsule update feature is enabled with the following configuration

> > +settings::

> > +

> > +    CONFIG_MTD=y

> > +    CONFIG_FLASH_CFI_MTD=y

> > +    CONFIG_CMD_MTDPARTS=y

> > +    CONFIG_CMD_DFU=y

> > +    CONFIG_DFU_MTD=y

> > +    CONFIG_PCI_INIT_R=y

> > +    CONFIG_EFI_CAPSULE_ON_DISK=y

> > +    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y

> > +    CONFIG_EFI_CAPSULE_FIRMWARE=y

> > +    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y

> > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y

> > +

> > +In addition, the following config needs to be disabled(QEMU ARM

> specific)::

> > +

> > +    CONFIG_TFABOOT

> > +

> > +The capsule file can be generated by using the GenerateCapsule.py

> > +script in EDKII::

> > +

> > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

> > +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \

> > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose --update-image-index

> \

> > +    <val> --verbose <u-boot.bin>

> > +

> > +The above is a wrapper script(GenerateCapsule) which eventually calls

> > +the actual GenerateCapsule.py script.

> > +

> > +As per the UEFI specification, the capsule file needs to be placed on

> > +the EFI System Partition, under the \EFI\UpdateCapsule directory. The

> > +EFI System Partition can be a virtio-blk-device.

> > +

> > +Before initiating the firmware update, the efi variables BootNext,

> > +BootXXXX and OsIndications need to be set. The BootXXXX variable needs

> > +to be pointing to the EFI System Partition which contains the capsule

> > +file. The BootNext, BootXXXX and OsIndications variables can be set

> > +using the following commands::

> > +

> > +    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>

> > +    => efidebug boot next 0

> > +    => setenv -e -nv -bs -rt -v OsIndications =0x04

> > +    => saveenv

> > +

> > +Finally, the capsule update can be initiated with the following

> > +command::

> > +

> > +    => efidebug capsule disk-update

> > +

> > +The updated U-Boot image will be booted on subsequent boot.

> > +

> > +Enabling Capsule Authentication

> > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> > +

> > +The UEFI specification defines a way of authenticating the capsule to

> > +be updated by verifying the capsule signature. The capsule signature

> > +is computed and prepended to the capsule payload at the time of

> > +capsule generation. This signature is then verified by using the

> > +public key stored as part of the X509 certificate. This certificate is

> > +in the form of an efi signature list (esl) file, which is embedded as

> > +part of the platform's device tree blob using the mkeficapsule

> > +utility.

> > +

> > +On the QEMU virt platforms, the device-tree is generated on the fly

> > +based on the devices configured. This device tree is then passed on to

> > +the various software components booting on the platform, including

> > +U-Boot. Therefore, on the QEMU virt platform, the signatute is

> > +embedded on an overlay. This overlay is then applied at runtime to the

> > +base platform device-tree. Steps needed for embedding the esl file in

> > +the overlay are highlighted below.

> > +

> > +The capsule authentication feature can be enabled through the

> > +following config, in addition to the configs listed above for capsule

> > +update::

> > +

> > +    CONFIG_EFI_CAPSULE_AUTHENTICATE=y

> > +

> > +The public and private keys used for the signing process are generated

> > +and used by the steps highlighted below::

> > +

> > +    1. Install utility commands on your host

> > +       * OPENSSL

> > +       * efitools

> > +

> > +    2. Create signing keys and certificate files on your host

> > +

> > +        $ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ \

> > +            -keyout CRT.key -out CRT.crt -nodes -days 365

> > +        $ cert-to-efi-sig-list CRT.crt CRT.esl

> > +

> > +        $ openssl x509 -in CRT.crt -out CRT.cer -outform DER

> > +        $ openssl x509 -inform DER -in CRT.cer -outform PEM -out

> CRT.pub.pem

> > +

> > +        $ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt

> > +        $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem

> > +

> > +The capsule file can be generated by using the GenerateCapsule.py

> > +script in EDKII::

> > +

> > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

> > +      <capsule_file_name> --monotonic-count <val> --fw-version \

> > +      <val> --lsv <val> --guid \

> > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \

> > +      --update-image-index <val> --signer-private-cert \

> > +      /path/to/CRT.pem --trusted-public-cert \

> > +      /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \

> > +      <u-boot.bin>

> > +

> > +Place the capsule generated in the above step on the EFI System

> > +Partition under the EFI/UpdateCapsule directory

> > +

> > +For embedding the public key certificate, the following steps need to

> > +be followed::

> > +

> > +    1. Generate a skeleton overlay dts file, with a single fragment

> > +       node and an empty __overlay__ node

> > +

> > +       A typical skeleton overlay file will look like this

> > +

> > +       /dts-v1/;

> > +       /plugin/;

> > +

> > +       / {

> > +               fragment@0 {

> > +                       target-path = "/";

> > +                       __overlay__ {

> > +                       };

> > +               };

> > +       };

> > +

> > +

> > +    2. Convert the dts to a corresponding dtb with the following

>

> Shouldn't this be dtbo?

>

> > +       command

> > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \

> > +        <dts_file>

> > +

> > +    3. Run the dtb file generated above through the mkeficapsule tool

> > +       in U-Boot

> > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>

> > +

> > +Running the above command results in the creation of a 'signature'

> > +node in the dtb, under which the public key is stored as a

> > +'capsule-key' property. The '-O' option is to be used since the

> > +public key certificate(esl) file is being embedded in an overlay.

> > +

> > +The dtb file embedded with the certificate is now to be placed on an

> > +EFI System Partition. This would then be loaded and "merged" with the

> > +base platform flattened device-tree(dtb) at runtime.

> > +

> > +Build U-Boot with the following steps(QEMU ARM64)::

> > +

> > +    $ make qemu_arm64_defconfig

> > +    $ make menuconfig

> > +        Disable CONFIG_TFABOOT

> > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE

> > +        Enable all configs needed for capsule update(listed above)

> > +    $ make all

> > +

> > +Boot the platform and perform the following steps on the U-Boot

> > +command line::

> > +

> > +    1. Enable capsule authentication by setting the following env

> > +       variable

> > +

> > +        => setenv capsule_authentication_enabled 1

> > +        => saveenv

> > +

> > +    2. Load the overlay dtb to memory and merge it with the base fdt

> > +

> > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>

> > +        => fdt addr $fdtcontroladdr

> > +        => fdt resize <size_of_ov_dtb_file>

> > +        => fdt apply <$fdtovaddr>

>

> Having the public key on the disk means that any public key can be

> placed here and we get zero security.

>


But that does not mean the authentication will succeed unless the private
key is compromised. Deleting or tampering the public key on the disk can
result in a denial of service attack, as the capsule authentication would
fail, but that is true even when the public key is embedded in u-boot --
the public key or the u-boot image can be tampered with, resulting in a
board brick. For countering this kind of denial of service attack, the
public key needs to be placed on a secure storage device, which cannot be
modified or removed from the normal world. Moreover, how is this different
to the placement of the signature database used for the uefi secure boot as
part of the uefi authenticated variables on a storage device that can be
accessed from the normal world.

-sughosh


>

> We need to build the public key into U-Boot.

>

> Could you, please, investigate how we can adjust the build process

> accordingly.

>

> Best regards

>

> Heinrich

>

> > +

> > +    3. Set the following environment and UEFI boot variables

> > +

> > +        => setenv -e -nv -bs -rt -v OsIndications =0x04

> > +        => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>

> > +        => efidebug boot next 0

> > +        => saveenv

> > +

> > +    4. Finally, the capsule update can be initiated with the following

> > +       command

> > +

> > +        => efidebug capsule disk-update

> > +

> > +On subsequent reboot, the platform should boot the updated U-Boot

> binary.

> >

>

>
Heinrich Schuchardt March 2, 2021, 3:57 p.m. UTC | #3
On 02.03.21 15:48, Sughosh Ganu wrote:
> hi Heinrich,

>

> On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt <xypron.glpk@gmx.de

> <mailto:xypron.glpk@gmx.de>> wrote:

>

>     On 30.12.20 14:57, Sughosh Ganu wrote:

>     > Add documentation highlighting the steps for using the uefi capsule

>     > update feature for updating the u-boot firmware image.

>     >

>     > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org

>     <mailto:sughosh.ganu@linaro.org>>

>     > ---

>     >

>     > Changes since V3: None

>     >

>     >  doc/board/emulation/index.rst               |   1 +

>     >  doc/board/emulation/qemu_capsule_update.rst | 210

>     ++++++++++++++++++++

>     >  2 files changed, 211 insertions(+)

>     >  create mode 100644 doc/board/emulation/qemu_capsule_update.rst

>     >

>     > diff --git a/doc/board/emulation/index.rst

>     b/doc/board/emulation/index.rst

>     > index 1adefee155..a09ead1c35 100644

>     > --- a/doc/board/emulation/index.rst

>     > +++ b/doc/board/emulation/index.rst

>     > @@ -10,3 +10,4 @@ Emulation

>     >     qemu-mips

>     >     qemu-riscv

>     >     qemu-x86

>     > +   qemu_capsule_update

>     > diff --git a/doc/board/emulation/qemu_capsule_update.rst

>     b/doc/board/emulation/qemu_capsule_update.rst

>     > new file mode 100644

>     > index 0000000000..9fec75f8f1

>     > --- /dev/null

>     > +++ b/doc/board/emulation/qemu_capsule_update.rst

>     > @@ -0,0 +1,210 @@

>     > +.. SPDX-License-Identifier: GPL-2.0+

>     > +.. Copyright (C) 2020, Linaro Limited

>     > +

>     > +Enabling UEFI Capsule Update feature

>     > +------------------------------------

>     > +

>     > +Support has been added for the UEFI capsule update feature which

>     > +enables updating the U-Boot image using the UEFI firmware management

>     > +protocol (fmp). The capsules are not passed to the firmware through

>     > +the UpdateCapsule runtime service. Instead, capsule-on-disk

>     > +functionality is used for fetching the capsule from the EFI System

>     > +Partition (ESP) by placing the capsule file under the

>     > +\EFI\UpdateCapsule directory.

>     > +

>     > +Currently, support has been added on the QEMU ARM64 virt platform for

>     > +updating the U-Boot binary as a raw image when the platform is booted

>     > +in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this

>     > +configuration, the QEMU platform needs to be booted with

>     > +'secure=off'. The U-Boot binary placed on the first bank of the NOR

>     > +flash at offset 0x0. The U-Boot environment is placed on the second

>     > +NOR flash bank at offset 0x4000000.

>     > +

>     > +The capsule update feature is enabled with the following

>     configuration

>     > +settings::

>     > +

>     > +    CONFIG_MTD=y

>     > +    CONFIG_FLASH_CFI_MTD=y

>     > +    CONFIG_CMD_MTDPARTS=y

>     > +    CONFIG_CMD_DFU=y

>     > +    CONFIG_DFU_MTD=y

>     > +    CONFIG_PCI_INIT_R=y

>     > +    CONFIG_EFI_CAPSULE_ON_DISK=y

>     > +    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y

>     > +    CONFIG_EFI_CAPSULE_FIRMWARE=y

>     > +    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y

>     > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y

>     > +

>     > +In addition, the following config needs to be disabled(QEMU ARM

>     specific)::

>     > +

>     > +    CONFIG_TFABOOT

>     > +

>     > +The capsule file can be generated by using the GenerateCapsule.py

>     > +script in EDKII::

>     > +

>     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

>     > +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \

>     > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose

>     --update-image-index \

>     > +    <val> --verbose <u-boot.bin>

>     > +

>     > +The above is a wrapper script(GenerateCapsule) which eventually calls

>     > +the actual GenerateCapsule.py script.

>     > +

>     > +As per the UEFI specification, the capsule file needs to be placed on

>     > +the EFI System Partition, under the \EFI\UpdateCapsule directory. The

>     > +EFI System Partition can be a virtio-blk-device.

>     > +

>     > +Before initiating the firmware update, the efi variables BootNext,

>     > +BootXXXX and OsIndications need to be set. The BootXXXX variable

>     needs

>     > +to be pointing to the EFI System Partition which contains the capsule

>     > +file. The BootNext, BootXXXX and OsIndications variables can be set

>     > +using the following commands::

>     > +

>     > +    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>

>     > +    => efidebug boot next 0

>     > +    => setenv -e -nv -bs -rt -v OsIndications =0x04

>     > +    => saveenv

>     > +

>     > +Finally, the capsule update can be initiated with the following

>     > +command::

>     > +

>     > +    => efidebug capsule disk-update

>     > +

>     > +The updated U-Boot image will be booted on subsequent boot.

>     > +

>     > +Enabling Capsule Authentication

>     > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>     > +

>     > +The UEFI specification defines a way of authenticating the capsule to

>     > +be updated by verifying the capsule signature. The capsule signature

>     > +is computed and prepended to the capsule payload at the time of

>     > +capsule generation. This signature is then verified by using the

>     > +public key stored as part of the X509 certificate. This

>     certificate is

>     > +in the form of an efi signature list (esl) file, which is embedded as

>     > +part of the platform's device tree blob using the mkeficapsule

>     > +utility.

>     > +

>     > +On the QEMU virt platforms, the device-tree is generated on the fly

>     > +based on the devices configured. This device tree is then passed

>     on to

>     > +the various software components booting on the platform, including

>     > +U-Boot. Therefore, on the QEMU virt platform, the signatute is

>     > +embedded on an overlay. This overlay is then applied at runtime

>     to the

>     > +base platform device-tree. Steps needed for embedding the esl file in

>     > +the overlay are highlighted below.

>     > +

>     > +The capsule authentication feature can be enabled through the

>     > +following config, in addition to the configs listed above for capsule

>     > +update::

>     > +

>     > +    CONFIG_EFI_CAPSULE_AUTHENTICATE=y

>     > +

>     > +The public and private keys used for the signing process are

>     generated

>     > +and used by the steps highlighted below::

>     > +

>     > +    1. Install utility commands on your host

>     > +       * OPENSSL

>     > +       * efitools

>     > +

>     > +    2. Create signing keys and certificate files on your host

>     > +

>     > +        $ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ \

>     > +            -keyout CRT.key -out CRT.crt -nodes -days 365

>     > +        $ cert-to-efi-sig-list CRT.crt CRT.esl

>     > +

>     > +        $ openssl x509 -in CRT.crt -out CRT.cer -outform DER

>     > +        $ openssl x509 -inform DER -in CRT.cer -outform PEM -out

>     CRT.pub.pem

>     > +

>     > +        $ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in

>     CRT.crt

>     > +        $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem

>     > +

>     > +The capsule file can be generated by using the GenerateCapsule.py

>     > +script in EDKII::

>     > +

>     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

>     > +      <capsule_file_name> --monotonic-count <val> --fw-version \

>     > +      <val> --lsv <val> --guid \

>     > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \

>     > +      --update-image-index <val> --signer-private-cert \

>     > +      /path/to/CRT.pem --trusted-public-cert \

>     > +      /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \

>     > +      <u-boot.bin>

>     > +

>     > +Place the capsule generated in the above step on the EFI System

>     > +Partition under the EFI/UpdateCapsule directory

>     > +

>     > +For embedding the public key certificate, the following steps need to

>     > +be followed::

>     > +

>     > +    1. Generate a skeleton overlay dts file, with a single fragment

>     > +       node and an empty __overlay__ node

>     > +

>     > +       A typical skeleton overlay file will look like this

>     > +

>     > +       /dts-v1/;

>     > +       /plugin/;

>     > +

>     > +       / {

>     > +               fragment@0 {

>     > +                       target-path = "/";

>     > +                       __overlay__ {

>     > +                       };

>     > +               };

>     > +       };

>     > +

>     > +

>     > +    2. Convert the dts to a corresponding dtb with the following

>

>     Shouldn't this be dtbo?

>

>     > +       command

>     > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \

>     > +        <dts_file>

>     > +

>     > +    3. Run the dtb file generated above through the mkeficapsule tool

>     > +       in U-Boot

>     > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>

>     > +

>     > +Running the above command results in the creation of a 'signature'

>     > +node in the dtb, under which the public key is stored as a

>     > +'capsule-key' property. The '-O' option is to be used since the

>     > +public key certificate(esl) file is being embedded in an overlay.

>     > +

>     > +The dtb file embedded with the certificate is now to be placed on an

>     > +EFI System Partition. This would then be loaded and "merged" with the

>     > +base platform flattened device-tree(dtb) at runtime.

>     > +

>     > +Build U-Boot with the following steps(QEMU ARM64)::

>     > +

>     > +    $ make qemu_arm64_defconfig

>     > +    $ make menuconfig

>     > +        Disable CONFIG_TFABOOT

>     > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE

>     > +        Enable all configs needed for capsule update(listed above)

>     > +    $ make all

>     > +

>     > +Boot the platform and perform the following steps on the U-Boot

>     > +command line::

>     > +

>     > +    1. Enable capsule authentication by setting the following env

>     > +       variable

>     > +

>     > +        => setenv capsule_authentication_enabled 1

>     > +        => saveenv

>     > +

>     > +    2. Load the overlay dtb to memory and merge it with the base fdt

>     > +

>     > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>

>     > +        => fdt addr $fdtcontroladdr

>     > +        => fdt resize <size_of_ov_dtb_file>

>     > +        => fdt apply <$fdtovaddr>

>

>     Having the public key on the disk means that any public key can be

>     placed here and we get zero security.

>

>

> But that does not mean the authentication will succeed unless the

> private key is compromised. Deleting or tampering the public key on the

> disk can result in a denial of service attack, as the capsule

> authentication would fail, but that is true even when the public key is

> embedded in u-boot -- the public key or the u-boot image can be tampered

> with, resulting in a board brick. For countering this kind of denial of

> service attack, the public key needs to be placed on a secure storage

> device, which cannot be modified or removed from the normal world.

> Moreover, how is this different to the placement of the signature

> database used for the uefi secure boot as part of the uefi authenticated

> variables on a storage device that can be accessed from the normal world.


The public key is what you use to verify that a capsule was signed by an
authorized party. Who controls the public keys used for capsule checking
can crack the device:

I just have to create a public/private key pair to sign my malware and
place both the public key and the malware capsule on the disk.

We should not allow public keys for capsules to be on disk.

TF-A checks BL33 (U-Boot). If the public key is part of BL33 then only
capsules signed with this trusted key can be installed.

An attacker can still change U-Boot in a way that TF-A will not load it
leading to a denial of service. But he cannot launch malware via capsules.

Best regards

Heinrich
>

>

>     We need to build the public key into U-Boot.

>

>     Could you, please, investigate how we can adjust the build process

>     accordingly.

>

>     Best regards

>

>     Heinrich

>

>     > +

>     > +    3. Set the following environment and UEFI boot variables

>     > +

>     > +        => setenv -e -nv -bs -rt -v OsIndications =0x04

>     > +        => efidebug boot add 0 Boot0000 virtio 0:1

>     <capsule_file_name>

>     > +        => efidebug boot next 0

>     > +        => saveenv

>     > +

>     > +    4. Finally, the capsule update can be initiated with the

>     following

>     > +       command

>     > +

>     > +        => efidebug capsule disk-update

>     > +

>     > +On subsequent reboot, the platform should boot the updated U-Boot

>     binary.

>     >

>
Sughosh Ganu March 2, 2021, 4:39 p.m. UTC | #4
On Tue, 2 Mar 2021 at 21:27, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> On 02.03.21 15:48, Sughosh Ganu wrote:

> > hi Heinrich,

> >

> > On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt <xypron.glpk@gmx.de

> > <mailto:xypron.glpk@gmx.de>> wrote:

> >

> >     On 30.12.20 14:57, Sughosh Ganu wrote:

> >     > Add documentation highlighting the steps for using the uefi capsule

> >     > update feature for updating the u-boot firmware image.

> >     >

> >     > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org

> >     <mailto:sughosh.ganu@linaro.org>>

> >     > ---

> >     >

> >     > Changes since V3: None

> >     >

> >     >  doc/board/emulation/index.rst               |   1 +

> >     >  doc/board/emulation/qemu_capsule_update.rst | 210

> >     ++++++++++++++++++++

> >     >  2 files changed, 211 insertions(+)

> >     >  create mode 100644 doc/board/emulation/qemu_capsule_update.rst

> >     >

> >     > diff --git a/doc/board/emulation/index.rst

> >     b/doc/board/emulation/index.rst

> >     > index 1adefee155..a09ead1c35 100644

> >     > --- a/doc/board/emulation/index.rst

> >     > +++ b/doc/board/emulation/index.rst

> >     > @@ -10,3 +10,4 @@ Emulation

> >     >     qemu-mips

> >     >     qemu-riscv

> >     >     qemu-x86

> >     > +   qemu_capsule_update

> >     > diff --git a/doc/board/emulation/qemu_capsule_update.rst

> >     b/doc/board/emulation/qemu_capsule_update.rst

> >     > new file mode 100644

> >     > index 0000000000..9fec75f8f1

> >     > --- /dev/null

> >     > +++ b/doc/board/emulation/qemu_capsule_update.rst

> >     > @@ -0,0 +1,210 @@

> >     > +.. SPDX-License-Identifier: GPL-2.0+

> >     > +.. Copyright (C) 2020, Linaro Limited

> >     > +

> >     > +Enabling UEFI Capsule Update feature

> >     > +------------------------------------

> >     > +

> >     > +Support has been added for the UEFI capsule update feature which

> >     > +enables updating the U-Boot image using the UEFI firmware

> management

> >     > +protocol (fmp). The capsules are not passed to the firmware

> through

> >     > +the UpdateCapsule runtime service. Instead, capsule-on-disk

> >     > +functionality is used for fetching the capsule from the EFI System

> >     > +Partition (ESP) by placing the capsule file under the

> >     > +\EFI\UpdateCapsule directory.

> >     > +

> >     > +Currently, support has been added on the QEMU ARM64 virt platform

> for

> >     > +updating the U-Boot binary as a raw image when the platform is

> booted

> >     > +in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this

> >     > +configuration, the QEMU platform needs to be booted with

> >     > +'secure=off'. The U-Boot binary placed on the first bank of the

> NOR

> >     > +flash at offset 0x0. The U-Boot environment is placed on the

> second

> >     > +NOR flash bank at offset 0x4000000.

> >     > +

> >     > +The capsule update feature is enabled with the following

> >     configuration

> >     > +settings::

> >     > +

> >     > +    CONFIG_MTD=y

> >     > +    CONFIG_FLASH_CFI_MTD=y

> >     > +    CONFIG_CMD_MTDPARTS=y

> >     > +    CONFIG_CMD_DFU=y

> >     > +    CONFIG_DFU_MTD=y

> >     > +    CONFIG_PCI_INIT_R=y

> >     > +    CONFIG_EFI_CAPSULE_ON_DISK=y

> >     > +    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y

> >     > +    CONFIG_EFI_CAPSULE_FIRMWARE=y

> >     > +    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y

> >     > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y

> >     > +

> >     > +In addition, the following config needs to be disabled(QEMU ARM

> >     specific)::

> >     > +

> >     > +    CONFIG_TFABOOT

> >     > +

> >     > +The capsule file can be generated by using the GenerateCapsule.py

> >     > +script in EDKII::

> >     > +

> >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

> >     > +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \

> >     > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose

> >     --update-image-index \

> >     > +    <val> --verbose <u-boot.bin>

> >     > +

> >     > +The above is a wrapper script(GenerateCapsule) which eventually

> calls

> >     > +the actual GenerateCapsule.py script.

> >     > +

> >     > +As per the UEFI specification, the capsule file needs to be

> placed on

> >     > +the EFI System Partition, under the \EFI\UpdateCapsule directory.

> The

> >     > +EFI System Partition can be a virtio-blk-device.

> >     > +

> >     > +Before initiating the firmware update, the efi variables BootNext,

> >     > +BootXXXX and OsIndications need to be set. The BootXXXX variable

> >     needs

> >     > +to be pointing to the EFI System Partition which contains the

> capsule

> >     > +file. The BootNext, BootXXXX and OsIndications variables can be

> set

> >     > +using the following commands::

> >     > +

> >     > +    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>

> >     > +    => efidebug boot next 0

> >     > +    => setenv -e -nv -bs -rt -v OsIndications =0x04

> >     > +    => saveenv

> >     > +

> >     > +Finally, the capsule update can be initiated with the following

> >     > +command::

> >     > +

> >     > +    => efidebug capsule disk-update

> >     > +

> >     > +The updated U-Boot image will be booted on subsequent boot.

> >     > +

> >     > +Enabling Capsule Authentication

> >     > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> >     > +

> >     > +The UEFI specification defines a way of authenticating the

> capsule to

> >     > +be updated by verifying the capsule signature. The capsule

> signature

> >     > +is computed and prepended to the capsule payload at the time of

> >     > +capsule generation. This signature is then verified by using the

> >     > +public key stored as part of the X509 certificate. This

> >     certificate is

> >     > +in the form of an efi signature list (esl) file, which is

> embedded as

> >     > +part of the platform's device tree blob using the mkeficapsule

> >     > +utility.

> >     > +

> >     > +On the QEMU virt platforms, the device-tree is generated on the

> fly

> >     > +based on the devices configured. This device tree is then passed

> >     on to

> >     > +the various software components booting on the platform, including

> >     > +U-Boot. Therefore, on the QEMU virt platform, the signatute is

> >     > +embedded on an overlay. This overlay is then applied at runtime

> >     to the

> >     > +base platform device-tree. Steps needed for embedding the esl

> file in

> >     > +the overlay are highlighted below.

> >     > +

> >     > +The capsule authentication feature can be enabled through the

> >     > +following config, in addition to the configs listed above for

> capsule

> >     > +update::

> >     > +

> >     > +    CONFIG_EFI_CAPSULE_AUTHENTICATE=y

> >     > +

> >     > +The public and private keys used for the signing process are

> >     generated

> >     > +and used by the steps highlighted below::

> >     > +

> >     > +    1. Install utility commands on your host

> >     > +       * OPENSSL

> >     > +       * efitools

> >     > +

> >     > +    2. Create signing keys and certificate files on your host

> >     > +

> >     > +        $ openssl req -x509 -sha256 -newkey rsa:2048 -subj

> /CN=CRT/ \

> >     > +            -keyout CRT.key -out CRT.crt -nodes -days 365

> >     > +        $ cert-to-efi-sig-list CRT.crt CRT.esl

> >     > +

> >     > +        $ openssl x509 -in CRT.crt -out CRT.cer -outform DER

> >     > +        $ openssl x509 -inform DER -in CRT.cer -outform PEM -out

> >     CRT.pub.pem

> >     > +

> >     > +        $ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in

> >     CRT.crt

> >     > +        $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem

> >     > +

> >     > +The capsule file can be generated by using the GenerateCapsule.py

> >     > +script in EDKII::

> >     > +

> >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

> >     > +      <capsule_file_name> --monotonic-count <val> --fw-version \

> >     > +      <val> --lsv <val> --guid \

> >     > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \

> >     > +      --update-image-index <val> --signer-private-cert \

> >     > +      /path/to/CRT.pem --trusted-public-cert \

> >     > +      /path/to/CRT.pub.pem --other-public-cert

> /path/to/CRT.pub.pem \

> >     > +      <u-boot.bin>

> >     > +

> >     > +Place the capsule generated in the above step on the EFI System

> >     > +Partition under the EFI/UpdateCapsule directory

> >     > +

> >     > +For embedding the public key certificate, the following steps

> need to

> >     > +be followed::

> >     > +

> >     > +    1. Generate a skeleton overlay dts file, with a single

> fragment

> >     > +       node and an empty __overlay__ node

> >     > +

> >     > +       A typical skeleton overlay file will look like this

> >     > +

> >     > +       /dts-v1/;

> >     > +       /plugin/;

> >     > +

> >     > +       / {

> >     > +               fragment@0 {

> >     > +                       target-path = "/";

> >     > +                       __overlay__ {

> >     > +                       };

> >     > +               };

> >     > +       };

> >     > +

> >     > +

> >     > +    2. Convert the dts to a corresponding dtb with the following

> >

> >     Shouldn't this be dtbo?

> >

> >     > +       command

> >     > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \

> >     > +        <dts_file>

> >     > +

> >     > +    3. Run the dtb file generated above through the mkeficapsule

> tool

> >     > +       in U-Boot

> >     > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>

> >     > +

> >     > +Running the above command results in the creation of a 'signature'

> >     > +node in the dtb, under which the public key is stored as a

> >     > +'capsule-key' property. The '-O' option is to be used since the

> >     > +public key certificate(esl) file is being embedded in an overlay.

> >     > +

> >     > +The dtb file embedded with the certificate is now to be placed on

> an

> >     > +EFI System Partition. This would then be loaded and "merged" with

> the

> >     > +base platform flattened device-tree(dtb) at runtime.

> >     > +

> >     > +Build U-Boot with the following steps(QEMU ARM64)::

> >     > +

> >     > +    $ make qemu_arm64_defconfig

> >     > +    $ make menuconfig

> >     > +        Disable CONFIG_TFABOOT

> >     > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE

> >     > +        Enable all configs needed for capsule update(listed above)

> >     > +    $ make all

> >     > +

> >     > +Boot the platform and perform the following steps on the U-Boot

> >     > +command line::

> >     > +

> >     > +    1. Enable capsule authentication by setting the following env

> >     > +       variable

> >     > +

> >     > +        => setenv capsule_authentication_enabled 1

> >     > +        => saveenv

> >     > +

> >     > +    2. Load the overlay dtb to memory and merge it with the base

> fdt

> >     > +

> >     > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>

> >     > +        => fdt addr $fdtcontroladdr

> >     > +        => fdt resize <size_of_ov_dtb_file>

> >     > +        => fdt apply <$fdtovaddr>

> >

> >     Having the public key on the disk means that any public key can be

> >     placed here and we get zero security.

> >

> >

> > But that does not mean the authentication will succeed unless the

> > private key is compromised. Deleting or tampering the public key on the

> > disk can result in a denial of service attack, as the capsule

> > authentication would fail, but that is true even when the public key is

> > embedded in u-boot -- the public key or the u-boot image can be tampered

> > with, resulting in a board brick. For countering this kind of denial of

> > service attack, the public key needs to be placed on a secure storage

> > device, which cannot be modified or removed from the normal world.

> > Moreover, how is this different to the placement of the signature

> > database used for the uefi secure boot as part of the uefi authenticated

> > variables on a storage device that can be accessed from the normal world.

>

> The public key is what you use to verify that a capsule was signed by an

> authorized party. Who controls the public keys used for capsule checking

> can crack the device:

>

> I just have to create a public/private key pair to sign my malware and

> place both the public key and the malware capsule on the disk.

>


But when tf-a verifies this this BL33 during boot, it would fail
authentication and would not boot that BL33 image. So it is the same as
denial of service, isn't it.

-sughosh


>

> We should not allow public keys for capsules to be on disk.

>

> TF-A checks BL33 (U-Boot). If the public key is part of BL33 then only

> capsules signed with this trusted key can be installed.

>

> An attacker can still change U-Boot in a way that TF-A will not load it

> leading to a denial of service. But he cannot launch malware via capsules.

>

> Best regards

>

> Heinrich

> >

> >

> >     We need to build the public key into U-Boot.

> >

> >     Could you, please, investigate how we can adjust the build process

> >     accordingly.

> >

> >     Best regards

> >

> >     Heinrich

> >

> >     > +

> >     > +    3. Set the following environment and UEFI boot variables

> >     > +

> >     > +        => setenv -e -nv -bs -rt -v OsIndications =0x04

> >     > +        => efidebug boot add 0 Boot0000 virtio 0:1

> >     <capsule_file_name>

> >     > +        => efidebug boot next 0

> >     > +        => saveenv

> >     > +

> >     > +    4. Finally, the capsule update can be initiated with the

> >     following

> >     > +       command

> >     > +

> >     > +        => efidebug capsule disk-update

> >     > +

> >     > +On subsequent reboot, the platform should boot the updated U-Boot

> >     binary.

> >     >

> >

>

>
Heinrich Schuchardt March 2, 2021, 5:06 p.m. UTC | #5
On 02.03.21 17:39, Sughosh Ganu wrote:
>

>

> On Tue, 2 Mar 2021 at 21:27, Heinrich Schuchardt <xypron.glpk@gmx.de

> <mailto:xypron.glpk@gmx.de>> wrote:

>

>     On 02.03.21 15:48, Sughosh Ganu wrote:

>     > hi Heinrich,

>     >

>     > On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt

>     <xypron.glpk@gmx.de <mailto:xypron.glpk@gmx.de>

>     > <mailto:xypron.glpk@gmx.de <mailto:xypron.glpk@gmx.de>>> wrote:

>     >

>     >     On 30.12.20 14:57, Sughosh Ganu wrote:

>     >     > Add documentation highlighting the steps for using the uefi

>     capsule

>     >     > update feature for updating the u-boot firmware image.

>     >     >

>     >     > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org

>     <mailto:sughosh.ganu@linaro.org>

>     >     <mailto:sughosh.ganu@linaro.org <mailto:sughosh.ganu@linaro.org>>>

>     >     > ---

>     >     >

>     >     > Changes since V3: None

>     >     >

>     >     >  doc/board/emulation/index.rst               |   1 +

>     >     >  doc/board/emulation/qemu_capsule_update.rst | 210

>     >     ++++++++++++++++++++

>     >     >  2 files changed, 211 insertions(+)

>     >     >  create mode 100644 doc/board/emulation/qemu_capsule_update.rst

>     >     >

>     >     > diff --git a/doc/board/emulation/index.rst

>     >     b/doc/board/emulation/index.rst

>     >     > index 1adefee155..a09ead1c35 100644

>     >     > --- a/doc/board/emulation/index.rst

>     >     > +++ b/doc/board/emulation/index.rst

>     >     > @@ -10,3 +10,4 @@ Emulation

>     >     >     qemu-mips

>     >     >     qemu-riscv

>     >     >     qemu-x86

>     >     > +   qemu_capsule_update

>     >     > diff --git a/doc/board/emulation/qemu_capsule_update.rst

>     >     b/doc/board/emulation/qemu_capsule_update.rst

>     >     > new file mode 100644

>     >     > index 0000000000..9fec75f8f1

>     >     > --- /dev/null

>     >     > +++ b/doc/board/emulation/qemu_capsule_update.rst

>     >     > @@ -0,0 +1,210 @@

>     >     > +.. SPDX-License-Identifier: GPL-2.0+

>     >     > +.. Copyright (C) 2020, Linaro Limited

>     >     > +

>     >     > +Enabling UEFI Capsule Update feature

>     >     > +------------------------------------

>     >     > +

>     >     > +Support has been added for the UEFI capsule update feature

>     which

>     >     > +enables updating the U-Boot image using the UEFI firmware

>     management

>     >     > +protocol (fmp). The capsules are not passed to the firmware

>     through

>     >     > +the UpdateCapsule runtime service. Instead, capsule-on-disk

>     >     > +functionality is used for fetching the capsule from the EFI

>     System

>     >     > +Partition (ESP) by placing the capsule file under the

>     >     > +\EFI\UpdateCapsule directory.

>     >     > +

>     >     > +Currently, support has been added on the QEMU ARM64 virt

>     platform for

>     >     > +updating the U-Boot binary as a raw image when the platform

>     is booted

>     >     > +in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this

>     >     > +configuration, the QEMU platform needs to be booted with

>     >     > +'secure=off'. The U-Boot binary placed on the first bank of

>     the NOR

>     >     > +flash at offset 0x0. The U-Boot environment is placed on

>     the second

>     >     > +NOR flash bank at offset 0x4000000.

>     >     > +

>     >     > +The capsule update feature is enabled with the following

>     >     configuration

>     >     > +settings::

>     >     > +

>     >     > +    CONFIG_MTD=y

>     >     > +    CONFIG_FLASH_CFI_MTD=y

>     >     > +    CONFIG_CMD_MTDPARTS=y

>     >     > +    CONFIG_CMD_DFU=y

>     >     > +    CONFIG_DFU_MTD=y

>     >     > +    CONFIG_PCI_INIT_R=y

>     >     > +    CONFIG_EFI_CAPSULE_ON_DISK=y

>     >     > +    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y

>     >     > +    CONFIG_EFI_CAPSULE_FIRMWARE=y

>     >     > +    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y

>     >     > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y

>     >     > +

>     >     > +In addition, the following config needs to be disabled(QEMU ARM

>     >     specific)::

>     >     > +

>     >     > +    CONFIG_TFABOOT

>     >     > +

>     >     > +The capsule file can be generated by using the

>     GenerateCapsule.py

>     >     > +script in EDKII::

>     >     > +

>     >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

>     >     > +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \

>     >     > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose

>     >     --update-image-index \

>     >     > +    <val> --verbose <u-boot.bin>

>     >     > +

>     >     > +The above is a wrapper script(GenerateCapsule) which

>     eventually calls

>     >     > +the actual GenerateCapsule.py script.

>     >     > +

>     >     > +As per the UEFI specification, the capsule file needs to be

>     placed on

>     >     > +the EFI System Partition, under the \EFI\UpdateCapsule

>     directory. The

>     >     > +EFI System Partition can be a virtio-blk-device.

>     >     > +

>     >     > +Before initiating the firmware update, the efi variables

>     BootNext,

>     >     > +BootXXXX and OsIndications need to be set. The BootXXXX

>     variable

>     >     needs

>     >     > +to be pointing to the EFI System Partition which contains

>     the capsule

>     >     > +file. The BootNext, BootXXXX and OsIndications variables

>     can be set

>     >     > +using the following commands::

>     >     > +

>     >     > +    => efidebug boot add 0 Boot0000 virtio 0:1

>     <capsule_file_name>

>     >     > +    => efidebug boot next 0

>     >     > +    => setenv -e -nv -bs -rt -v OsIndications =0x04

>     >     > +    => saveenv

>     >     > +

>     >     > +Finally, the capsule update can be initiated with the following

>     >     > +command::

>     >     > +

>     >     > +    => efidebug capsule disk-update

>     >     > +

>     >     > +The updated U-Boot image will be booted on subsequent boot.

>     >     > +

>     >     > +Enabling Capsule Authentication

>     >     > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

>     >     > +

>     >     > +The UEFI specification defines a way of authenticating the

>     capsule to

>     >     > +be updated by verifying the capsule signature. The capsule

>     signature

>     >     > +is computed and prepended to the capsule payload at the time of

>     >     > +capsule generation. This signature is then verified by

>     using the

>     >     > +public key stored as part of the X509 certificate. This

>     >     certificate is

>     >     > +in the form of an efi signature list (esl) file, which is

>     embedded as

>     >     > +part of the platform's device tree blob using the mkeficapsule

>     >     > +utility.

>     >     > +

>     >     > +On the QEMU virt platforms, the device-tree is generated on

>     the fly

>     >     > +based on the devices configured. This device tree is then

>     passed

>     >     on to

>     >     > +the various software components booting on the platform,

>     including

>     >     > +U-Boot. Therefore, on the QEMU virt platform, the signatute is

>     >     > +embedded on an overlay. This overlay is then applied at runtime

>     >     to the

>     >     > +base platform device-tree. Steps needed for embedding the

>     esl file in

>     >     > +the overlay are highlighted below.

>     >     > +

>     >     > +The capsule authentication feature can be enabled through the

>     >     > +following config, in addition to the configs listed above

>     for capsule

>     >     > +update::

>     >     > +

>     >     > +    CONFIG_EFI_CAPSULE_AUTHENTICATE=y

>     >     > +

>     >     > +The public and private keys used for the signing process are

>     >     generated

>     >     > +and used by the steps highlighted below::

>     >     > +

>     >     > +    1. Install utility commands on your host

>     >     > +       * OPENSSL

>     >     > +       * efitools

>     >     > +

>     >     > +    2. Create signing keys and certificate files on your host

>     >     > +

>     >     > +        $ openssl req -x509 -sha256 -newkey rsa:2048 -subj

>     /CN=CRT/ \

>     >     > +            -keyout CRT.key -out CRT.crt -nodes -days 365

>     >     > +        $ cert-to-efi-sig-list CRT.crt CRT.esl

>     >     > +

>     >     > +        $ openssl x509 -in CRT.crt -out CRT.cer -outform DER

>     >     > +        $ openssl x509 -inform DER -in CRT.cer -outform PEM

>     -out

>     >     CRT.pub.pem

>     >     > +

>     >     > +        $ openssl pkcs12 -export -out CRT.pfx -inkey

>     CRT.key -in

>     >     CRT.crt

>     >     > +        $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem

>     >     > +

>     >     > +The capsule file can be generated by using the

>     GenerateCapsule.py

>     >     > +script in EDKII::

>     >     > +

>     >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \

>     >     > +      <capsule_file_name> --monotonic-count <val>

>     --fw-version \

>     >     > +      <val> --lsv <val> --guid \

>     >     > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \

>     >     > +      --update-image-index <val> --signer-private-cert \

>     >     > +      /path/to/CRT.pem --trusted-public-cert \

>     >     > +      /path/to/CRT.pub.pem --other-public-cert

>     /path/to/CRT.pub.pem \

>     >     > +      <u-boot.bin>

>     >     > +

>     >     > +Place the capsule generated in the above step on the EFI System

>     >     > +Partition under the EFI/UpdateCapsule directory

>     >     > +

>     >     > +For embedding the public key certificate, the following

>     steps need to

>     >     > +be followed::

>     >     > +

>     >     > +    1. Generate a skeleton overlay dts file, with a single

>     fragment

>     >     > +       node and an empty __overlay__ node

>     >     > +

>     >     > +       A typical skeleton overlay file will look like this

>     >     > +

>     >     > +       /dts-v1/;

>     >     > +       /plugin/;

>     >     > +

>     >     > +       / {

>     >     > +               fragment@0 {

>     >     > +                       target-path = "/";

>     >     > +                       __overlay__ {

>     >     > +                       };

>     >     > +               };

>     >     > +       };

>     >     > +

>     >     > +

>     >     > +    2. Convert the dts to a corresponding dtb with the

>     following

>     >

>     >     Shouldn't this be dtbo?

>     >

>     >     > +       command

>     >     > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o

>     <ov_dtb_file_name> \

>     >     > +        <dts_file>

>     >     > +

>     >     > +    3. Run the dtb file generated above through the

>     mkeficapsule tool

>     >     > +       in U-Boot

>     >     > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>

>     >     > +

>     >     > +Running the above command results in the creation of a

>     'signature'

>     >     > +node in the dtb, under which the public key is stored as a

>     >     > +'capsule-key' property. The '-O' option is to be used since the

>     >     > +public key certificate(esl) file is being embedded in an

>     overlay.

>     >     > +

>     >     > +The dtb file embedded with the certificate is now to be

>     placed on an

>     >     > +EFI System Partition. This would then be loaded and

>     "merged" with the

>     >     > +base platform flattened device-tree(dtb) at runtime.

>     >     > +

>     >     > +Build U-Boot with the following steps(QEMU ARM64)::

>     >     > +

>     >     > +    $ make qemu_arm64_defconfig

>     >     > +    $ make menuconfig

>     >     > +        Disable CONFIG_TFABOOT

>     >     > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE

>     >     > +        Enable all configs needed for capsule update(listed

>     above)

>     >     > +    $ make all

>     >     > +

>     >     > +Boot the platform and perform the following steps on the U-Boot

>     >     > +command line::

>     >     > +

>     >     > +    1. Enable capsule authentication by setting the

>     following env

>     >     > +       variable

>     >     > +

>     >     > +        => setenv capsule_authentication_enabled 1

>     >     > +        => saveenv

>     >     > +

>     >     > +    2. Load the overlay dtb to memory and merge it with the

>     base fdt

>     >     > +

>     >     > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>

>     >     > +        => fdt addr $fdtcontroladdr

>     >     > +        => fdt resize <size_of_ov_dtb_file>

>     >     > +        => fdt apply <$fdtovaddr>

>     >

>     >     Having the public key on the disk means that any public key can be

>     >     placed here and we get zero security.

>     >

>     >

>     > But that does not mean the authentication will succeed unless the

>     > private key is compromised. Deleting or tampering the public key

>     on the

>     > disk can result in a denial of service attack, as the capsule

>     > authentication would fail, but that is true even when the public

>     key is

>     > embedded in u-boot -- the public key or the u-boot image can be

>     tampered

>     > with, resulting in a board brick. For countering this kind of

>     denial of

>     > service attack, the public key needs to be placed on a secure storage

>     > device, which cannot be modified or removed from the normal world.

>     > Moreover, how is this different to the placement of the signature

>     > database used for the uefi secure boot as part of the uefi

>     authenticated

>     > variables on a storage device that can be accessed from the normal

>     world.

>

>     The public key is what you use to verify that a capsule was signed by an

>     authorized party. Who controls the public keys used for capsule checking

>     can crack the device:

>

>     I just have to create a public/private key pair to sign my malware and

>     place both the public key and the malware capsule on the disk.

>

>

> But when tf-a verifies this this BL33 during boot, it would fail

> authentication and would not boot that BL33 image. So it is the same as

> denial of service, isn't it.


You cannot stop denial of service, but you can stop malware.

That is why I don't want the public key used for capsule verification on
disk.

Best regards

Heinrich

>

> -sughosh

>  

>

>

>     We should not allow public keys for capsules to be on disk.

>

>     TF-A checks BL33 (U-Boot). If the public key is part of BL33 then only

>     capsules signed with this trusted key can be installed.

>

>     An attacker can still change U-Boot in a way that TF-A will not load it

>     leading to a denial of service. But he cannot launch malware via

>     capsules.

>

>     Best regards

>

>     Heinrich

>     >

>     >

>     >     We need to build the public key into U-Boot.

>     >

>     >     Could you, please, investigate how we can adjust the build process

>     >     accordingly.

>     >

>     >     Best regards

>     >

>     >     Heinrich

>     >

>     >     > +

>     >     > +    3. Set the following environment and UEFI boot variables

>     >     > +

>     >     > +        => setenv -e -nv -bs -rt -v OsIndications =0x04

>     >     > +        => efidebug boot add 0 Boot0000 virtio 0:1

>     >     <capsule_file_name>

>     >     > +        => efidebug boot next 0

>     >     > +        => saveenv

>     >     > +

>     >     > +    4. Finally, the capsule update can be initiated with the

>     >     following

>     >     > +       command

>     >     > +

>     >     > +        => efidebug capsule disk-update

>     >     > +

>     >     > +On subsequent reboot, the platform should boot the updated

>     U-Boot

>     >     binary.

>     >     >

>     >

>
Sughosh Ganu March 2, 2021, 5:38 p.m. UTC | #6
On Tue, 2 Mar 2021 at 22:36, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> On 02.03.21 17:39, Sughosh Ganu wrote:

> >

> >

> > On Tue, 2 Mar 2021 at 21:27, Heinrich Schuchardt <xypron.glpk@gmx.de

> > <mailto:xypron.glpk@gmx.de>> wrote:

> >

> >     On 02.03.21 15:48, Sughosh Ganu wrote:

> >     > hi Heinrich,

> >     >

> >     > On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt

> >     <xypron.glpk@gmx.de <mailto:xypron.glpk@gmx.de>

> >     > <mailto:xypron.glpk@gmx.de <mailto:xypron.glpk@gmx.de>>> wrote:

> >     >

> >     >     On 30.12.20 14:57, Sughosh Ganu wrote:

> >     >     > Add documentation highlighting the steps for using the uefi

> >     capsule

> >     >     > update feature for updating the u-boot firmware image.

> >     >     >

> >     >     > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org

> >     <mailto:sughosh.ganu@linaro.org>

> >     >     <mailto:sughosh.ganu@linaro.org <mailto:

> sughosh.ganu@linaro.org>>>

> >     >     > ---

> >     >     >

> >     >     > Changes since V3: None

> >     >     >

> >     >     >  doc/board/emulation/index.rst               |   1 +

> >     >     >  doc/board/emulation/qemu_capsule_update.rst | 210

> >     >     ++++++++++++++++++++

> >     >     >  2 files changed, 211 insertions(+)

> >     >     >  create mode 100644

> doc/board/emulation/qemu_capsule_update.rst

> >     >     >

> >     >     > diff --git a/doc/board/emulation/index.rst

> >     >     b/doc/board/emulation/index.rst

> >     >     > index 1adefee155..a09ead1c35 100644

> >     >     > --- a/doc/board/emulation/index.rst

> >     >     > +++ b/doc/board/emulation/index.rst

> >     >     > @@ -10,3 +10,4 @@ Emulation

> >     >     >     qemu-mips

> >     >     >     qemu-riscv

> >     >     >     qemu-x86

> >     >     > +   qemu_capsule_update

> >     >     > diff --git a/doc/board/emulation/qemu_capsule_update.rst

> >     >     b/doc/board/emulation/qemu_capsule_update.rst

> >     >     > new file mode 100644

> >     >     > index 0000000000..9fec75f8f1

> >     >     > --- /dev/null

> >     >     > +++ b/doc/board/emulation/qemu_capsule_update.rst

> >     >     > @@ -0,0 +1,210 @@

> >     >     > +.. SPDX-License-Identifier: GPL-2.0+

> >     >     > +.. Copyright (C) 2020, Linaro Limited

> >     >     > +

> >     >     > +Enabling UEFI Capsule Update feature

> >     >     > +------------------------------------

> >     >     > +

> >     >     > +Support has been added for the UEFI capsule update feature

> >     which

> >     >     > +enables updating the U-Boot image using the UEFI firmware

> >     management

> >     >     > +protocol (fmp). The capsules are not passed to the firmware

> >     through

> >     >     > +the UpdateCapsule runtime service. Instead, capsule-on-disk

> >     >     > +functionality is used for fetching the capsule from the EFI

> >     System

> >     >     > +Partition (ESP) by placing the capsule file under the

> >     >     > +\EFI\UpdateCapsule directory.

> >     >     > +

> >     >     > +Currently, support has been added on the QEMU ARM64 virt

> >     platform for

> >     >     > +updating the U-Boot binary as a raw image when the platform

> >     is booted

> >     >     > +in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For

> this

> >     >     > +configuration, the QEMU platform needs to be booted with

> >     >     > +'secure=off'. The U-Boot binary placed on the first bank of

> >     the NOR

> >     >     > +flash at offset 0x0. The U-Boot environment is placed on

> >     the second

> >     >     > +NOR flash bank at offset 0x4000000.

> >     >     > +

> >     >     > +The capsule update feature is enabled with the following

> >     >     configuration

> >     >     > +settings::

> >     >     > +

> >     >     > +    CONFIG_MTD=y

> >     >     > +    CONFIG_FLASH_CFI_MTD=y

> >     >     > +    CONFIG_CMD_MTDPARTS=y

> >     >     > +    CONFIG_CMD_DFU=y

> >     >     > +    CONFIG_DFU_MTD=y

> >     >     > +    CONFIG_PCI_INIT_R=y

> >     >     > +    CONFIG_EFI_CAPSULE_ON_DISK=y

> >     >     > +    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y

> >     >     > +    CONFIG_EFI_CAPSULE_FIRMWARE=y

> >     >     > +    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y

> >     >     > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y

> >     >     > +

> >     >     > +In addition, the following config needs to be disabled(QEMU

> ARM

> >     >     specific)::

> >     >     > +

> >     >     > +    CONFIG_TFABOOT

> >     >     > +

> >     >     > +The capsule file can be generated by using the

> >     GenerateCapsule.py

> >     >     > +script in EDKII::

> >     >     > +

> >     >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e

> -o \

> >     >     > +    <capsule_file_name> --fw-version <val> --lsv <val>

> --guid \

> >     >     > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose

> >     >     --update-image-index \

> >     >     > +    <val> --verbose <u-boot.bin>

> >     >     > +

> >     >     > +The above is a wrapper script(GenerateCapsule) which

> >     eventually calls

> >     >     > +the actual GenerateCapsule.py script.

> >     >     > +

> >     >     > +As per the UEFI specification, the capsule file needs to be

> >     placed on

> >     >     > +the EFI System Partition, under the \EFI\UpdateCapsule

> >     directory. The

> >     >     > +EFI System Partition can be a virtio-blk-device.

> >     >     > +

> >     >     > +Before initiating the firmware update, the efi variables

> >     BootNext,

> >     >     > +BootXXXX and OsIndications need to be set. The BootXXXX

> >     variable

> >     >     needs

> >     >     > +to be pointing to the EFI System Partition which contains

> >     the capsule

> >     >     > +file. The BootNext, BootXXXX and OsIndications variables

> >     can be set

> >     >     > +using the following commands::

> >     >     > +

> >     >     > +    => efidebug boot add 0 Boot0000 virtio 0:1

> >     <capsule_file_name>

> >     >     > +    => efidebug boot next 0

> >     >     > +    => setenv -e -nv -bs -rt -v OsIndications =0x04

> >     >     > +    => saveenv

> >     >     > +

> >     >     > +Finally, the capsule update can be initiated with the

> following

> >     >     > +command::

> >     >     > +

> >     >     > +    => efidebug capsule disk-update

> >     >     > +

> >     >     > +The updated U-Boot image will be booted on subsequent boot.

> >     >     > +

> >     >     > +Enabling Capsule Authentication

> >     >     > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> >     >     > +

> >     >     > +The UEFI specification defines a way of authenticating the

> >     capsule to

> >     >     > +be updated by verifying the capsule signature. The capsule

> >     signature

> >     >     > +is computed and prepended to the capsule payload at the

> time of

> >     >     > +capsule generation. This signature is then verified by

> >     using the

> >     >     > +public key stored as part of the X509 certificate. This

> >     >     certificate is

> >     >     > +in the form of an efi signature list (esl) file, which is

> >     embedded as

> >     >     > +part of the platform's device tree blob using the

> mkeficapsule

> >     >     > +utility.

> >     >     > +

> >     >     > +On the QEMU virt platforms, the device-tree is generated on

> >     the fly

> >     >     > +based on the devices configured. This device tree is then

> >     passed

> >     >     on to

> >     >     > +the various software components booting on the platform,

> >     including

> >     >     > +U-Boot. Therefore, on the QEMU virt platform, the signatute

> is

> >     >     > +embedded on an overlay. This overlay is then applied at

> runtime

> >     >     to the

> >     >     > +base platform device-tree. Steps needed for embedding the

> >     esl file in

> >     >     > +the overlay are highlighted below.

> >     >     > +

> >     >     > +The capsule authentication feature can be enabled through

> the

> >     >     > +following config, in addition to the configs listed above

> >     for capsule

> >     >     > +update::

> >     >     > +

> >     >     > +    CONFIG_EFI_CAPSULE_AUTHENTICATE=y

> >     >     > +

> >     >     > +The public and private keys used for the signing process are

> >     >     generated

> >     >     > +and used by the steps highlighted below::

> >     >     > +

> >     >     > +    1. Install utility commands on your host

> >     >     > +       * OPENSSL

> >     >     > +       * efitools

> >     >     > +

> >     >     > +    2. Create signing keys and certificate files on your

> host

> >     >     > +

> >     >     > +        $ openssl req -x509 -sha256 -newkey rsa:2048 -subj

> >     /CN=CRT/ \

> >     >     > +            -keyout CRT.key -out CRT.crt -nodes -days 365

> >     >     > +        $ cert-to-efi-sig-list CRT.crt CRT.esl

> >     >     > +

> >     >     > +        $ openssl x509 -in CRT.crt -out CRT.cer -outform DER

> >     >     > +        $ openssl x509 -inform DER -in CRT.cer -outform PEM

> >     -out

> >     >     CRT.pub.pem

> >     >     > +

> >     >     > +        $ openssl pkcs12 -export -out CRT.pfx -inkey

> >     CRT.key -in

> >     >     CRT.crt

> >     >     > +        $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem

> >     >     > +

> >     >     > +The capsule file can be generated by using the

> >     GenerateCapsule.py

> >     >     > +script in EDKII::

> >     >     > +

> >     >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e

> -o \

> >     >     > +      <capsule_file_name> --monotonic-count <val>

> >     --fw-version \

> >     >     > +      <val> --lsv <val> --guid \

> >     >     > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \

> >     >     > +      --update-image-index <val> --signer-private-cert \

> >     >     > +      /path/to/CRT.pem --trusted-public-cert \

> >     >     > +      /path/to/CRT.pub.pem --other-public-cert

> >     /path/to/CRT.pub.pem \

> >     >     > +      <u-boot.bin>

> >     >     > +

> >     >     > +Place the capsule generated in the above step on the EFI

> System

> >     >     > +Partition under the EFI/UpdateCapsule directory

> >     >     > +

> >     >     > +For embedding the public key certificate, the following

> >     steps need to

> >     >     > +be followed::

> >     >     > +

> >     >     > +    1. Generate a skeleton overlay dts file, with a single

> >     fragment

> >     >     > +       node and an empty __overlay__ node

> >     >     > +

> >     >     > +       A typical skeleton overlay file will look like this

> >     >     > +

> >     >     > +       /dts-v1/;

> >     >     > +       /plugin/;

> >     >     > +

> >     >     > +       / {

> >     >     > +               fragment@0 {

> >     >     > +                       target-path = "/";

> >     >     > +                       __overlay__ {

> >     >     > +                       };

> >     >     > +               };

> >     >     > +       };

> >     >     > +

> >     >     > +

> >     >     > +    2. Convert the dts to a corresponding dtb with the

> >     following

> >     >

> >     >     Shouldn't this be dtbo?

> >     >

> >     >     > +       command

> >     >     > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o

> >     <ov_dtb_file_name> \

> >     >     > +        <dts_file>

> >     >     > +

> >     >     > +    3. Run the dtb file generated above through the

> >     mkeficapsule tool

> >     >     > +       in U-Boot

> >     >     > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>

> >     >     > +

> >     >     > +Running the above command results in the creation of a

> >     'signature'

> >     >     > +node in the dtb, under which the public key is stored as a

> >     >     > +'capsule-key' property. The '-O' option is to be used since

> the

> >     >     > +public key certificate(esl) file is being embedded in an

> >     overlay.

> >     >     > +

> >     >     > +The dtb file embedded with the certificate is now to be

> >     placed on an

> >     >     > +EFI System Partition. This would then be loaded and

> >     "merged" with the

> >     >     > +base platform flattened device-tree(dtb) at runtime.

> >     >     > +

> >     >     > +Build U-Boot with the following steps(QEMU ARM64)::

> >     >     > +

> >     >     > +    $ make qemu_arm64_defconfig

> >     >     > +    $ make menuconfig

> >     >     > +        Disable CONFIG_TFABOOT

> >     >     > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE

> >     >     > +        Enable all configs needed for capsule update(listed

> >     above)

> >     >     > +    $ make all

> >     >     > +

> >     >     > +Boot the platform and perform the following steps on the

> U-Boot

> >     >     > +command line::

> >     >     > +

> >     >     > +    1. Enable capsule authentication by setting the

> >     following env

> >     >     > +       variable

> >     >     > +

> >     >     > +        => setenv capsule_authentication_enabled 1

> >     >     > +        => saveenv

> >     >     > +

> >     >     > +    2. Load the overlay dtb to memory and merge it with the

> >     base fdt

> >     >     > +

> >     >     > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>

> >     >     > +        => fdt addr $fdtcontroladdr

> >     >     > +        => fdt resize <size_of_ov_dtb_file>

> >     >     > +        => fdt apply <$fdtovaddr>

> >     >

> >     >     Having the public key on the disk means that any public key

> can be

> >     >     placed here and we get zero security.

> >     >

> >     >

> >     > But that does not mean the authentication will succeed unless the

> >     > private key is compromised. Deleting or tampering the public key

> >     on the

> >     > disk can result in a denial of service attack, as the capsule

> >     > authentication would fail, but that is true even when the public

> >     key is

> >     > embedded in u-boot -- the public key or the u-boot image can be

> >     tampered

> >     > with, resulting in a board brick. For countering this kind of

> >     denial of

> >     > service attack, the public key needs to be placed on a secure

> storage

> >     > device, which cannot be modified or removed from the normal world.

> >     > Moreover, how is this different to the placement of the signature

> >     > database used for the uefi secure boot as part of the uefi

> >     authenticated

> >     > variables on a storage device that can be accessed from the normal

> >     world.

> >

> >     The public key is what you use to verify that a capsule was signed

> by an

> >     authorized party. Who controls the public keys used for capsule

> checking

> >     can crack the device:

> >

> >     I just have to create a public/private key pair to sign my malware

> and

> >     place both the public key and the malware capsule on the disk.

> >

> >

> > But when tf-a verifies this this BL33 during boot, it would fail

> > authentication and would not boot that BL33 image. So it is the same as

> > denial of service, isn't it.

>

> You cannot stop denial of service, but you can stop malware.

>

> That is why I don't want the public key used for capsule verification on

> disk.

>


If we have a trusted boot flow[1], with tf-a authenticating the
BL33(u-boot) image before booting, how do we allow malware to boot on the
system.

-sughosh

[1] -
https://trustedfirmware-a.readthedocs.io/en/latest/design/trusted-board-boot.html


>

> Best regards

>

> Heinrich

>

> >

> > -sughosh

> >

> >

> >

> >     We should not allow public keys for capsules to be on disk.

> >

> >     TF-A checks BL33 (U-Boot). If the public key is part of BL33 then

> only

> >     capsules signed with this trusted key can be installed.

> >

> >     An attacker can still change U-Boot in a way that TF-A will not load

> it

> >     leading to a denial of service. But he cannot launch malware via

> >     capsules.

> >

> >     Best regards

> >

> >     Heinrich

> >     >

> >     >

> >     >     We need to build the public key into U-Boot.

> >     >

> >     >     Could you, please, investigate how we can adjust the build

> process

> >     >     accordingly.

> >     >

> >     >     Best regards

> >     >

> >     >     Heinrich

> >     >

> >     >     > +

> >     >     > +    3. Set the following environment and UEFI boot variables

> >     >     > +

> >     >     > +        => setenv -e -nv -bs -rt -v OsIndications =0x04

> >     >     > +        => efidebug boot add 0 Boot0000 virtio 0:1

> >     >     <capsule_file_name>

> >     >     > +        => efidebug boot next 0

> >     >     > +        => saveenv

> >     >     > +

> >     >     > +    4. Finally, the capsule update can be initiated with the

> >     >     following

> >     >     > +       command

> >     >     > +

> >     >     > +        => efidebug capsule disk-update

> >     >     > +

> >     >     > +On subsequent reboot, the platform should boot the updated

> >     U-Boot

> >     >     binary.

> >     >     >

> >     >

> >

>

>
diff mbox series

Patch

diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst
index 1adefee155..a09ead1c35 100644
--- a/doc/board/emulation/index.rst
+++ b/doc/board/emulation/index.rst
@@ -10,3 +10,4 @@  Emulation
    qemu-mips
    qemu-riscv
    qemu-x86
+   qemu_capsule_update
diff --git a/doc/board/emulation/qemu_capsule_update.rst b/doc/board/emulation/qemu_capsule_update.rst
new file mode 100644
index 0000000000..9fec75f8f1
--- /dev/null
+++ b/doc/board/emulation/qemu_capsule_update.rst
@@ -0,0 +1,210 @@ 
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2020, Linaro Limited
+
+Enabling UEFI Capsule Update feature
+------------------------------------
+
+Support has been added for the UEFI capsule update feature which
+enables updating the U-Boot image using the UEFI firmware management
+protocol (fmp). The capsules are not passed to the firmware through
+the UpdateCapsule runtime service. Instead, capsule-on-disk
+functionality is used for fetching the capsule from the EFI System
+Partition (ESP) by placing the capsule file under the
+\EFI\UpdateCapsule directory.
+
+Currently, support has been added on the QEMU ARM64 virt platform for
+updating the U-Boot binary as a raw image when the platform is booted
+in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this
+configuration, the QEMU platform needs to be booted with
+'secure=off'. The U-Boot binary placed on the first bank of the NOR
+flash at offset 0x0. The U-Boot environment is placed on the second
+NOR flash bank at offset 0x4000000.
+
+The capsule update feature is enabled with the following configuration
+settings::
+
+    CONFIG_MTD=y
+    CONFIG_FLASH_CFI_MTD=y
+    CONFIG_CMD_MTDPARTS=y
+    CONFIG_CMD_DFU=y
+    CONFIG_DFU_MTD=y
+    CONFIG_PCI_INIT_R=y
+    CONFIG_EFI_CAPSULE_ON_DISK=y
+    CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y
+    CONFIG_EFI_CAPSULE_FIRMWARE=y
+    CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
+    CONFIG_EFI_CAPSULE_FMP_HEADER=y
+
+In addition, the following config needs to be disabled(QEMU ARM specific)::
+
+    CONFIG_TFABOOT
+
+The capsule file can be generated by using the GenerateCapsule.py
+script in EDKII::
+
+    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
+    <capsule_file_name> --fw-version <val> --lsv <val> --guid \
+    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose --update-image-index \
+    <val> --verbose <u-boot.bin>
+
+The above is a wrapper script(GenerateCapsule) which eventually calls
+the actual GenerateCapsule.py script.
+
+As per the UEFI specification, the capsule file needs to be placed on
+the EFI System Partition, under the \EFI\UpdateCapsule directory. The
+EFI System Partition can be a virtio-blk-device.
+
+Before initiating the firmware update, the efi variables BootNext,
+BootXXXX and OsIndications need to be set. The BootXXXX variable needs
+to be pointing to the EFI System Partition which contains the capsule
+file. The BootNext, BootXXXX and OsIndications variables can be set
+using the following commands::
+
+    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
+    => efidebug boot next 0
+    => setenv -e -nv -bs -rt -v OsIndications =0x04
+    => saveenv
+
+Finally, the capsule update can be initiated with the following
+command::
+
+    => efidebug capsule disk-update
+
+The updated U-Boot image will be booted on subsequent boot.
+
+Enabling Capsule Authentication
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The UEFI specification defines a way of authenticating the capsule to
+be updated by verifying the capsule signature. The capsule signature
+is computed and prepended to the capsule payload at the time of
+capsule generation. This signature is then verified by using the
+public key stored as part of the X509 certificate. This certificate is
+in the form of an efi signature list (esl) file, which is embedded as
+part of the platform's device tree blob using the mkeficapsule
+utility.
+
+On the QEMU virt platforms, the device-tree is generated on the fly
+based on the devices configured. This device tree is then passed on to
+the various software components booting on the platform, including
+U-Boot. Therefore, on the QEMU virt platform, the signatute is
+embedded on an overlay. This overlay is then applied at runtime to the
+base platform device-tree. Steps needed for embedding the esl file in
+the overlay are highlighted below.
+
+The capsule authentication feature can be enabled through the
+following config, in addition to the configs listed above for capsule
+update::
+
+    CONFIG_EFI_CAPSULE_AUTHENTICATE=y
+
+The public and private keys used for the signing process are generated
+and used by the steps highlighted below::
+
+    1. Install utility commands on your host
+       * OPENSSL
+       * efitools
+
+    2. Create signing keys and certificate files on your host
+
+        $ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ \
+            -keyout CRT.key -out CRT.crt -nodes -days 365
+        $ cert-to-efi-sig-list CRT.crt CRT.esl
+
+        $ openssl x509 -in CRT.crt -out CRT.cer -outform DER
+        $ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem
+
+        $ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt
+        $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem
+
+The capsule file can be generated by using the GenerateCapsule.py
+script in EDKII::
+
+    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
+      <capsule_file_name> --monotonic-count <val> --fw-version \
+      <val> --lsv <val> --guid \
+      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
+      --update-image-index <val> --signer-private-cert \
+      /path/to/CRT.pem --trusted-public-cert \
+      /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \
+      <u-boot.bin>
+
+Place the capsule generated in the above step on the EFI System
+Partition under the EFI/UpdateCapsule directory
+
+For embedding the public key certificate, the following steps need to
+be followed::
+
+    1. Generate a skeleton overlay dts file, with a single fragment
+       node and an empty __overlay__ node
+
+       A typical skeleton overlay file will look like this
+
+       /dts-v1/;
+       /plugin/;
+
+       / {
+               fragment@0 {
+                       target-path = "/";
+                       __overlay__ {
+                       };
+               };
+       };
+
+
+    2. Convert the dts to a corresponding dtb with the following
+       command
+        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \
+        <dts_file>
+
+    3. Run the dtb file generated above through the mkeficapsule tool
+       in U-Boot
+        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
+
+Running the above command results in the creation of a 'signature'
+node in the dtb, under which the public key is stored as a
+'capsule-key' property. The '-O' option is to be used since the
+public key certificate(esl) file is being embedded in an overlay.
+
+The dtb file embedded with the certificate is now to be placed on an
+EFI System Partition. This would then be loaded and "merged" with the
+base platform flattened device-tree(dtb) at runtime.
+
+Build U-Boot with the following steps(QEMU ARM64)::
+
+    $ make qemu_arm64_defconfig
+    $ make menuconfig
+        Disable CONFIG_TFABOOT
+        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
+        Enable all configs needed for capsule update(listed above)
+    $ make all
+
+Boot the platform and perform the following steps on the U-Boot
+command line::
+
+    1. Enable capsule authentication by setting the following env
+       variable
+
+        => setenv capsule_authentication_enabled 1
+        => saveenv
+
+    2. Load the overlay dtb to memory and merge it with the base fdt
+
+        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
+        => fdt addr $fdtcontroladdr
+        => fdt resize <size_of_ov_dtb_file>
+        => fdt apply <$fdtovaddr>
+
+    3. Set the following environment and UEFI boot variables
+
+        => setenv -e -nv -bs -rt -v OsIndications =0x04
+        => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
+        => efidebug boot next 0
+        => saveenv
+
+    4. Finally, the capsule update can be initiated with the following
+       command
+
+        => efidebug capsule disk-update
+
+On subsequent reboot, the platform should boot the updated U-Boot binary.