Pull request for efi-2021-10-rc1-2

* Correct device path nodes for GUID partitions
 * Embed keys to check update capsules instead of providing then in DTB
 * Increase event log buffer size for measured boot.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmD0MkYACgkQxIHbvCwF
 GsTVuRAAh3JvhR6h/8jK0HG4+ZkAPw6LlXDuoFKwh6wBWOQOgxSA3eqlW+jM9YbM
 PKeO47z9A0TIFfMUCwiwiixhzHjZI6jo39J04Mq9B+1JCe6ITdUNunvjqGvIM9Uc
 0eaxhdq8Jb3pFjIw/8HckPoXqM7grKe2SKeKYfuxL0xwCWNaAi4fKxnlBUrFiYSn
 hHZLvvhtDSMZMXeK03GJojVUl62z9AxUglmZ7qxIDWcoffPpctW46khoXFSKh8b5
 Bvm5lJ4+jWsx2czWC2HZ04NWGANDyP4XHgOVt4OhqdWR695IRLpWkBoyoQkBS+Q7
 sD7r0iaHml8nausNzwSi6//1h8sWYR13GTHGnivkp1b0/ujczENlBDvG/coyNa+T
 WngkXQkBjkvYS6+l9bCGWUs6NUhmpDguhy0tfRcqBuiJr4BsWy4RvrQE7yV2/ZLK
 1C0TPb4ZcBJjRfC5aHmau5zjjslUWMeyZRllOh/OTKKE6PAE7JQWJn/gcZS6+3us
 70pEnMN/3DO9k7eOxSsXXH9Ioe6ZtHyCK2TtvlQ2Wa1IEOvmK2hVrw6zPJbUvFxS
 ZFWNmqXcu1OT5tFIy5Axne8lktivVrKUt4NqhhTJWbOTrejWb32vgg7O9+Q0Zk/0
 1TkD989qmzSlNK3Uz2oC72h8lq37TL0gqPzJGQAGVAJFg788+jI=
 =sV/0
 -----END PGP SIGNATURE-----

Merge tag 'efi-2021-10-rc1-2' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request for efi-2021-10-rc1-2

* Correct device path nodes for GUID partitions
* Embed keys to check update capsules instead of providing then in DTB
* Increase event log buffer size for measured boot.
This commit is contained in:
Tom Rini 2021-07-18 11:03:02 -04:00
commit 6943da4ee7
11 changed files with 192 additions and 480 deletions

View file

@ -2,4 +2,3 @@
obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += qemu_mtdparts.o
obj-$(CONFIG_SET_DFU_ALT_INFO) += qemu_dfu.o
obj-$(CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT) += qemu_capsule.o

View file

@ -1,43 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2020 Linaro Limited
*/
#include <common.h>
#include <efi_api.h>
#include <efi_loader.h>
#include <env.h>
#include <fdtdec.h>
#include <asm/global_data.h>
DECLARE_GLOBAL_DATA_PTR;
int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len)
{
const void *fdt_blob = gd->fdt_blob;
const void *blob;
const char *cnode_name = "capsule-key";
const char *snode_name = "signature";
int sig_node;
int len;
sig_node = fdt_subnode_offset(fdt_blob, 0, snode_name);
if (sig_node < 0) {
EFI_PRINT("Unable to get signature node offset\n");
return -FDT_ERR_NOTFOUND;
}
blob = fdt_getprop(fdt_blob, sig_node, cnode_name, &len);
if (!blob || len < 0) {
EFI_PRINT("Unable to get capsule-key value\n");
*pkey = NULL;
*pkey_len = 0;
return -FDT_ERR_NOTFOUND;
}
*pkey = (void *)blob;
*pkey_len = len;
return 0;
}

View file

@ -1,203 +0,0 @@
.. 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 tools/mkeficapsule::
$ mkeficapsule --raw <u-boot.bin> --index 1 <capsule_file_name>
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 -b 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 -b 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.

View file

@ -277,6 +277,131 @@ Enable ``CONFIG_OPTEE``, ``CONFIG_CMD_OPTEE_RPMB`` and ``CONFIG_EFI_MM_COMM_TEE`
[1] https://optee.readthedocs.io/en/latest/building/efi_vars/stmm.html
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.
The directory \EFI\UpdateCapsule is checked for capsules only within the
EFI system partition on the device specified in the active boot option
determined by reference to BootNext variable or BootOrder variable processing.
The active Boot Variable is the variable with highest priority BootNext or
within BootOrder that refers to a device found to be present. Boot variables
in BootOrder but referring to devices not present are ignored when determining
active boot variable.
Before starting a capsule update make sure your capsules are installed in the
correct ESP partition or set BootNext.
Performing the update
*********************
Since U-boot doesn't currently support SetVariable at runtime there's a Kconfig
option (CONFIG_EFI_IGNORE_OSINDICATIONS) to disable the OsIndications variable
check. If that option is enabled just copy your capsule to \EFI\UpdateCapsule.
If that option is disabled, you'll need to set the OsIndications variable with::
=> setenv -e -nv -bs -rt -v OsIndications =0x04
Finally, the capsule update can be initiated either by rebooting the board,
which is the preferred method, or by issuing the following command::
=> efidebug capsule disk-update
**The efidebug command is should only be used during debugging/development.**
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 U-Boot.
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
CONFIG_EFI_CAPSULE_KEY_PATH=<path to .esl cert>
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
Testing on QEMU
***************
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 tools/mkeficapsule::
$ mkeficapsule --raw <u-boot.bin> --index 1 <capsule_file_name>
Executing the boot manager
~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -27,6 +27,8 @@ extern char __efi_helloworld_begin[];
extern char __efi_helloworld_end[];
extern char __efi_var_file_begin[];
extern char __efi_var_file_end[];
extern char __efi_capsule_sig_begin[];
extern char __efi_capsule_sig_end[];
/* Private data used by of-platdata devices/uclasses */
extern char __priv_data_start[], __priv_data_end[];

View file

@ -12,6 +12,7 @@ config EFI_LOADER
depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
select LIB_UUID
select PARTITION_UUIDS
select HAVE_BLOCK_DEVICE
select REGEX
imply CFB_CONSOLE_ANSI
@ -213,6 +214,13 @@ config EFI_CAPSULE_AUTHENTICATE
Select this option if you want to enable capsule
authentication
config EFI_CAPSULE_KEY_PATH
string "Path to .esl cert for capsule authentication"
depends on EFI_CAPSULE_AUTHENTICATE
help
Provide the EFI signature list (esl) certificate used for capsule
authentication
config EFI_DEVICE_PATH_TO_TEXT
bool "Device path to text protocol"
default y
@ -326,7 +334,7 @@ config EFI_TCG2_PROTOCOL
config EFI_TCG2_PROTOCOL_EVENTLOG_SIZE
int "EFI_TCG2_PROTOCOL EventLog size"
depends on EFI_TCG2_PROTOCOL
default 4096
default 65536
help
Define the size of the EventLog for EFI_TCG2_PROTOCOL. Note that
this is going to be allocated twice. One for the eventlog it self

View file

@ -20,11 +20,19 @@ always += helloworld.efi
targets += helloworld.o
endif
ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y)
EFI_CAPSULE_KEY_PATH := $(subst $\",,$(CONFIG_EFI_CAPSULE_KEY_PATH))
ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","")
$(error .esl cerificate not found. Configure your CONFIG_EFI_CAPSULE_KEY_PATH)
endif
endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o
obj-y += efi_boottime.o
obj-y += efi_helper.o
obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o
obj-$(CONFIG_EFI_CAPSULE_AUTHENTICATE) += efi_capsule_key.o
obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o
obj-y += efi_console.o
obj-y += efi_device_path.o

View file

@ -16,6 +16,7 @@
#include <mapmem.h>
#include <sort.h>
#include <asm/sections.h>
#include <crypto/pkcs7.h>
#include <crypto/pkcs7_parser.h>
#include <linux/err.h>
@ -222,12 +223,23 @@ skip:
const efi_guid_t efi_guid_capsule_root_cert_guid =
EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID;
static int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len)
{
const void *blob = __efi_capsule_sig_begin;
const int len = __efi_capsule_sig_end - __efi_capsule_sig_begin;
*pkey = (void *)blob;
*pkey_len = len;
return 0;
}
efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size,
void **image, efi_uintn_t *image_size)
{
u8 *buf;
int ret;
void *fdt_pkey, *pkey;
void *stored_pkey, *pkey;
efi_uintn_t pkey_len;
uint64_t monotonic_count;
struct efi_signature_store *truststore;
@ -286,7 +298,7 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s
goto out;
}
ret = efi_get_public_key_data(&fdt_pkey, &pkey_len);
ret = efi_get_public_key_data(&stored_pkey, &pkey_len);
if (ret < 0)
goto out;
@ -294,7 +306,7 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s
if (!pkey)
goto out;
memcpy(pkey, fdt_pkey, pkey_len);
memcpy(pkey, stored_pkey, pkey_len);
truststore = efi_build_signature_store(pkey, pkey_len);
if (!truststore)
goto out;
@ -691,11 +703,7 @@ skip:
}
found:
if (boot_dev) {
u16 *path_str;
path_str = efi_dp_str(boot_dev);
log_debug("Boot device %ls\n", path_str);
efi_free_pool(path_str);
log_debug("Boot device %pD\n", boot_dev);
volume = efi_fs_from_path(boot_dev);
if (!volume)

View file

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* .esl cert for capsule authentication
*
* Copyright (c) 2021, Ilias Apalodimas <ilias.apalodimas@linaro.org>
*/
#include <config.h>
.section .rodata.capsule_key.init,"a"
.balign 16
.global __efi_capsule_sig_begin
__efi_capsule_sig_begin:
.incbin CONFIG_EFI_CAPSULE_KEY_PATH
__efi_capsule_sig_end:
.global __efi_capsule_sig_end
.balign 16

View file

@ -5,6 +5,8 @@
* (C) Copyright 2017 Rob Clark
*/
#define LOG_CATEGORY LOGC_EFI
#include <common.h>
#include <blk.h>
#include <dm.h>
@ -16,6 +18,7 @@
#include <efi_loader.h>
#include <part.h>
#include <sandboxblockdev.h>
#include <uuid.h>
#include <asm-generic/unaligned.h>
#include <linux/compat.h> /* U16_MAX */
@ -851,8 +854,11 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
break;
case SIG_TYPE_GUID:
hddp->signature_type = 2;
memcpy(hddp->partition_signature, &desc->guid_sig,
sizeof(hddp->partition_signature));
if (uuid_str_to_bin(info.uuid,
hddp->partition_signature, 1))
log_warning(
"Partition no. %d: invalid guid: %s\n",
part, info.uuid);
break;
}

View file

@ -4,22 +4,17 @@
* Author: AKASHI Takahiro
*/
#include <errno.h>
#include <getopt.h>
#include <malloc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "fdt_host.h"
typedef __u8 u8;
typedef __u16 u16;
typedef __u32 u32;
@ -29,9 +24,6 @@ typedef __s32 s32;
#define aligned_u64 __aligned_u64
#define SIGNATURE_NODENAME "signature"
#define OVERLAY_NODENAME "__overlay__"
#ifndef __packed
#define __packed __attribute__((packed))
#endif
@ -52,9 +44,6 @@ static struct option options[] = {
{"raw", required_argument, NULL, 'r'},
{"index", required_argument, NULL, 'i'},
{"instance", required_argument, NULL, 'I'},
{"dtb", required_argument, NULL, 'D'},
{"public key", required_argument, NULL, 'K'},
{"overlay", no_argument, NULL, 'O'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0},
};
@ -68,187 +57,10 @@ static void print_usage(void)
"\t-r, --raw <raw image> new raw image file\n"
"\t-i, --index <index> update image index\n"
"\t-I, --instance <instance> update hardware instance\n"
"\t-K, --public-key <key file> public key esl file\n"
"\t-D, --dtb <dtb file> dtb file\n"
"\t-O, --overlay the dtb file is an overlay\n"
"\t-h, --help print a help message\n",
tool_name);
}
static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size,
bool overlay)
{
int parent;
int ov_node;
int frag_node;
int ret = 0;
if (overlay) {
/*
* The signature would be stored in the
* first fragment node of the overlay
*/
frag_node = fdt_first_subnode(dptr, 0);
if (frag_node == -FDT_ERR_NOTFOUND) {
fprintf(stderr,
"Couldn't find the fragment node: %s\n",
fdt_strerror(frag_node));
goto done;
}
ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME);
if (ov_node == -FDT_ERR_NOTFOUND) {
fprintf(stderr,
"Couldn't find the __overlay__ node: %s\n",
fdt_strerror(ov_node));
goto done;
}
} else {
ov_node = 0;
}
parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME);
if (parent == -FDT_ERR_NOTFOUND) {
parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME);
if (parent < 0) {
ret = parent;
if (ret != -FDT_ERR_NOSPACE) {
fprintf(stderr,
"Couldn't create signature node: %s\n",
fdt_strerror(parent));
}
}
}
if (ret)
goto done;
/* Write the key to the FDT node */
ret = fdt_setprop(dptr, parent, "capsule-key",
sptr, key_size);
done:
if (ret)
ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
return ret;
}
static int add_public_key(const char *pkey_file, const char *dtb_file,
bool overlay)
{
int ret;
int srcfd = -1;
int destfd = -1;
void *sptr = NULL;
void *dptr = NULL;
off_t src_size;
struct stat pub_key;
struct stat dtb;
/* Find out the size of the public key */
srcfd = open(pkey_file, O_RDONLY);
if (srcfd == -1) {
fprintf(stderr, "%s: Can't open %s: %s\n",
__func__, pkey_file, strerror(errno));
ret = -1;
goto err;
}
ret = fstat(srcfd, &pub_key);
if (ret == -1) {
fprintf(stderr, "%s: Can't stat %s: %s\n",
__func__, pkey_file, strerror(errno));
ret = -1;
goto err;
}
src_size = pub_key.st_size;
/* mmap the public key esl file */
sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0);
if (sptr == MAP_FAILED) {
fprintf(stderr, "%s: Failed to mmap %s:%s\n",
__func__, pkey_file, strerror(errno));
ret = -1;
goto err;
}
/* Open the dest FDT */
destfd = open(dtb_file, O_RDWR);
if (destfd == -1) {
fprintf(stderr, "%s: Can't open %s: %s\n",
__func__, dtb_file, strerror(errno));
ret = -1;
goto err;
}
ret = fstat(destfd, &dtb);
if (ret == -1) {
fprintf(stderr, "%s: Can't stat %s: %s\n",
__func__, dtb_file, strerror(errno));
goto err;
}
dtb.st_size += src_size + 0x30;
if (ftruncate(destfd, dtb.st_size)) {
fprintf(stderr, "%s: Can't expand %s: %s\n",
__func__, dtb_file, strerror(errno));
ret = -1;
goto err;
}
errno = 0;
/* mmap the dtb file */
dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
destfd, 0);
if (dptr == MAP_FAILED) {
fprintf(stderr, "%s: Failed to mmap %s:%s\n",
__func__, dtb_file, strerror(errno));
ret = -1;
goto err;
}
if (fdt_check_header(dptr)) {
fprintf(stderr, "%s: Invalid FDT header\n", __func__);
ret = -1;
goto err;
}
ret = fdt_open_into(dptr, dptr, dtb.st_size);
if (ret) {
fprintf(stderr, "%s: Cannot expand FDT: %s\n",
__func__, fdt_strerror(ret));
ret = -1;
goto err;
}
/* Copy the esl file to the expanded FDT */
ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);
if (ret < 0) {
fprintf(stderr, "%s: Unable to add public key to the FDT\n",
__func__);
ret = -1;
goto err;
}
ret = 0;
err:
if (sptr)
munmap(sptr, src_size);
if (dptr)
munmap(dptr, dtb.st_size);
if (srcfd != -1)
close(srcfd);
if (destfd != -1)
close(destfd);
return ret;
}
static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
unsigned long index, unsigned long instance)
{
@ -366,22 +178,16 @@ err_1:
int main(int argc, char **argv)
{
char *file;
char *pkey_file;
char *dtb_file;
efi_guid_t *guid;
unsigned long index, instance;
int c, idx;
int ret;
bool overlay = false;
file = NULL;
pkey_file = NULL;
dtb_file = NULL;
guid = NULL;
index = 0;
instance = 0;
for (;;) {
c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx);
c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
if (c == -1)
break;
@ -408,43 +214,22 @@ int main(int argc, char **argv)
case 'I':
instance = strtoul(optarg, NULL, 0);
break;
case 'K':
if (pkey_file) {
printf("Public Key already specified\n");
return -1;
}
pkey_file = optarg;
break;
case 'D':
if (dtb_file) {
printf("DTB file already specified\n");
return -1;
}
dtb_file = optarg;
break;
case 'O':
overlay = true;
break;
case 'h':
print_usage();
return 0;
}
}
/* need a fit image file or raw image file */
if (!file && !pkey_file && !dtb_file) {
/* need an output file */
if (argc != optind + 1) {
print_usage();
exit(EXIT_FAILURE);
}
if (pkey_file && dtb_file) {
ret = add_public_key(pkey_file, dtb_file, overlay);
if (ret == -1) {
printf("Adding public key to the dtb failed\n");
exit(EXIT_FAILURE);
} else {
exit(EXIT_SUCCESS);
}
/* need a fit image file or raw image file */
if (!file) {
print_usage();
exit(EXIT_SUCCESS);
}
if (create_fwbin(argv[optind], file, guid, index, instance)