From 118a0ecd6d8b3bab401a780fefad2b02ad28d6af Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 9 Feb 2022 19:10:36 +0900 Subject: tools: mkeficapsule: add man page Add a man page for mkeficapsule command. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass Acked-by: Ilias Apalodimas --- doc/mkeficapsule.1 | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 doc/mkeficapsule.1 (limited to 'doc') diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 new file mode 100644 index 0000000000..680362f5c4 --- /dev/null +++ b/doc/mkeficapsule.1 @@ -0,0 +1,99 @@ +.\" SPDX-License-Identifier: GPL-2.0+ +.\" Copyright (c) 2021, Linaro Limited +.\" written by AKASHI Takahiro +.TH MAEFICAPSULE 1 "May 2021" + +.SH NAME +mkeficapsule \- Generate EFI capsule file for U-Boot + +.SH SYNOPSIS +.B mkeficapsule +.RI [ options "] " capsule-file + +.SH "DESCRIPTION" +.B mkeficapsule +command is used to create an EFI capsule file for use with the U-Boot +EFI capsule update. +A capsule file may contain various type of firmware blobs which +are to be applied to the system and must be placed in the specific +directory on the UEFI system partition. +An update will be automatically executed at next reboot. + +Optionally, a capsule file can be signed with a given private key. +In this case, the update will be authenticated by verifying the signature +before applying. + +.B mkeficapsule +supports two different format of image files: +.TP +.I raw image +format is a single binary blob of any type of firmware. + +.TP +.I FIT (Flattened Image Tree) image +format is the same as used in the new uImage format and allows for +multiple binary blobs in a single capsule file. +This type of image file can be generated by +.BR mkimage . + +.SH "OPTIONS" +One of +.BR --fit " or " --raw +option must be specified. + +.TP +.BI "-f\fR,\fB --fit " fit-image-file +Specify a FIT image file + +.TP +.BI "-r\fR,\fB --raw " raw-image-file +Specify a raw image file + +.TP +.BI "-i\fR,\fB --index " index +Specify an image index + +.TP +.BI "-I\fR,\fB --instance " instance +Specify a hardware instance + +.TP +.BR -h ", " --help +Print a help message + +.PP +With signing, +.BR --private-key ", " --certificate " and " --monotonic-count +are all mandatory. + +.TP +.BI "-p\fR,\fB --private-key " private-key-file +Specify signer's private key file in PEM + +.TP +.BI "-c\fR,\fB --certificate " certificate-file +Specify signer's certificate file in EFI certificate list format + +.TP +.BI "-m\fR,\fB --monotonic-count " count +Specify a monotonic count which is set to be monotonically incremented +at every firmware update. + +.TP +.B "-d\fR,\fB --dump_sig" +Dump signature data into *.p7 file + +.PP +.SH FILES +.TP +.I /EFI/UpdateCapsule +The directory in which all capsule files be placed + +.SH SEE ALSO +.BR mkimage (1) + +.SH AUTHORS +Written by AKASHI Takahiro + +.SH HOMEPAGE +http://www.denx.de/wiki/U-Boot/WebHome -- cgit v1.2.3 From a62eb06f7c2b80e80a1f14f8950c3fb6958a97d4 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 9 Feb 2022 19:10:37 +0900 Subject: doc: update UEFI document for usage of mkeficapsule Now we can use mkeficapsule command instead of EDK-II's script to create a signed capsule file. So update the instruction for capsule authentication. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass Acked-by: Ilias Apalodimas --- doc/develop/uefi/uefi.rst | 151 +++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 75 deletions(-) (limited to 'doc') diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index 43fb10f797..52a38c6b23 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -284,37 +284,56 @@ 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. +functionality is used for fetching capsules from the EFI System +Partition (ESP) by placing capsule files under the directory:: + + \EFI\UpdateCapsule + +The directory is checked for capsules only within the +EFI system partition on the device specified in the active boot option, +which is determined by BootXXXX variable in BootNext, or if not, the highest +priority one within BootOrder. Any BootXXXX variables referring to devices +not present are ignored when determining the active boot option. + +Please note that capsules will be applied in the alphabetic order of +capsule file names. + +Creating a capsule file +*********************** + +A capsule file can be created by using tools/mkeficapsule. +To build this tool, enable:: + + CONFIG_TOOLS_MKEFICAPSULE=y + CONFIG_TOOLS_LIBCRYPTO=y + +Run the following command + +.. code-block:: console + + $ mkeficapsule \ + --index 1 --instance 0 \ + [--fit | --raw ] \ + 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. +Put capsule files under the directory mentioned above. +Then, following the UEFI specification, you'll need to set +the EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED +bit in OsIndications variable with -If that option is disabled, you'll need to set the OsIndications variable with:: +.. code-block:: console => 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 +Since U-boot doesn't currently support SetVariable at runtime, its value +won't be taken over across the reboot. If this is the case, you can skip +this feature check with the Kconfig option (CONFIG_EFI_IGNORE_OSINDICATIONS) +set. -**The efidebug command is should only be used during debugging/development.** +Finally, the capsule update can be initiated by rebooting the board. Enabling Capsule Authentication ******************************* @@ -324,82 +343,64 @@ 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. +in the form of an efi signature list (esl) file, which is embedded in +a device tree. 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= The public and private keys used for the signing process are generated -and used by the steps highlighted below:: +and used by the steps highlighted below. - 1. Install utility commands on your host - * OPENSSL +1. Install utility commands on your host + * openssl * efitools - 2. Create signing keys and certificate files on your host +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 +.. code-block:: console - $ openssl x509 -in CRT.crt -out CRT.cer -outform DER - $ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem + $ 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 pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt - $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem +3. Run the following command to create and sign the capsule file -The capsule file can be generated by using the GenerateCapsule.py -script in EDKII:: +.. code-block:: console - $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \ - --monotonic-count --fw-version \ - --lsv --guid \ - e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \ - --update-image-index --signer-private-cert \ - /path/to/CRT.pem --trusted-public-cert \ - /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \ - + $ mkeficapsule --monotonic-count 1 \ + --private-key CRT.key \ + --certificate CRT.crt \ + --index 1 --instance 0 \ + [--fit | --raw ] \ + -Place the capsule generated in the above step on the EFI System -Partition under the EFI/UpdateCapsule directory +4. Insert the signature list into a device tree in the following format:: -Testing on QEMU -*************** + { + signature { + capsule-key = [ ]; + } + ... + } -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. +You can do step-4 manually with -The capsule update feature is enabled with the following configuration -settings:: +.. code-block:: console - 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 + $ dtc -@ -I dts -O dtb -o signature.dtbo signature.dts + $ fdtoverlay -i orig.dtb -o new.dtb -v signature.dtbo -In addition, the following config needs to be disabled(QEMU ARM specific):: +where signature.dts looks like:: - CONFIG_TFABOOT - -The capsule file can be generated by using the tools/mkeficapsule:: - - $ mkeficapsule --raw --index 1 + &{/} { + signature { + capsule-key = /incbin/("CRT.esl"); + }; + }; Executing the boot manager ~~~~~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From d9612f4426b490a5df420083b5aaf812607d4197 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 9 Feb 2022 19:10:39 +0900 Subject: tools: mkeficapsule: allow for specifying GUID explicitly The existing options, "--fit" and "--raw," are only used to put a proper GUID in a capsule header, where GUID identifies a particular FMP (Firmware Management Protocol) driver which then would handle the firmware binary in a capsule. In fact, mkeficapsule does the exact same job in creating a capsule file whatever the firmware binary type is. To prepare for the future extension, the command syntax will be a bit modified to allow users to specify arbitrary GUID for their own FMP driver. OLD: [--fit | --raw ] NEW: [--fit | --raw | --guid ] Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- .azure-pipelines.yml | 4 +-- doc/develop/uefi/uefi.rst | 4 +-- doc/mkeficapsule.1 | 26 +++++++++++---- tools/Makefile | 2 +- tools/mkeficapsule.c | 85 ++++++++++++++++++++++++++++++++++------------- 5 files changed, 86 insertions(+), 35 deletions(-) (limited to 'doc') diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 2c421da133..db452916d0 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -26,7 +26,7 @@ stages: %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Su" displayName: 'Update MSYS2' - script: | - %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm --needed -Sy make gcc bison flex diffutils openssl-devel libgnutls-devel" + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm --needed -Sy make gcc bison flex diffutils openssl-devel libgnutls-devel libutil-linux-devel" displayName: 'Install Toolchain' - script: | echo make tools-only_defconfig tools-only NO_SDL=1 > build-tools.sh @@ -43,7 +43,7 @@ stages: pool: vmImage: $(macos_vm) steps: - - script: brew install make + - script: brew install make ossp-uuid displayName: Brew install dependencies - script: | gmake tools-only_config tools-only NO_SDL=1 \ diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index 52a38c6b23..b7bf135627 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -375,8 +375,8 @@ and used by the steps highlighted below. --private-key CRT.key \ --certificate CRT.crt \ --index 1 --instance 0 \ - [--fit | --raw ] \ - + [--fit | --raw | --guid 4. Insert the signature list into a device tree in the following format:: diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 680362f5c4..8babb27ee8 100644 --- a/doc/mkeficapsule.1 +++ b/doc/mkeficapsule.1 @@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot .SH SYNOPSIS .B mkeficapsule -.RI [ options "] " capsule-file +.RI [ options "] " image-blob " " capsule-file .SH "DESCRIPTION" .B mkeficapsule @@ -24,7 +24,7 @@ In this case, the update will be authenticated by verifying the signature before applying. .B mkeficapsule -supports two different format of image files: +takes any type of image files, including: .TP .I raw image format is a single binary blob of any type of firmware. @@ -36,18 +36,30 @@ multiple binary blobs in a single capsule file. This type of image file can be generated by .BR mkimage . +.PP +If you want to use other types than above two, you should explicitly +specify a guid for the FMP driver. + .SH "OPTIONS" One of -.BR --fit " or " --raw +.BR --fit ", " --raw " or " --guid option must be specified. .TP -.BI "-f\fR,\fB --fit " fit-image-file -Specify a FIT image file +.BR -f ", " --fit +Indicate that the blob is a FIT image file .TP -.BI "-r\fR,\fB --raw " raw-image-file -Specify a raw image file +.BR -r ", " --raw +Indicate that the blob is a raw image file + +.TP +.BI "-g\fR,\fB --guid " guid-string +Specify guid for image blob type. The format is: + xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + +The first three elements are in little endian, while the rest +is in big endian. .TP .BI "-i\fR,\fB --index " index diff --git a/tools/Makefile b/tools/Makefile index 8da07d60a7..5409ff2879 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -238,7 +238,7 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include -HOSTLDLIBS_mkeficapsule += -lgnutls +HOSTLDLIBS_mkeficapsule += -lgnutls -luuid hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule # We build some files with extra pedantic flags to try to minimize things diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4b7fe15c6e..f7590e482f 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -15,7 +15,7 @@ #include #include - +#include #include #include @@ -33,11 +33,12 @@ efi_guid_t efi_guid_image_type_uboot_raw = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; -static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +static const char *opts_short = "frg:i:I:v:p:c:m:dh"; static struct option options[] = { - {"fit", required_argument, NULL, 'f'}, - {"raw", required_argument, NULL, 'r'}, + {"fit", no_argument, NULL, 'f'}, + {"raw", no_argument, NULL, 'r'}, + {"guid", required_argument, NULL, 'g'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, {"private-key", required_argument, NULL, 'p'}, @@ -50,11 +51,12 @@ static struct option options[] = { static void print_usage(void) { - printf("Usage: %s [options] \n" + fprintf(stderr, "Usage: %s [options] \n" "Options:\n" - "\t-f, --fit new FIT image file\n" - "\t-r, --raw new raw image file\n" + "\t-f, --fit FIT image type\n" + "\t-r, --raw raw image type\n" + "\t-g, --guid guid for image blob type\n" "\t-i, --index update image index\n" "\t-I, --instance update hardware instance\n" "\t-p, --private-key private key file\n" @@ -541,6 +543,37 @@ err: return ret; } +/** + * convert_uuid_to_guid() - convert UUID to GUID + * @buf: UUID binary + * + * UUID and GUID have the same data structure, but their binary + * formats are different due to the endianness. See lib/uuid.c. + * Since uuid_parse() can handle only UUID, this function must + * be called to get correct data for GUID when parsing a string. + * + * The correct data will be returned in @buf. + */ +void convert_uuid_to_guid(unsigned char *buf) +{ + unsigned char c; + + c = buf[0]; + buf[0] = buf[3]; + buf[3] = c; + c = buf[1]; + buf[1] = buf[2]; + buf[2] = c; + + c = buf[4]; + buf[4] = buf[5]; + buf[5] = c; + + c = buf[6]; + buf[6] = buf[7]; + buf[7] = c; +} + /** * main - main entry function of mkeficapsule * @argc: Number of arguments @@ -555,14 +588,13 @@ err: */ int main(int argc, char **argv) { - char *file; efi_guid_t *guid; + unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount; char *privkey_file, *cert_file; int c, idx; - file = NULL; guid = NULL; index = 0; instance = 0; @@ -577,21 +609,34 @@ int main(int argc, char **argv) switch (c) { case 'f': - if (file) { - fprintf(stderr, "Image already specified\n"); + if (guid) { + fprintf(stderr, + "Image type already specified\n"); exit(EXIT_FAILURE); } - file = optarg; guid = &efi_guid_image_type_uboot_fit; break; case 'r': - if (file) { - fprintf(stderr, "Image already specified\n"); + if (guid) { + fprintf(stderr, + "Image type already specified\n"); exit(EXIT_FAILURE); } - file = optarg; guid = &efi_guid_image_type_uboot_raw; break; + case 'g': + if (guid) { + fprintf(stderr, + "Image type already specified\n"); + exit(EXIT_FAILURE); + } + if (uuid_parse(optarg, uuid_buf)) { + fprintf(stderr, "Wrong guid format\n"); + exit(EXIT_FAILURE); + } + convert_uuid_to_guid(uuid_buf); + guid = (efi_guid_t *)uuid_buf; + break; case 'i': index = strtoul(optarg, NULL, 0); break; @@ -627,20 +672,14 @@ int main(int argc, char **argv) } /* check necessary parameters */ - if ((argc != optind + 1) || !file || + if ((argc != optind + 2) || !guid || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) { print_usage(); exit(EXIT_FAILURE); } - /* 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, + if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance, mcount, privkey_file, cert_file) < 0) { fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE); -- cgit v1.2.3