openbmc.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] u-boot: Support for SPL verified boot
@ 2021-03-26 20:14 Klaus Heinrich Kiwi
  2021-03-26 20:14 ` [PATCH v2 1/4] u-boot: Move definitions to common locations Klaus Heinrich Kiwi
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Klaus Heinrich Kiwi @ 2021-03-26 20:14 UTC (permalink / raw)
  To: openembedded-core; +Cc: andrew, klaus, openbmc

This patch series aims at extending U-Boot's verified boot support to
also include SPL.

Presently, setting UBOOT_SIGN_ENABLE instructs the classes uboot-sign
and kernel-fitimage to create and sign a Linux Kernel fitImage. This
proposal introduces the variables UBOOT_FITIMAGE_ENABLE and
SPL_SIGN_ENABLE that will, respectively, create and sign a U-Boot
(proper) fitImage that the SPL can load (and verify if enabled)

In order to accomplish this, the first patch moves some of necessary
infrastructure (variables, functions) used to sign the Kernel
fitImage to more common locations, and then essentially duplicates the
method currently used to sign the Kernel fitImage to also sign the
U-Boot fitImage.

If the variable UBOOT_FITIMAGE_ENABLE = "1", the uboot-sign class will
copy the SPL files (nodtb image and dtb file) from the u-boot recipe to
the staging area, so that the Kernel recipe can then create the U-Boot
fitImage.

In case SPL_SIGN_ENABLE = "1", the U-Boot fitImage will be signed using
the key provided by SPL_SIGN_KEYNAME / SPL_SIGN_KEYDIR, or will
auto-generate keys based on UBOOT_FIT_HASH_ALG, UBOOT_FIT_SIGN_ALG and
UBOOT_FIT_SIGN_NUMBITS if UBOOT_FIT_GENERATE_KEYS is "1".

After the operations above, the Kernel recipe will deploy the (signed)
U-Boot fitImage, the ITS script used to create it, as well as the SPL
concatenated with the DTB containing the pubkey to the images directory.

The reason why the U-Boot fitImage is created by the Kernel is in order
to make sure that, when UBOOT_SIGN_ENABLE is set (and the Kernel
fitImage is signed), the U-Boot fitImage being created/signed contains
the pubkey used by the Kernel recipe to sign the Kernel fitImage.

I added oe-selftest testcases and also tested this on upstream OpenBMC
with AST2600 BMC devices.

Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>

---
Changes since V1:

 * Separated SPL_SIGN_ENABLE from UBOOT_FITIMAGE_ENABLE so that an
   U-Boot fitImage can be created without a signature

 * Completely moved the task of creating/signing the U-Boot fitImage to
   the Kernel recipe, so that we don't get collisions when reusing the
   build tree while changing the configuration. This is apparently also
   necessary for testcases to be sane.

 * Testcases changes and additions, covering the above scenarios

 meta/classes/kernel-fitimage.bbclass     |  82 ++---
 meta/classes/uboot-config.bbclass        |  58 ++++
 meta/classes/uboot-sign.bbclass          | 407 +++++++++++++++++++++++--
 meta/lib/oeqa/selftest/cases/fitimage.py | 468 +++++++++++++++++++++++++++++
 meta/recipes-bsp/u-boot/u-boot.inc       |  46 ---
 5 files changed, 928 insertions(+), 133 deletions(-)


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/4] u-boot: Move definitions to common locations
  2021-03-26 20:14 [PATCH v2 0/4] u-boot: Support for SPL verified boot Klaus Heinrich Kiwi
@ 2021-03-26 20:14 ` Klaus Heinrich Kiwi
  2021-03-26 20:14 ` [PATCH v2 2/4] u-boot: Add infrastructure to SPL verified boot Klaus Heinrich Kiwi
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Klaus Heinrich Kiwi @ 2021-03-26 20:14 UTC (permalink / raw)
  To: openembedded-core; +Cc: andrew, klaus, openbmc

Move some definitions from u-boot.inc into uboot-config.bbclass and
similarly from kernel-fitimage.bbclass into uboot-sign.bbclass, so that
they can be useful when signing the U-boot proper fitimage, for a
verified-boot SPL.

Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
---
 meta/classes/kernel-fitimage.bbclass | 58 ----------------------------
 meta/classes/uboot-config.bbclass    | 56 +++++++++++++++++++++++++++
 meta/classes/uboot-sign.bbclass      | 35 +++++++++++++++++
 meta/recipes-bsp/u-boot/u-boot.inc   | 46 ----------------------
 4 files changed, 91 insertions(+), 104 deletions(-)

diff --git a/meta/classes/kernel-fitimage.bbclass b/meta/classes/kernel-fitimage.bbclass
index b9d8270027..6b7c1c3a7d 100644
--- a/meta/classes/kernel-fitimage.bbclass
+++ b/meta/classes/kernel-fitimage.bbclass
@@ -53,30 +53,6 @@ python __anonymous () {
                 d.appendVarFlag('do_assemble_fitimage_initramfs', 'depends', ' %s:do_populate_sysroot' % uboot_pn)
 }
 
-# Options for the device tree compiler passed to mkimage '-D' feature:
-UBOOT_MKIMAGE_DTCOPTS ??= ""
-
-# fitImage Hash Algo
-FIT_HASH_ALG ?= "sha256"
-
-# fitImage Signature Algo
-FIT_SIGN_ALG ?= "rsa2048"
-
-# Generate keys for signing fitImage
-FIT_GENERATE_KEYS ?= "0"
-
-# Size of private key in number of bits
-FIT_SIGN_NUMBITS ?= "2048"
-
-# args to openssl genrsa (Default is just the public exponent)
-FIT_KEY_GENRSA_ARGS ?= "-F4"
-
-# args to openssl req (Default is -batch for non interactive mode and
-# -new for new certificate)
-FIT_KEY_REQ_ARGS ?= "-batch -new"
-
-# Standard format for public key certificate
-FIT_KEY_SIGN_PKCS ?= "-x509"
 
 # Description string
 FIT_DESC ?= "U-Boot fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}"
@@ -84,13 +60,6 @@ FIT_DESC ?= "U-Boot fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}"
 # Sign individual images as well
 FIT_SIGN_INDIVIDUAL ?= "0"
 
-# mkimage command
-UBOOT_MKIMAGE ?= "uboot-mkimage"
-UBOOT_MKIMAGE_SIGN ?= "${UBOOT_MKIMAGE}"
-
-# Arguments passed to mkimage for signing
-UBOOT_MKIMAGE_SIGN_ARGS ?= ""
-
 #
 # Emit the fitImage ITS header
 #
@@ -698,33 +667,6 @@ do_assemble_fitimage_initramfs() {
 
 addtask assemble_fitimage_initramfs before do_deploy after do_bundle_initramfs
 
-do_generate_rsa_keys() {
-	if [ "${UBOOT_SIGN_ENABLE}" = "0" ] && [ "${FIT_GENERATE_KEYS}" = "1" ]; then
-		bbwarn "FIT_GENERATE_KEYS is set to 1 eventhough UBOOT_SIGN_ENABLE is set to 0. The keys will not be generated as they won't be used."
-	fi
-
-	if [ "${UBOOT_SIGN_ENABLE}" = "1" ] && [ "${FIT_GENERATE_KEYS}" = "1" ]; then
-
-		# Generate keys only if they don't already exist
-		if [ ! -f "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".key ] || \
-			[ ! -f "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".crt]; then
-
-			# make directory if it does not already exist
-			mkdir -p "${UBOOT_SIGN_KEYDIR}"
-
-			echo "Generating RSA private key for signing fitImage"
-			openssl genrsa ${FIT_KEY_GENRSA_ARGS} -out \
-				"${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".key \
-				"${FIT_SIGN_NUMBITS}"
-
-			echo "Generating certificate for signing fitImage"
-			openssl req ${FIT_KEY_REQ_ARGS} "${FIT_KEY_SIGN_PKCS}" \
-				-key "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".key \
-				-out "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".crt
-		fi
-	fi
-}
-
 addtask generate_rsa_keys before do_assemble_fitimage after do_compile
 
 kernel_do_deploy[vardepsexclude] = "DATETIME"
diff --git a/meta/classes/uboot-config.bbclass b/meta/classes/uboot-config.bbclass
index 89ff970fcc..31487c1418 100644
--- a/meta/classes/uboot-config.bbclass
+++ b/meta/classes/uboot-config.bbclass
@@ -11,7 +11,63 @@
 #
 # Copyright 2013, 2014 (C) O.S. Systems Software LTDA.
 
+# Some versions of u-boot use .bin and others use .img.  By default use .bin
+# but enable individual recipes to change this value.
+UBOOT_SUFFIX ??= "bin"
 UBOOT_BINARY ?= "u-boot.${UBOOT_SUFFIX}"
+UBOOT_BINARYNAME ?= "${@os.path.splitext(d.getVar("UBOOT_BINARY"))[0]}"
+UBOOT_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.${UBOOT_SUFFIX}"
+UBOOT_SYMLINK ?= "u-boot-${MACHINE}.${UBOOT_SUFFIX}"
+UBOOT_MAKE_TARGET ?= "all"
+
+# Output the ELF generated. Some platforms can use the ELF file and directly
+# load it (JTAG booting, QEMU) additionally the ELF can be used for debugging
+# purposes.
+UBOOT_ELF ?= ""
+UBOOT_ELF_SUFFIX ?= "elf"
+UBOOT_ELF_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.${UBOOT_ELF_SUFFIX}"
+UBOOT_ELF_BINARY ?= "u-boot.${UBOOT_ELF_SUFFIX}"
+UBOOT_ELF_SYMLINK ?= "u-boot-${MACHINE}.${UBOOT_ELF_SUFFIX}"
+
+# Some versions of u-boot build an SPL (Second Program Loader) image that
+# should be packaged along with the u-boot binary as well as placed in the
+# deploy directory.  For those versions they can set the following variables
+# to allow packaging the SPL.
+SPL_BINARY ?= ""
+SPL_BINARYNAME ?= "${@os.path.basename(d.getVar("SPL_BINARY"))}"
+SPL_IMAGE ?= "${SPL_BINARYNAME}-${MACHINE}-${PV}-${PR}"
+SPL_SYMLINK ?= "${SPL_BINARYNAME}-${MACHINE}"
+
+# Additional environment variables or a script can be installed alongside
+# u-boot to be used automatically on boot.  This file, typically 'uEnv.txt'
+# or 'boot.scr', should be packaged along with u-boot as well as placed in the
+# deploy directory.  Machine configurations needing one of these files should
+# include it in the SRC_URI and set the UBOOT_ENV parameter.
+UBOOT_ENV_SUFFIX ?= "txt"
+UBOOT_ENV ?= ""
+UBOOT_ENV_BINARY ?= "${UBOOT_ENV}.${UBOOT_ENV_SUFFIX}"
+UBOOT_ENV_IMAGE ?= "${UBOOT_ENV}-${MACHINE}-${PV}-${PR}.${UBOOT_ENV_SUFFIX}"
+UBOOT_ENV_SYMLINK ?= "${UBOOT_ENV}-${MACHINE}.${UBOOT_ENV_SUFFIX}"
+
+# Default name of u-boot initial env, but enable individual recipes to change
+# this value.
+UBOOT_INITIAL_ENV ?= "${PN}-initial-env"
+
+# U-Boot EXTLINUX variables. U-Boot searches for /boot/extlinux/extlinux.conf
+# to find EXTLINUX conf file.
+UBOOT_EXTLINUX_INSTALL_DIR ?= "/boot/extlinux"
+UBOOT_EXTLINUX_CONF_NAME ?= "extlinux.conf"
+UBOOT_EXTLINUX_SYMLINK ?= "${UBOOT_EXTLINUX_CONF_NAME}-${MACHINE}-${PR}"
+
+# Options for the device tree compiler passed to mkimage '-D' feature:
+UBOOT_MKIMAGE_DTCOPTS ??= ""
+
+# mkimage command
+UBOOT_MKIMAGE ?= "uboot-mkimage"
+UBOOT_MKIMAGE_SIGN ?= "${UBOOT_MKIMAGE}"
+
+# Arguments passed to mkimage for signing
+UBOOT_MKIMAGE_SIGN_ARGS ?= ""
 
 python () {
     ubootmachine = d.getVar("UBOOT_MACHINE")
diff --git a/meta/classes/uboot-sign.bbclass b/meta/classes/uboot-sign.bbclass
index 713196df41..d57bef6669 100644
--- a/meta/classes/uboot-sign.bbclass
+++ b/meta/classes/uboot-sign.bbclass
@@ -31,6 +31,9 @@
 #
 # For more details on signature process, please refer to U-Boot documentation.
 
+# We need some variables from u-boot-config
+inherit uboot-config
+
 # Signature activation.
 UBOOT_SIGN_ENABLE ?= "0"
 
@@ -41,6 +44,38 @@ UBOOT_DTB_SYMLINK ?= "u-boot-${MACHINE}.dtb"
 UBOOT_NODTB_IMAGE ?= "u-boot-nodtb-${MACHINE}-${PV}-${PR}.${UBOOT_SUFFIX}"
 UBOOT_NODTB_BINARY ?= "u-boot-nodtb.${UBOOT_SUFFIX}"
 UBOOT_NODTB_SYMLINK ?= "u-boot-nodtb-${MACHINE}.${UBOOT_SUFFIX}"
+UBOOT_ITS_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.its"
+UBOOT_ITS ?= "u-boot.its"
+UBOOT_ITS_SYMLINK ?= "u-boot-${MACHINE}.its"
+SPL_DIR ?= "${@os.path.dirname(d.getVar("SPL_BINARY")) or '.'}"
+SPL_DTB_IMAGE ?= "u-boot-spl-${MACHINE}-${PV}-${PR}.dtb"
+SPL_DTB_BINARY ?= "u-boot-spl.dtb"
+SPL_DTB_SYMLINK ?= "u-boot-spl-${MACHINE}.dtb"
+SPL_NODTB_IMAGE ?= "${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[0]}-nodtb-${MACHINE}-${PV}-${PR}${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[1]}"
+SPL_NODTB_BINARY ?= "${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[0]}-nodtb${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[1]}"
+SPL_NODTB_SYMLINK ?= "${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[0]}-nodtb-${MACHINE}${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[1]}"
+
+# fitImage Hash Algo
+FIT_HASH_ALG ?= "sha256"
+
+# fitImage Signature Algo
+FIT_SIGN_ALG ?= "rsa2048"
+
+# Generate keys for signing fitImage
+FIT_GENERATE_KEYS ?= "0"
+
+# Size of private key in number of bits
+FIT_SIGN_NUMBITS ?= "2048"
+
+# args to openssl genrsa (Default is just the public exponent)
+FIT_KEY_GENRSA_ARGS ?= "-F4"
+
+# args to openssl req (Default is -batch for non interactive mode and
+# -new for new certificate)
+FIT_KEY_REQ_ARGS ?= "-batch -new"
+
+# Standard format for public key certificate
+FIT_KEY_SIGN_PKCS ?= "-x509"
 
 # Functions in this bbclass is for u-boot only
 UBOOT_PN = "${@d.getVar('PREFERRED_PROVIDER_u-boot') or 'u-boot'}"
diff --git a/meta/recipes-bsp/u-boot/u-boot.inc b/meta/recipes-bsp/u-boot/u-boot.inc
index 251178db33..5398c2e621 100644
--- a/meta/recipes-bsp/u-boot/u-boot.inc
+++ b/meta/recipes-bsp/u-boot/u-boot.inc
@@ -24,52 +24,6 @@ PACKAGECONFIG[openssl] = ",,openssl-native"
 # file already exists it will not be overwritten.
 UBOOT_LOCALVERSION ?= ""
 
-# Some versions of u-boot use .bin and others use .img.  By default use .bin
-# but enable individual recipes to change this value.
-UBOOT_SUFFIX ??= "bin"
-UBOOT_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.${UBOOT_SUFFIX}"
-UBOOT_SYMLINK ?= "u-boot-${MACHINE}.${UBOOT_SUFFIX}"
-UBOOT_MAKE_TARGET ?= "all"
-
-# Output the ELF generated. Some platforms can use the ELF file and directly
-# load it (JTAG booting, QEMU) additionally the ELF can be used for debugging
-# purposes.
-UBOOT_ELF ?= ""
-UBOOT_ELF_SUFFIX ?= "elf"
-UBOOT_ELF_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.${UBOOT_ELF_SUFFIX}"
-UBOOT_ELF_BINARY ?= "u-boot.${UBOOT_ELF_SUFFIX}"
-UBOOT_ELF_SYMLINK ?= "u-boot-${MACHINE}.${UBOOT_ELF_SUFFIX}"
-
-# Some versions of u-boot build an SPL (Second Program Loader) image that
-# should be packaged along with the u-boot binary as well as placed in the
-# deploy directory.  For those versions they can set the following variables
-# to allow packaging the SPL.
-SPL_BINARY ?= ""
-SPL_BINARYNAME ?= "${@os.path.basename(d.getVar("SPL_BINARY"))}"
-SPL_IMAGE ?= "${SPL_BINARYNAME}-${MACHINE}-${PV}-${PR}"
-SPL_SYMLINK ?= "${SPL_BINARYNAME}-${MACHINE}"
-
-# Additional environment variables or a script can be installed alongside
-# u-boot to be used automatically on boot.  This file, typically 'uEnv.txt'
-# or 'boot.scr', should be packaged along with u-boot as well as placed in the
-# deploy directory.  Machine configurations needing one of these files should
-# include it in the SRC_URI and set the UBOOT_ENV parameter.
-UBOOT_ENV_SUFFIX ?= "txt"
-UBOOT_ENV ?= ""
-UBOOT_ENV_BINARY ?= "${UBOOT_ENV}.${UBOOT_ENV_SUFFIX}"
-UBOOT_ENV_IMAGE ?= "${UBOOT_ENV}-${MACHINE}-${PV}-${PR}.${UBOOT_ENV_SUFFIX}"
-UBOOT_ENV_SYMLINK ?= "${UBOOT_ENV}-${MACHINE}.${UBOOT_ENV_SUFFIX}"
-
-# Default name of u-boot initial env, but enable individual recipes to change
-# this value.
-UBOOT_INITIAL_ENV ?= "${PN}-initial-env"
-
-# U-Boot EXTLINUX variables. U-Boot searches for /boot/extlinux/extlinux.conf
-# to find EXTLINUX conf file.
-UBOOT_EXTLINUX_INSTALL_DIR ?= "/boot/extlinux"
-UBOOT_EXTLINUX_CONF_NAME ?= "extlinux.conf"
-UBOOT_EXTLINUX_SYMLINK ?= "${UBOOT_EXTLINUX_CONF_NAME}-${MACHINE}-${PR}"
-
 do_configure () {
     if [ -n "${UBOOT_CONFIG}" ]; then
         unset i j
-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 2/4] u-boot: Add infrastructure to SPL verified boot
  2021-03-26 20:14 [PATCH v2 0/4] u-boot: Support for SPL verified boot Klaus Heinrich Kiwi
  2021-03-26 20:14 ` [PATCH v2 1/4] u-boot: Move definitions to common locations Klaus Heinrich Kiwi
@ 2021-03-26 20:14 ` Klaus Heinrich Kiwi
  2021-03-26 20:14 ` [PATCH v2 3/4] u-boot: Use a different Key for SPL signing Klaus Heinrich Kiwi
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Klaus Heinrich Kiwi @ 2021-03-26 20:14 UTC (permalink / raw)
  To: openembedded-core; +Cc: andrew, klaus, openbmc

Add the necessary infrastructure to create a U-boot proper fitimage,
sign it (using the same keys as the kernel-fitimage), and put the public
key in the SPL binary so that verified SPL boot can be accomplished.

Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
---
 meta/classes/kernel-fitimage.bbclass |  24 +-
 meta/classes/uboot-sign.bbclass      | 351 ++++++++++++++++++++++++---
 2 files changed, 340 insertions(+), 35 deletions(-)

diff --git a/meta/classes/kernel-fitimage.bbclass b/meta/classes/kernel-fitimage.bbclass
index 6b7c1c3a7d..5cfd8af99d 100644
--- a/meta/classes/kernel-fitimage.bbclass
+++ b/meta/classes/kernel-fitimage.bbclass
@@ -55,7 +55,7 @@ python __anonymous () {
 
 
 # Description string
-FIT_DESC ?= "U-Boot fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}"
+FIT_DESC ?= "Kernel fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}"
 
 # Sign individual images as well
 FIT_SIGN_INDIVIDUAL ?= "0"
@@ -695,12 +695,22 @@ kernel_do_deploy_append() {
 				ln -snf fitImage-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_NAME}.bin "$deployDir/fitImage-${INITRAMFS_IMAGE_NAME}-${KERNEL_FIT_LINK_NAME}"
 			fi
 		fi
-		if [ "${UBOOT_SIGN_ENABLE}" = "1" -a -n "${UBOOT_DTB_BINARY}" ] ; then
-			# UBOOT_DTB_IMAGE is a realfile, but we can't use
-			# ${UBOOT_DTB_IMAGE} since it contains ${PV} which is aimed
-			# for u-boot, but we are in kernel env now.
-			install -m 0644 ${B}/u-boot-${MACHINE}*.dtb "$deployDir/"
-		fi
+	fi
+	if [ "${UBOOT_SIGN_ENABLE}" = "1" -o "${UBOOT_FITIMAGE_ENABLE}" = "1" ] && \
+	   [ -n "${UBOOT_DTB_BINARY}" ] ; then
+		# UBOOT_DTB_IMAGE is a realfile, but we can't use
+		# ${UBOOT_DTB_IMAGE} since it contains ${PV} which is aimed
+		# for u-boot, but we are in kernel env now.
+		install -m 0644 ${B}/u-boot-${MACHINE}*.dtb "$deployDir/"
+	fi
+	if [ "${UBOOT_FITIMAGE_ENABLE}" = "1" -a -n "${UBOOT_BINARY}" -a -n "${SPL_DTB_BINARY}" ] ; then
+		# If we're also creating and/or signing the uboot fit, now we need to
+		# deploy it, it's its file, as well as u-boot-spl.dtb
+		install -m 0644 ${B}/u-boot-spl-${MACHINE}*.dtb "$deployDir/"
+		echo "Copying u-boot-fitImage file..."
+		install -m 0644 ${B}/u-boot-fitImage-* "$deployDir/"
+		echo "Copying u-boot-its file..."
+		install -m 0644 ${B}/u-boot-its-* "$deployDir/"
 	fi
 }
 
diff --git a/meta/classes/uboot-sign.bbclass b/meta/classes/uboot-sign.bbclass
index d57bef6669..30ccebe94a 100644
--- a/meta/classes/uboot-sign.bbclass
+++ b/meta/classes/uboot-sign.bbclass
@@ -34,26 +34,36 @@
 # We need some variables from u-boot-config
 inherit uboot-config
 
-# Signature activation.
+# Enable use of a U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE ?= "0"
+
+# Signature activation - these require their respective fitImages
 UBOOT_SIGN_ENABLE ?= "0"
+SPL_SIGN_ENABLE ?= "0"
 
 # Default value for deployment filenames.
 UBOOT_DTB_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.dtb"
 UBOOT_DTB_BINARY ?= "u-boot.dtb"
 UBOOT_DTB_SYMLINK ?= "u-boot-${MACHINE}.dtb"
-UBOOT_NODTB_IMAGE ?= "u-boot-nodtb-${MACHINE}-${PV}-${PR}.${UBOOT_SUFFIX}"
-UBOOT_NODTB_BINARY ?= "u-boot-nodtb.${UBOOT_SUFFIX}"
-UBOOT_NODTB_SYMLINK ?= "u-boot-nodtb-${MACHINE}.${UBOOT_SUFFIX}"
-UBOOT_ITS_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.its"
+UBOOT_NODTB_IMAGE ?= "u-boot-nodtb-${MACHINE}-${PV}-${PR}.bin"
+UBOOT_NODTB_BINARY ?= "u-boot-nodtb.bin"
+UBOOT_NODTB_SYMLINK ?= "u-boot-nodtb-${MACHINE}.bin"
+UBOOT_ITS_IMAGE ?= "u-boot-its-${MACHINE}-${PV}-${PR}"
 UBOOT_ITS ?= "u-boot.its"
-UBOOT_ITS_SYMLINK ?= "u-boot-${MACHINE}.its"
-SPL_DIR ?= "${@os.path.dirname(d.getVar("SPL_BINARY")) or '.'}"
+UBOOT_ITS_SYMLINK ?= "u-boot-its-${MACHINE}"
+UBOOT_FITIMAGE_IMAGE ?= "u-boot-fitImage-${MACHINE}-${PV}-${PR}"
+UBOOT_FITIMAGE_BINARY ?= "u-boot-fitImage"
+UBOOT_FITIMAGE_SYMLINK ?= "u-boot-fitImage-${MACHINE}"
+SPL_DIR ?= "spl"
 SPL_DTB_IMAGE ?= "u-boot-spl-${MACHINE}-${PV}-${PR}.dtb"
 SPL_DTB_BINARY ?= "u-boot-spl.dtb"
 SPL_DTB_SYMLINK ?= "u-boot-spl-${MACHINE}.dtb"
-SPL_NODTB_IMAGE ?= "${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[0]}-nodtb-${MACHINE}-${PV}-${PR}${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[1]}"
-SPL_NODTB_BINARY ?= "${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[0]}-nodtb${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[1]}"
-SPL_NODTB_SYMLINK ?= "${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[0]}-nodtb-${MACHINE}${@os.path.splitext(d.getVar("SPL_BINARYNAME"))[1]}"
+SPL_NODTB_IMAGE ?= "u-boot-spl-nodtb-${MACHINE}-${PV}-${PR}.bin"
+SPL_NODTB_BINARY ?= "u-boot-spl-nodtb.bin"
+SPL_NODTB_SYMLINK ?= "u-boot-spl-nodtb-${MACHINE}.bin"
+
+# U-Boot fitImage description
+UBOOT_FIT_DESC ?= "U-Boot fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}"
 
 # fitImage Hash Algo
 FIT_HASH_ALG ?= "sha256"
@@ -77,8 +87,18 @@ FIT_KEY_REQ_ARGS ?= "-batch -new"
 # Standard format for public key certificate
 FIT_KEY_SIGN_PKCS ?= "-x509"
 
-# Functions in this bbclass is for u-boot only
+# Functions on this bbclass can apply to either U-boot or Kernel,
+# depending on the scenario
 UBOOT_PN = "${@d.getVar('PREFERRED_PROVIDER_u-boot') or 'u-boot'}"
+KERNEL_PN = "${@d.getVar('PREFERRED_PROVIDER_virtual/kernel')}"
+
+# We need u-boot-tools-native if we're creating a U-Boot fitImage
+python() {
+    if d.getVar('UBOOT_FITIMAGE_ENABLE') == '1':
+        depends = d.getVar("DEPENDS")
+        depends = "%s u-boot-tools-native dtc-native" % depends
+        d.setVar("DEPENDS", depends)
+}
 
 concat_dtb_helper() {
 	if [ -e "${UBOOT_DTB_BINARY}" ]; then
@@ -92,21 +112,51 @@ concat_dtb_helper() {
 		ln -sf ${UBOOT_NODTB_IMAGE} ${DEPLOYDIR}/${UBOOT_NODTB_BINARY}
 	fi
 
-	# Concatenate U-Boot w/o DTB & DTB with public key
-	# (cf. kernel-fitimage.bbclass for more details)
-	deployed_uboot_dtb_binary='${DEPLOY_DIR_IMAGE}/${UBOOT_DTB_IMAGE}'
-	if [ "x${UBOOT_SUFFIX}" = "ximg" -o "x${UBOOT_SUFFIX}" = "xrom" ] && \
-		[ -e "$deployed_uboot_dtb_binary" ]; then
-		oe_runmake EXT_DTB=$deployed_uboot_dtb_binary
-		install ${UBOOT_BINARY} ${DEPLOYDIR}/${UBOOT_IMAGE}
-	elif [ -e "${DEPLOYDIR}/${UBOOT_NODTB_IMAGE}" -a -e "$deployed_uboot_dtb_binary" ]; then
+	# If we're not using a signed u-boot fit, concatenate SPL w/o DTB & U-Boot DTB
+	# with public key (otherwise it will be deployed by the equivalent
+	# concat_spl_dtb_helper function - cf. kernel-fitimage.bbclass for more details)
+	if [ "${SPL_SIGN_ENABLE}" != "1" ] ; then
+		deployed_uboot_dtb_binary='${DEPLOY_DIR_IMAGE}/${UBOOT_DTB_IMAGE}'
+		if [ "x${UBOOT_SUFFIX}" = "ximg" -o "x${UBOOT_SUFFIX}" = "xrom" ] && \
+			[ -e "$deployed_uboot_dtb_binary" ]; then
+			oe_runmake EXT_DTB=$deployed_uboot_dtb_binary
+			install ${UBOOT_BINARY} ${DEPLOYDIR}/${UBOOT_IMAGE}
+		elif [ -e "${DEPLOYDIR}/${UBOOT_NODTB_IMAGE}" -a -e "$deployed_uboot_dtb_binary" ]; then
+			cd ${DEPLOYDIR}
+			cat ${UBOOT_NODTB_IMAGE} $deployed_uboot_dtb_binary | tee ${B}/${CONFIG_B_PATH}/${UBOOT_BINARY} > ${UBOOT_IMAGE}
+		else
+			bbwarn "Failure while adding public key to u-boot binary. Verified boot won't be available."
+		fi
+	fi
+}
+
+concat_spl_dtb_helper() {
+
+	# We only deploy symlinks to the u-boot-spl.dtb,as the KERNEL_PN will
+	# be responsible for deploying the real file
+	if [ -e "${SPL_DIR}/${SPL_DTB_BINARY}" ] ; then
+		deployed_spl_dtb_binary='${DEPLOY_DIR_IMAGE}/${SPL_DTB_IMAGE}'
+		ln -sf ${SPL_DTB_IMAGE} ${DEPLOYDIR}/${SPL_DTB_SYMLINK}
+		ln -sf ${SPL_DTB_IMAGE} ${DEPLOYDIR}/${SPL_DTB_BINARY}
+	fi
+
+	if [ -f "${SPL_DIR}/${SPL_NODTB_BINARY}" ] ; then
+		echo "Copying u-boot-nodtb binary..."
+		install -m 0644 ${SPL_DIR}/${SPL_NODTB_BINARY} ${DEPLOYDIR}/${SPL_NODTB_IMAGE}
+		ln -sf ${SPL_NODTB_IMAGE} ${DEPLOYDIR}/${SPL_NODTB_SYMLINK}
+		ln -sf ${SPL_NODTB_IMAGE} ${DEPLOYDIR}/${SPL_NODTB_BINARY}
+	fi
+
+	# Concatenate the SPL nodtb binary and u-boot.dtb
+	if [ -e "${DEPLOYDIR}/${SPL_NODTB_IMAGE}" -a -e "$deployed_spl_dtb_binary" ] ; then
 		cd ${DEPLOYDIR}
-		cat ${UBOOT_NODTB_IMAGE} $deployed_uboot_dtb_binary | tee ${B}/${CONFIG_B_PATH}/${UBOOT_BINARY} > ${UBOOT_IMAGE}
+		cat ${SPL_NODTB_IMAGE} $deployed_spl_dtb_binary | tee ${B}/${CONFIG_B_PATH}/${SPL_BINARY} > ${SPL_IMAGE}
 	else
-		bbwarn "Failure while adding public key to u-boot binary. Verified boot won't be available."
+		bbwarn "Failure while adding public key to spl binary. Verified U-Boot boot won't be available."
 	fi
 }
 
+
 concat_dtb() {
 	if [ "${UBOOT_SIGN_ENABLE}" = "1" -a "${PN}" = "${UBOOT_PN}" -a -n "${UBOOT_DTB_BINARY}" ]; then
 		mkdir -p ${DEPLOYDIR}
@@ -124,6 +174,24 @@ concat_dtb() {
 	fi
 }
 
+concat_spl_dtb() {
+	if [ "${SPL_SIGN_ENABLE}" = "1" -a "${PN}" = "${UBOOT_PN}" -a -n "${SPL_DTB_BINARY}" ]; then
+		mkdir -p ${DEPLOYDIR}
+		if [ -n "${UBOOT_CONFIG}" ]; then
+			for config in ${UBOOT_MACHINE}; do
+				CONFIG_B_PATH="${config}"
+				cd ${B}/${config}
+				concat_spl_dtb_helper
+			done
+		else
+			CONFIG_B_PATH=""
+			cd ${B}
+			concat_spl_dtb_helper
+		fi
+	fi
+}
+
+
 # Install UBOOT_DTB_BINARY to datadir, so that kernel can use it for
 # signing, and kernel will deploy UBOOT_DTB_BINARY after signs it.
 install_helper() {
@@ -138,30 +206,257 @@ install_helper() {
 	fi
 }
 
+# Install SPL dtb and u-boot nodtb to datadir, 
+install_spl_helper() {
+	if [ -f "${SPL_DIR}/${SPL_DTB_BINARY}" ]; then
+		install -d ${D}${datadir}
+		install ${SPL_DIR}/${SPL_DTB_BINARY} ${D}${datadir}/${SPL_DTB_IMAGE}
+		ln -sf ${SPL_DTB_IMAGE} ${D}${datadir}/${SPL_DTB_BINARY}
+	else
+		bbwarn "${SPL_DTB_BINARY} not found"
+	fi
+	if [ -f "${UBOOT_NODTB_BINARY}" ] ; then
+		install ${UBOOT_NODTB_BINARY} ${D}${datadir}/${UBOOT_NODTB_IMAGE}
+		ln -sf ${UBOOT_NODTB_IMAGE} ${D}${datadir}/${UBOOT_NODTB_BINARY}
+	else
+		bbwarn "${UBOOT_NODTB_BINARY} not found"
+	fi
+
+	# We need to install a 'stub' u-boot-fitimage + its to datadir,
+	# so that the KERNEL_PN can use the correct filename when
+	# assembling and deploying them
+	touch ${D}/${datadir}/${UBOOT_FITIMAGE_IMAGE}
+	touch ${D}/${datadir}/${UBOOT_ITS_IMAGE}
+}
+
 do_install_append() {
-	if [ "${UBOOT_SIGN_ENABLE}" = "1" -a "${PN}" = "${UBOOT_PN}" -a -n "${UBOOT_DTB_BINARY}" ]; then
+	if [ "${PN}" = "${UBOOT_PN}" ]; then
 		if [ -n "${UBOOT_CONFIG}" ]; then
 			for config in ${UBOOT_MACHINE}; do
 				cd ${B}/${config}
-				install_helper
+				if [ "${UBOOT_SIGN_ENABLE}" = "1" -o "${UBOOT_FITIMAGE_ENABLE}" = "1" ] && \
+					[ -n "${UBOOT_DTB_BINARY}" ]; then
+					install_helper
+				fi
+				if [ "${SPL_SIGN_ENABLE}" = "1" -a -n "${SPL_DTB_BINARY}" ]; then
+					install_spl_helper
+				fi
 			done
 		else
 			cd ${B}
-			install_helper
+			if [ "${UBOOT_SIGN_ENABLE}" = "1" -o "${UBOOT_FITIMAGE_ENABLE}" = "1" ] && \
+				[ -n "${UBOOT_DTB_BINARY}" ]; then
+				install_helper
+			fi
+			if [ "${UBOOT_FITIMAGE_ENABLE}" = "1" -a -n "${SPL_DTB_BINARY}" ]; then
+				install_spl_helper
+			fi
 		fi
 	fi
 }
 
+do_generate_rsa_keys() {
+	if [ "${UBOOT_SIGN_ENABLE}" = "0" ] && [ "${FIT_GENERATE_KEYS}" = "1" ]; then
+		bbwarn "FIT_GENERATE_KEYS is set to 1 even though UBOOT_SIGN_ENABLE is set to 0. The keys will not be generated as they won't be used."
+	fi
+
+	if [ "${UBOOT_SIGN_ENABLE}" = "1" ] && [ "${FIT_GENERATE_KEYS}" = "1" ]; then
+
+		# Generate keys only if they don't already exist
+		if [ ! -f "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".key ] || \
+			[ ! -f "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".crt ]; then
+
+			# make directory if it does not already exist
+			mkdir -p "${UBOOT_SIGN_KEYDIR}"
+
+			echo "Generating RSA private key for signing fitImage"
+			openssl genrsa ${FIT_KEY_GENRSA_ARGS} -out \
+				"${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".key \
+				"${FIT_SIGN_NUMBITS}"
+
+			echo "Generating certificate for signing fitImage"
+			openssl req ${FIT_KEY_REQ_ARGS} "${FIT_KEY_SIGN_PKCS}" \
+				-key "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".key \
+				-out "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".crt
+		fi
+	fi
+}
+
+addtask generate_rsa_keys before do_uboot_assemble_fitimage after do_compile
+
+# Create a ITS file for the U-boot FIT, for use when
+# we want to sign it so that the SPL can verify it
+uboot_fitimage_assemble() {
+	uboot_its="${1}"
+	uboot_nodtb_bin="${2}"
+	uboot_dtb="${3}"
+	uboot_bin="${4}"
+	spl_dtb="${5}"
+	uboot_csum="${FIT_HASH_ALG}"
+	uboot_sign_algo="${FIT_SIGN_ALG}"
+	uboot_sign_keyname="${UBOOT_SIGN_KEYNAME}"
+
+	rm -f ${uboot_its} ${uboot_bin}
+
+	# First we create the ITS script
+	cat << EOF >> ${uboot_its}
+/dts-v1/;
+
+/ {
+    description = "${UBOOT_FIT_DESC}";
+    #address-cells = <1>;
+
+    images {
+        uboot {
+            description = "U-Boot image";
+            data = /incbin/("${uboot_nodtb_bin}");
+            type = "uboot";
+            os = "U-Boot";
+            arch = "${UBOOT_ARCH}";
+            compression = "none";
+            load = <${UBOOT_LOADADDRESS}>;
+            entry = <${UBOOT_ENTRYPOINT}>;
+EOF
+
+	if [ "${SPL_SIGN_ENABLE}" = "1" ] ; then
+		cat << EOF >> ${uboot_its}
+            signature {
+                algo = "${uboot_csum},${uboot_sign_algo}";
+                key-name-hint = "${uboot_sign_keyname}";
+            };
+EOF
+	fi
+
+	cat << EOF >> ${uboot_its}
+        };
+        fdt {
+            description = "U-Boot FDT";
+            data = /incbin/("${uboot_dtb}");
+            type = "flat_dt";
+            arch = "${UBOOT_ARCH}";
+            compression = "none";
+EOF
+
+	if [ "${SPL_SIGN_ENABLE}" = "1" ] ; then
+		cat << EOF >> ${uboot_its}
+            signature {
+                algo = "${uboot_csum},${uboot_sign_algo}";
+                key-name-hint = "${uboot_sign_keyname}";
+            };
+EOF
+	fi
+
+	cat << EOF >> ${uboot_its}
+        };
+    };
+
+    configurations {
+        default = "conf";
+        conf {
+            description = "Boot with signed U-Boot FIT";
+            loadables = "uboot";
+            fdt = "fdt";
+        };
+    };
+};
+EOF
+
+	#
+	# Assemble the U-boot FIT image
+	#
+	${UBOOT_MKIMAGE} \
+		${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \
+		-f ${uboot_its} \
+		${uboot_bin}
+
+	if [ "${SPL_SIGN_ENABLE}" = "1" ] ; then
+		#
+		# Sign the U-boot FIT image and add public key to SPL dtb
+		#
+		${UBOOT_MKIMAGE_SIGN} \
+			${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \
+			-F -k "${SPL_SIGN_KEYDIR}" \
+			-K "${spl_dtb}" \
+			-r ${uboot_bin} \
+			${UBOOT_MKIMAGE_SIGN_ARGS}
+	fi
+
+}
+
+do_uboot_assemble_fitimage() {
+	# This function runs in KERNEL_PN context. The reason for that is that we need to
+	# support the scenario where UBOOT_SIGN_ENABLE is placing the Kernel fitImage's
+	# pubkey in the u-boot.dtb file, so that we can use it when building the U-Boot
+	# fitImage itself.
+	if [ "${UBOOT_FITIMAGE_ENABLE}" = "1" ] && \
+	   [ -n "${SPL_DTB_BINARY}" -a "${PN}" = "${KERNEL_PN}" ] ; then
+		if [ "${UBOOT_SIGN_ENABLE}" != "1" ]; then
+			# If we're not signing the Kernel fitImage, that means
+			# we need to copy the u-boot.dtb from staging ourselves
+			cp -P ${STAGING_DATADIR}/u-boot*.dtb ${B}
+		fi
+		# As we are in the kernel context, we need to copy u-boot-spl.dtb from staging first.
+		# Unfortunately, need to glob on top of ${SPL_DTB_BINARY} since _IMAGE and _SYMLINK
+		# will contain U-boot's PV
+		# Similarly, we need to get the filename for the 'stub' u-boot-fitimage + its in
+		# staging so that we can use it for creating the image with the correct filename
+		# in the KERNEL_PN context.
+		# As for the u-boot.dtb (with fitimage's pubkey), it should come from the dependent
+		# do_assemble_fitimage task
+		cp -P ${STAGING_DATADIR}/u-boot-spl*.dtb ${B}
+		cp -P ${STAGING_DATADIR}/u-boot-nodtb*.bin ${B}
+		kernel_uboot_fitimage_name=`basename ${STAGING_DATADIR}/u-boot-fitImage-*`
+		kernel_uboot_its_name=`basename ${STAGING_DATADIR}/u-boot-its-*`
+		cd ${B}
+		uboot_fitimage_assemble ${kernel_uboot_its_name} ${UBOOT_NODTB_BINARY} \
+					${UBOOT_DTB_BINARY} ${kernel_uboot_fitimage_name} \
+					${SPL_DTB_BINARY}
+	fi
+}
+
+addtask uboot_assemble_fitimage before do_deploy after do_compile
+
 do_deploy_prepend_pn-${UBOOT_PN}() {
-	if [ "${UBOOT_SIGN_ENABLE}" = "1" -a -n "${UBOOT_DTB_BINARY}" ]; then
+	if [ "${UBOOT_SIGN_ENABLE}" = "1" -a -n "${UBOOT_DTB_BINARY}" ] ; then
 		concat_dtb
 	fi
+	if [ "${SPL_SIGN_ENABLE}" = "1" -a -n "${SPL_DTB_BINARY}" ] ; then
+		concat_spl_dtb
+	fi
+
+	# We only deploy the symlinks to the uboot-fitImage and uboot-its
+	# images, as the KERNEL_PN will take care of deploying the real file
+	if [ "${UBOOT_FITIMAGE_ENABLE}" = "1" ] ; then
+		ln -sf ${UBOOT_FITIMAGE_IMAGE} ${DEPLOYDIR}/${UBOOT_FITIMAGE_BINARY}
+		ln -sf ${UBOOT_FITIMAGE_IMAGE} ${DEPLOYDIR}/${UBOOT_FITIMAGE_SYMLINK}
+		ln -sf ${UBOOT_ITS_IMAGE} ${DEPLOYDIR}/${UBOOT_ITS}
+		ln -sf ${UBOOT_ITS_IMAGE} ${DEPLOYDIR}/${UBOOT_ITS_SYMLINK}
+	fi
+
 }
 
 python () {
-    if d.getVar('UBOOT_SIGN_ENABLE') == '1' and d.getVar('PN') == d.getVar('UBOOT_PN') and d.getVar('UBOOT_DTB_BINARY'):
-        kernel_pn = d.getVar('PREFERRED_PROVIDER_virtual/kernel')
+    if (   (d.getVar('UBOOT_SIGN_ENABLE') == '1'
+            or d.getVar('UBOOT_FITIMAGE_ENABLE') == '1')
+        and d.getVar('PN') == d.getVar('UBOOT_PN')
+        and d.getVar('UBOOT_DTB_BINARY')):
 
         # Make "bitbake u-boot -cdeploy" deploys the signed u-boot.dtb
-        d.appendVarFlag('do_deploy', 'depends', ' %s:do_deploy' % kernel_pn)
+        # and/or the U-Boot fitImage
+        d.appendVarFlag('do_deploy', 'depends', ' %s:do_deploy' % d.getVar('KERNEL_PN'))
+
+    if d.getVar('UBOOT_FITIMAGE_ENABLE') == '1' and d.getVar('PN') == d.getVar('KERNEL_PN'):
+        # As the U-Boot fitImage is created by the KERNEL_PN, we need
+        # to make sure that the u-boot-spl.dtb and u-boot-spl-nodtb.bin
+        # files are in the staging dir for it's use
+        d.appendVarFlag('do_uboot_assemble_fitimage', 'depends', ' %s:do_populate_sysroot' % d.getVar('UBOOT_PN'))
+
+        # If the Kernel fitImage is being signed, we need to
+        # create the U-Boot fitImage after it
+        if d.getVar('UBOOT_SIGN_ENABLE') == '1':
+            if d.getVar('INITRAMFS_IMAGE_BUNDLE') == "1":
+                d.appendVarFlag('do_uboot_assemble_fitimage', 'depends', ' %s:do_assemble_fitimage_initramfs' % d.getVar('KERNEL_PN'))
+            else:
+                d.appendVarFlag('do_uboot_assemble_fitimage', 'depends', ' %s:do_assemble_fitimage' % d.getVar('KERNEL_PN'))
+
 }
-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 3/4] u-boot: Use a different Key for SPL signing
  2021-03-26 20:14 [PATCH v2 0/4] u-boot: Support for SPL verified boot Klaus Heinrich Kiwi
  2021-03-26 20:14 ` [PATCH v2 1/4] u-boot: Move definitions to common locations Klaus Heinrich Kiwi
  2021-03-26 20:14 ` [PATCH v2 2/4] u-boot: Add infrastructure to SPL verified boot Klaus Heinrich Kiwi
@ 2021-03-26 20:14 ` Klaus Heinrich Kiwi
  2021-03-26 20:14 ` [PATCH v2 4/4] oe-selftest: Add U-Boot fitImage signing testcases Klaus Heinrich Kiwi
  2021-04-06 10:57 ` [OE-core] [PATCH v2 0/4] u-boot: Support for SPL verified boot Richard Purdie
  4 siblings, 0 replies; 8+ messages in thread
From: Klaus Heinrich Kiwi @ 2021-03-26 20:14 UTC (permalink / raw)
  To: openembedded-core; +Cc: andrew, klaus, openbmc

Duplicate the variables governing u-boot signing so that we can have a
different set of keys/parameters signing the SPL.

Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
---
 meta/classes/uboot-config.bbclass |  2 ++
 meta/classes/uboot-sign.bbclass   | 53 +++++++++++++++++++++++++------
 2 files changed, 45 insertions(+), 10 deletions(-)

diff --git a/meta/classes/uboot-config.bbclass b/meta/classes/uboot-config.bbclass
index 31487c1418..3bba02828b 100644
--- a/meta/classes/uboot-config.bbclass
+++ b/meta/classes/uboot-config.bbclass
@@ -61,6 +61,7 @@ UBOOT_EXTLINUX_SYMLINK ?= "${UBOOT_EXTLINUX_CONF_NAME}-${MACHINE}-${PR}"
 
 # Options for the device tree compiler passed to mkimage '-D' feature:
 UBOOT_MKIMAGE_DTCOPTS ??= ""
+SPL_MKIMAGE_DTCOPTS ??= ""
 
 # mkimage command
 UBOOT_MKIMAGE ?= "uboot-mkimage"
@@ -68,6 +69,7 @@ UBOOT_MKIMAGE_SIGN ?= "${UBOOT_MKIMAGE}"
 
 # Arguments passed to mkimage for signing
 UBOOT_MKIMAGE_SIGN_ARGS ?= ""
+SPL_MKIMAGE_SIGN_ARGS ?= ""
 
 python () {
     ubootmachine = d.getVar("UBOOT_MACHINE")
diff --git a/meta/classes/uboot-sign.bbclass b/meta/classes/uboot-sign.bbclass
index 30ccebe94a..5f1750fdcc 100644
--- a/meta/classes/uboot-sign.bbclass
+++ b/meta/classes/uboot-sign.bbclass
@@ -65,27 +65,34 @@ SPL_NODTB_SYMLINK ?= "u-boot-spl-nodtb-${MACHINE}.bin"
 # U-Boot fitImage description
 UBOOT_FIT_DESC ?= "U-Boot fitImage for ${DISTRO_NAME}/${PV}/${MACHINE}"
 
-# fitImage Hash Algo
+# Kernel / U-Boot fitImage Hash Algo
 FIT_HASH_ALG ?= "sha256"
+UBOOT_FIT_HASH_ALG ?= "sha256"
 
-# fitImage Signature Algo
+# Kernel / U-Boot fitImage Signature Algo
 FIT_SIGN_ALG ?= "rsa2048"
+UBOOT_FIT_SIGN_ALG ?= "rsa2048"
 
-# Generate keys for signing fitImage
+# Generate keys for signing Kernel / U-Boot fitImage
 FIT_GENERATE_KEYS ?= "0"
+UBOOT_FIT_GENERATE_KEYS ?= "0"
 
-# Size of private key in number of bits
+# Size of private keys in number of bits
 FIT_SIGN_NUMBITS ?= "2048"
+UBOOT_FIT_SIGN_NUMBITS ?= "2048"
 
 # args to openssl genrsa (Default is just the public exponent)
 FIT_KEY_GENRSA_ARGS ?= "-F4"
+UBOOT_FIT_KEY_GENRSA_ARGS ?= "-F4"
 
 # args to openssl req (Default is -batch for non interactive mode and
 # -new for new certificate)
 FIT_KEY_REQ_ARGS ?= "-batch -new"
+UBOOT_FIT_KEY_REQ_ARGS ?= "-batch -new"
 
 # Standard format for public key certificate
 FIT_KEY_SIGN_PKCS ?= "-x509"
+UBOOT_FIT_KEY_SIGN_PKCS ?= "-x509"
 
 # Functions on this bbclass can apply to either U-boot or Kernel,
 # depending on the scenario
@@ -280,6 +287,32 @@ do_generate_rsa_keys() {
 				-out "${UBOOT_SIGN_KEYDIR}/${UBOOT_SIGN_KEYNAME}".crt
 		fi
 	fi
+
+	if [ "${SPL_SIGN_ENABLE}" = "0" ] && [ "${UBOOT_FIT_GENERATE_KEYS}" = "1" ]; then
+		bbwarn "UBOOT_FIT_GENERATE_KEYS is set to 1 eventhough SPL_SIGN_ENABLE is set to 0. The keys will not be generated as they won't be used."
+	fi
+
+	if [ "${SPL_SIGN_ENABLE}" = "1" ] && [ "${UBOOT_FIT_GENERATE_KEYS}" = "1" ]; then
+
+		# Generate keys only if they don't already exist
+		if [ ! -f "${SPL_SIGN_KEYDIR}/${SPL_SIGN_KEYNAME}".key ] || \
+			[ ! -f "${SPL_SIGN_KEYDIR}/${SPL_SIGN_KEYNAME}".crt ]; then
+
+			# make directory if it does not already exist
+			mkdir -p "${SPL_SIGN_KEYDIR}"
+
+			echo "Generating RSA private key for signing U-Boot fitImage"
+			openssl genrsa ${UBOOT_FIT_KEY_GENRSA_ARGS} -out \
+				"${SPL_SIGN_KEYDIR}/${SPL_SIGN_KEYNAME}".key \
+				"${UBOOT_FIT_SIGN_NUMBITS}"
+
+			echo "Generating certificate for signing U-Boot fitImage"
+			openssl req ${FIT_KEY_REQ_ARGS} "${UBOOT_FIT_KEY_SIGN_PKCS}" \
+				-key "${SPL_SIGN_KEYDIR}/${SPL_SIGN_KEYNAME}".key \
+				-out "${SPL_SIGN_KEYDIR}/${SPL_SIGN_KEYNAME}".crt
+		fi
+	fi
+
 }
 
 addtask generate_rsa_keys before do_uboot_assemble_fitimage after do_compile
@@ -292,9 +325,9 @@ uboot_fitimage_assemble() {
 	uboot_dtb="${3}"
 	uboot_bin="${4}"
 	spl_dtb="${5}"
-	uboot_csum="${FIT_HASH_ALG}"
-	uboot_sign_algo="${FIT_SIGN_ALG}"
-	uboot_sign_keyname="${UBOOT_SIGN_KEYNAME}"
+	uboot_csum="${UBOOT_FIT_HASH_ALG}"
+	uboot_sign_algo="${UBOOT_FIT_SIGN_ALG}"
+	uboot_sign_keyname="${SPL_SIGN_KEYNAME}"
 
 	rm -f ${uboot_its} ${uboot_bin}
 
@@ -365,7 +398,7 @@ EOF
 	# Assemble the U-boot FIT image
 	#
 	${UBOOT_MKIMAGE} \
-		${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \
+		${@'-D "${SPL_MKIMAGE_DTCOPTS}"' if len('${SPL_MKIMAGE_DTCOPTS}') else ''} \
 		-f ${uboot_its} \
 		${uboot_bin}
 
@@ -374,11 +407,11 @@ EOF
 		# Sign the U-boot FIT image and add public key to SPL dtb
 		#
 		${UBOOT_MKIMAGE_SIGN} \
-			${@'-D "${UBOOT_MKIMAGE_DTCOPTS}"' if len('${UBOOT_MKIMAGE_DTCOPTS}') else ''} \
+			${@'-D "${SPL_MKIMAGE_DTCOPTS}"' if len('${SPL_MKIMAGE_DTCOPTS}') else ''} \
 			-F -k "${SPL_SIGN_KEYDIR}" \
 			-K "${spl_dtb}" \
 			-r ${uboot_bin} \
-			${UBOOT_MKIMAGE_SIGN_ARGS}
+			${SPL_MKIMAGE_SIGN_ARGS}
 	fi
 
 }
-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 4/4] oe-selftest: Add U-Boot fitImage signing testcases
  2021-03-26 20:14 [PATCH v2 0/4] u-boot: Support for SPL verified boot Klaus Heinrich Kiwi
                   ` (2 preceding siblings ...)
  2021-03-26 20:14 ` [PATCH v2 3/4] u-boot: Use a different Key for SPL signing Klaus Heinrich Kiwi
@ 2021-03-26 20:14 ` Klaus Heinrich Kiwi
  2021-04-06 10:57 ` [OE-core] [PATCH v2 0/4] u-boot: Support for SPL verified boot Richard Purdie
  4 siblings, 0 replies; 8+ messages in thread
From: Klaus Heinrich Kiwi @ 2021-03-26 20:14 UTC (permalink / raw)
  To: openembedded-core; +Cc: andrew, klaus, openbmc

Derived from the similar kernel fitImage sign testcase, the U-Boot
fitImage testcases exercises the following fitimage.FitImageTest
scenarios:

 * test_uboot_fit_image - create unsigned U-Boot fitImage
 * test_uboot_sign_fit_image - create unsigned U-Boot fitImage in
   addition to signed Kernel fitImage
 * test_sign_standalone_uboot_fit_image - Create signed U-Boot fitImage
   without a Kernel fitImage
 * test_sign_cascaded_uboot_fit_image - Create and sign U-Boot and
   Kernel fitImages

Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
---
 meta/lib/oeqa/selftest/cases/fitimage.py | 468 +++++++++++++++++++++++
 1 file changed, 468 insertions(+)

diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
index 02692de822..b911fded74 100644
--- a/meta/lib/oeqa/selftest/cases/fitimage.py
+++ b/meta/lib/oeqa/selftest/cases/fitimage.py
@@ -231,6 +231,474 @@ UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart comment'"
         result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_assemble_fitimage' % tempdir, ignore_status=True)
         self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
 
+    def test_uboot_fit_image(self):
+        """
+        Summary:     Check if Uboot FIT image and Image Tree Source
+                     (its) are built and the Image Tree Source has the
+                     correct fields.
+        Expected:    1. u-boot-fitImage and u-boot-its can be built
+                     2. The type, load address, entrypoint address and
+                     default values of U-boot image are correct in the
+                     Image Tree Source. Not all the fields are tested,
+                     only the key fields that wont vary between
+                     different architectures.
+        Product:     oe-core
+        Author:      Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+                     based on work by Usama Arif <usama.arif@arm.com>
+        """
+        config = """
+# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+
+# Enable creation of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+
+# (U-boot) fitImage properties
+UBOOT_LOADADDRESS = "0x80080000"
+UBOOT_ENTRYPOINT = "0x80080000"
+UBOOT_FIT_DESC = "A model description"
+
+# Enable creation of Kernel fitImage
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage"
+UBOOT_SIGN_ENABLE = "1"
+FIT_GENERATE_KEYS = "1"
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_SIGN_KEYNAME = "oe-selftest"
+FIT_SIGN_INDIVIDUAL = "1"
+"""
+        self.write_config(config)
+
+        # The U-Boot fitImage is created as part of linux recipe
+        bitbake("virtual/kernel")
+
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+            "u-boot-its-%s" % (machine,))
+        fitimage_path = os.path.join(deploy_dir_image,
+            "u-boot-fitImage-%s" % (machine,))
+
+        self.assertTrue(os.path.exists(fitimage_its_path),
+            "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertTrue(os.path.exists(fitimage_path),
+            "%s FIT image doesn't exist" % (fitimage_path))
+
+        # Check that the type, load address, entrypoint address and default
+        # values for kernel and ramdisk in Image Tree Source are as expected.
+        # The order of fields in the below array is important. Not all the
+        # fields are tested, only the key fields that wont vary between
+        # different architectures.
+        its_field_check = [
+            'description = "A model description";',
+            'type = "uboot";',
+            'load = <0x80080000>;',
+            'entry = <0x80080000>;',
+            'default = "conf";',
+            'loadables = "uboot";',
+            'fdt = "fdt";'
+            ]
+
+        with open(fitimage_its_path) as its_file:
+            field_index = 0
+            for line in its_file:
+                if field_index == len(its_field_check):
+                    break
+                if its_field_check[field_index] in line:
+                    field_index +=1
+
+        if field_index != len(its_field_check): # if its equal, the test passed
+            self.assertTrue(field_index == len(its_field_check),
+                "Fields in Image Tree Source File %s did not match, error in finding %s"
+                % (fitimage_its_path, its_field_check[field_index]))
+
+    def test_uboot_sign_fit_image(self):
+        """
+        Summary:     Check if Uboot FIT image and Image Tree Source
+                     (its) are built and the Image Tree Source has the
+                     correct fields, in the scenario where the Kernel
+                     is also creating/signing it's fitImage.
+        Expected:    1. u-boot-fitImage and u-boot-its can be built
+                     2. The type, load address, entrypoint address and
+                     default values of U-boot image are correct in the
+                     Image Tree Source. Not all the fields are tested,
+                     only the key fields that wont vary between
+                     different architectures.
+        Product:     oe-core
+        Author:      Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+                     based on work by Usama Arif <usama.arif@arm.com>
+        """
+        config = """
+# We need at least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+
+# Enable creation of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+
+# (U-boot) fitImage properties
+UBOOT_LOADADDRESS = "0x80080000"
+UBOOT_ENTRYPOINT = "0x80080000"
+UBOOT_FIT_DESC = "A model description"
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
+UBOOT_SIGN_ENABLE = "1"
+FIT_GENERATE_KEYS = "1"
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_SIGN_KEYNAME = "oe-selftest"
+FIT_SIGN_INDIVIDUAL = "1"
+UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'"
+"""
+        self.write_config(config)
+
+        # The U-Boot fitImage is created as part of linux recipe
+        bitbake("virtual/kernel")
+
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+            "u-boot-its-%s" % (machine,))
+        fitimage_path = os.path.join(deploy_dir_image,
+            "u-boot-fitImage-%s" % (machine,))
+
+        self.assertTrue(os.path.exists(fitimage_its_path),
+            "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertTrue(os.path.exists(fitimage_path),
+            "%s FIT image doesn't exist" % (fitimage_path))
+
+        # Check that the type, load address, entrypoint address and default
+        # values for kernel and ramdisk in Image Tree Source are as expected.
+        # The order of fields in the below array is important. Not all the
+        # fields are tested, only the key fields that wont vary between
+        # different architectures.
+        its_field_check = [
+            'description = "A model description";',
+            'type = "uboot";',
+            'load = <0x80080000>;',
+            'entry = <0x80080000>;',
+            'default = "conf";',
+            'loadables = "uboot";',
+            'fdt = "fdt";'
+            ]
+
+        with open(fitimage_its_path) as its_file:
+            field_index = 0
+            for line in its_file:
+                if field_index == len(its_field_check):
+                    break
+                if its_field_check[field_index] in line:
+                    field_index +=1
+
+        if field_index != len(its_field_check): # if its equal, the test passed
+            self.assertTrue(field_index == len(its_field_check),
+                "Fields in Image Tree Source File %s did not match, error in finding %s"
+                % (fitimage_its_path, its_field_check[field_index]))
+
+
+    def test_sign_standalone_uboot_fit_image(self):
+        """
+        Summary:     Check if U-Boot FIT image and Image Tree Source (its) are
+                     created and signed correctly for the scenario where only
+                     the U-Boot proper fitImage is being created and signed.
+        Expected:    1) U-Boot its and FIT image are built successfully
+                     2) Scanning the its file indicates signing is enabled
+                        as requested by SPL_SIGN_ENABLE (using keys generated
+                        via UBOOT_FIT_GENERATE_KEYS)
+                     3) Dumping the FIT image indicates signature values
+                        are present
+                     4) Examination of the do_uboot_assemble_fitimage
+                     runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN
+                     and SPL_MKIMAGE_SIGN_ARGS are working as expected.
+        Product:     oe-core
+        Author:      Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon
+                     work by Paul Eggleton <paul.eggleton@microsoft.com> and
+                     Usama Arif <usama.arif@arm.com>
+        """
+        config = """
+# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at
+# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+# The kernel-fitimage class is a dependency even if we're only
+# creating/signing the U-Boot fitImage
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
+# Enable creation and signing of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+SPL_SIGN_ENABLE = "1"
+SPL_SIGN_KEYNAME = "spl-oe-selftest"
+SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_DTB_BINARY = "u-boot.dtb"
+UBOOT_ENTRYPOINT  = "0x80000000"
+UBOOT_LOADADDRESS = "0x80000000"
+UBOOT_DTB_LOADADDRESS = "0x82000000"
+UBOOT_ARCH = "arm"
+SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart U-Boot comment'"
+UBOOT_EXTLINUX = "0"
+UBOOT_FIT_GENERATE_KEYS = "1"
+UBOOT_FIT_HASH_ALG = "sha256"
+"""
+        self.write_config(config)
+
+        # The U-Boot fitImage is created as part of linux recipe
+        bitbake("virtual/kernel")
+
+        image_type = "core-image-minimal"
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+            "u-boot-its-%s" % (machine,))
+        fitimage_path = os.path.join(deploy_dir_image,
+            "u-boot-fitImage-%s" % (machine,))
+
+        self.assertTrue(os.path.exists(fitimage_its_path),
+            "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertTrue(os.path.exists(fitimage_path),
+            "%s FIT image doesn't exist" % (fitimage_path))
+
+        req_itspaths = [
+            ['/', 'images', 'uboot'],
+            ['/', 'images', 'uboot', 'signature'],
+            ['/', 'images', 'fdt'],
+            ['/', 'images', 'fdt', 'signature'],
+        ]
+
+        itspath = []
+        itspaths = []
+        linect = 0
+        sigs = {}
+        with open(fitimage_its_path) as its_file:
+            linect += 1
+            for line in its_file:
+                line = line.strip()
+                if line.endswith('};'):
+                    itspath.pop()
+                elif line.endswith('{'):
+                    itspath.append(line[:-1].strip())
+                    itspaths.append(itspath[:])
+                elif itspath and itspath[-1] == 'signature':
+                    itsdotpath = '.'.join(itspath)
+                    if not itsdotpath in sigs:
+                        sigs[itsdotpath] = {}
+                    if not '=' in line or not line.endswith(';'):
+                        self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line))
+                    key, value = line.split('=', 1)
+                    sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';')
+
+        for reqpath in req_itspaths:
+            if not reqpath in itspaths:
+                self.fail('Missing section in its file: %s' % reqpath)
+
+        reqsigvalues_image = {
+            'algo': '"sha256,rsa2048"',
+            'key-name-hint': '"spl-oe-selftest"',
+        }
+
+        for itspath, values in sigs.items():
+            reqsigvalues = reqsigvalues_image
+            for reqkey, reqvalue in reqsigvalues.items():
+                value = values.get(reqkey, None)
+                if value is None:
+                    self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath))
+                self.assertEqual(value, reqvalue)
+
+        # Dump the image to see if it really got signed
+        bitbake("u-boot-tools-native -c addto_recipe_sysroot")
+        result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=')
+        recipe_sysroot_native = result.output.split('=')[1].strip('"')
+        dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage')
+        result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path))
+        in_signed = None
+        signed_sections = {}
+        for line in result.output.splitlines():
+            if line.startswith((' Image')):
+                in_signed = re.search('\((.*)\)', line).groups()[0]
+            elif re.match(' \w', line):
+                in_signed = None
+            elif in_signed:
+                if not in_signed in signed_sections:
+                    signed_sections[in_signed] = {}
+                key, value = line.split(':', 1)
+                signed_sections[in_signed][key.strip()] = value.strip()
+        self.assertIn('uboot', signed_sections)
+        self.assertIn('fdt', signed_sections)
+        for signed_section, values in signed_sections.items():
+            value = values.get('Sign algo', None)
+            self.assertEqual(value, 'sha256,rsa2048:spl-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section)
+            value = values.get('Sign value', None)
+            self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section)
+
+        # Check for SPL_MKIMAGE_SIGN_ARGS
+        result = runCmd('bitbake -e virtual/kernel | grep ^T=')
+        tempdir = result.output.split('=', 1)[1].strip().strip('')
+        result = runCmd('grep "a smart U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+        self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used')
+
+        # Check for evidence of test-mkimage-wrapper class
+        result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+        self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work')
+        result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+        self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
+
+    def test_sign_cascaded_uboot_fit_image(self):
+        """
+        Summary:     Check if U-Boot FIT image and Image Tree Source (its) are
+                     created and signed correctly for the scenario where both
+                     U-Boot proper and Kernel fitImages are being created and
+                     signed.
+        Expected:    1) U-Boot its and FIT image are built successfully
+                     2) Scanning the its file indicates signing is enabled
+                        as requested by SPL_SIGN_ENABLE (using keys generated
+                        via UBOOT_FIT_GENERATE_KEYS)
+                     3) Dumping the FIT image indicates signature values
+                        are present
+                     4) Examination of the do_uboot_assemble_fitimage
+                     runfile/logfile indicate that UBOOT_MKIMAGE, UBOOT_MKIMAGE_SIGN
+                     and SPL_MKIMAGE_SIGN_ARGS are working as expected.
+        Product:     oe-core
+        Author:      Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> based upon
+                     work by Paul Eggleton <paul.eggleton@microsoft.com> and
+                     Usama Arif <usama.arif@arm.com>
+        """
+        config = """
+# There's no U-boot deconfig with CONFIG_FIT_SIGNATURE yet, so we need at
+# least CONFIG_SPL_LOAD_FIT and CONFIG_SPL_OF_CONTROL set
+MACHINE = "qemuarm"
+UBOOT_MACHINE = "am57xx_evm_defconfig"
+SPL_BINARY = "MLO"
+# Enable creation and signing of the U-Boot fitImage
+UBOOT_FITIMAGE_ENABLE = "1"
+SPL_SIGN_ENABLE = "1"
+SPL_SIGN_KEYNAME = "spl-cascaded-oe-selftest"
+SPL_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_DTB_BINARY = "u-boot.dtb"
+UBOOT_ENTRYPOINT  = "0x80000000"
+UBOOT_LOADADDRESS = "0x80000000"
+UBOOT_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+UBOOT_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded Kernel comment'"
+UBOOT_DTB_LOADADDRESS = "0x82000000"
+UBOOT_ARCH = "arm"
+SPL_MKIMAGE_DTCOPTS = "-I dts -O dtb -p 2000"
+SPL_MKIMAGE_SIGN_ARGS = "-c 'a smart cascaded U-Boot comment'"
+UBOOT_EXTLINUX = "0"
+UBOOT_FIT_GENERATE_KEYS = "1"
+UBOOT_FIT_HASH_ALG = "sha256"
+KERNEL_IMAGETYPES += " fitImage "
+KERNEL_CLASSES = " kernel-fitimage test-mkimage-wrapper "
+UBOOT_SIGN_ENABLE = "1"
+FIT_GENERATE_KEYS = "1"
+UBOOT_SIGN_KEYDIR = "${TOPDIR}/signing-keys"
+UBOOT_SIGN_KEYNAME = "kernel-oe-selftest"
+FIT_SIGN_INDIVIDUAL = "1"
+"""
+        self.write_config(config)
+
+        # The U-Boot fitImage is created as part of linux recipe
+        bitbake("virtual/kernel")
+
+        image_type = "core-image-minimal"
+        deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
+        machine = get_bb_var('MACHINE')
+        fitimage_its_path = os.path.join(deploy_dir_image,
+            "u-boot-its-%s" % (machine,))
+        fitimage_path = os.path.join(deploy_dir_image,
+            "u-boot-fitImage-%s" % (machine,))
+
+        self.assertTrue(os.path.exists(fitimage_its_path),
+            "%s image tree source doesn't exist" % (fitimage_its_path))
+        self.assertTrue(os.path.exists(fitimage_path),
+            "%s FIT image doesn't exist" % (fitimage_path))
+
+        req_itspaths = [
+            ['/', 'images', 'uboot'],
+            ['/', 'images', 'uboot', 'signature'],
+            ['/', 'images', 'fdt'],
+            ['/', 'images', 'fdt', 'signature'],
+        ]
+
+        itspath = []
+        itspaths = []
+        linect = 0
+        sigs = {}
+        with open(fitimage_its_path) as its_file:
+            linect += 1
+            for line in its_file:
+                line = line.strip()
+                if line.endswith('};'):
+                    itspath.pop()
+                elif line.endswith('{'):
+                    itspath.append(line[:-1].strip())
+                    itspaths.append(itspath[:])
+                elif itspath and itspath[-1] == 'signature':
+                    itsdotpath = '.'.join(itspath)
+                    if not itsdotpath in sigs:
+                        sigs[itsdotpath] = {}
+                    if not '=' in line or not line.endswith(';'):
+                        self.fail('Unexpected formatting in %s sigs section line %d:%s' % (fitimage_its_path, linect, line))
+                    key, value = line.split('=', 1)
+                    sigs[itsdotpath][key.rstrip()] = value.lstrip().rstrip(';')
+
+        for reqpath in req_itspaths:
+            if not reqpath in itspaths:
+                self.fail('Missing section in its file: %s' % reqpath)
+
+        reqsigvalues_image = {
+            'algo': '"sha256,rsa2048"',
+            'key-name-hint': '"spl-cascaded-oe-selftest"',
+        }
+
+        for itspath, values in sigs.items():
+            reqsigvalues = reqsigvalues_image
+            for reqkey, reqvalue in reqsigvalues.items():
+                value = values.get(reqkey, None)
+                if value is None:
+                    self.fail('Missing key "%s" in its file signature section %s' % (reqkey, itspath))
+                self.assertEqual(value, reqvalue)
+
+        # Dump the image to see if it really got signed
+        bitbake("u-boot-tools-native -c addto_recipe_sysroot")
+        result = runCmd('bitbake -e u-boot-tools-native | grep ^RECIPE_SYSROOT_NATIVE=')
+        recipe_sysroot_native = result.output.split('=')[1].strip('"')
+        dumpimage_path = os.path.join(recipe_sysroot_native, 'usr', 'bin', 'dumpimage')
+        result = runCmd('%s -l %s' % (dumpimage_path, fitimage_path))
+        in_signed = None
+        signed_sections = {}
+        for line in result.output.splitlines():
+            if line.startswith((' Image')):
+                in_signed = re.search('\((.*)\)', line).groups()[0]
+            elif re.match(' \w', line):
+                in_signed = None
+            elif in_signed:
+                if not in_signed in signed_sections:
+                    signed_sections[in_signed] = {}
+                key, value = line.split(':', 1)
+                signed_sections[in_signed][key.strip()] = value.strip()
+        self.assertIn('uboot', signed_sections)
+        self.assertIn('fdt', signed_sections)
+        for signed_section, values in signed_sections.items():
+            value = values.get('Sign algo', None)
+            self.assertEqual(value, 'sha256,rsa2048:spl-cascaded-oe-selftest', 'Signature algorithm for %s not expected value' % signed_section)
+            value = values.get('Sign value', None)
+            self.assertEqual(len(value), 512, 'Signature value for section %s not expected length' % signed_section)
+
+        # Check for SPL_MKIMAGE_SIGN_ARGS
+        result = runCmd('bitbake -e virtual/kernel | grep ^T=')
+        tempdir = result.output.split('=', 1)[1].strip().strip('')
+        result = runCmd('grep "a smart cascaded U-Boot comment" %s/run.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+        self.assertEqual(result.status, 0, 'SPL_MKIMAGE_SIGN_ARGS value did not get used')
+
+        # Check for evidence of test-mkimage-wrapper class
+        result = runCmd('grep "### uboot-mkimage wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+        self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE did not work')
+        result = runCmd('grep "### uboot-mkimage signing wrapper message" %s/log.do_uboot_assemble_fitimage' % tempdir, ignore_status=True)
+        self.assertEqual(result.status, 0, 'UBOOT_MKIMAGE_SIGN did not work')
+
+
+
     def test_initramfs_bundle(self):
         """
         Summary:     Verifies the content of the initramfs bundle node in the FIT Image Tree Source (its)
-- 
2.25.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [OE-core] [PATCH v2 0/4] u-boot: Support for SPL verified boot
  2021-03-26 20:14 [PATCH v2 0/4] u-boot: Support for SPL verified boot Klaus Heinrich Kiwi
                   ` (3 preceding siblings ...)
  2021-03-26 20:14 ` [PATCH v2 4/4] oe-selftest: Add U-Boot fitImage signing testcases Klaus Heinrich Kiwi
@ 2021-04-06 10:57 ` Richard Purdie
  2021-04-06 13:21   ` Klaus Heinrich Kiwi
  4 siblings, 1 reply; 8+ messages in thread
From: Richard Purdie @ 2021-04-06 10:57 UTC (permalink / raw)
  To: Klaus Heinrich Kiwi, openembedded-core; +Cc: andrew, openbmc

On Fri, 2021-03-26 at 17:14 -0300, Klaus Heinrich Kiwi wrote:
> This patch series aims at extending U-Boot's verified boot support to
> also include SPL.
> 
> Presently, setting UBOOT_SIGN_ENABLE instructs the classes uboot-sign
> and kernel-fitimage to create and sign a Linux Kernel fitImage. This
> proposal introduces the variables UBOOT_FITIMAGE_ENABLE and
> SPL_SIGN_ENABLE that will, respectively, create and sign a U-Boot
> (proper) fitImage that the SPL can load (and verify if enabled)
> 
> In order to accomplish this, the first patch moves some of necessary
> infrastructure (variables, functions) used to sign the Kernel
> fitImage to more common locations, and then essentially duplicates the
> method currently used to sign the Kernel fitImage to also sign the
> U-Boot fitImage.
> 
> If the variable UBOOT_FITIMAGE_ENABLE = "1", the uboot-sign class will
> copy the SPL files (nodtb image and dtb file) from the u-boot recipe to
> the staging area, so that the Kernel recipe can then create the U-Boot
> fitImage.
> 
> In case SPL_SIGN_ENABLE = "1", the U-Boot fitImage will be signed using
> the key provided by SPL_SIGN_KEYNAME / SPL_SIGN_KEYDIR, or will
> auto-generate keys based on UBOOT_FIT_HASH_ALG, UBOOT_FIT_SIGN_ALG and
> UBOOT_FIT_SIGN_NUMBITS if UBOOT_FIT_GENERATE_KEYS is "1".
> 
> After the operations above, the Kernel recipe will deploy the (signed)
> U-Boot fitImage, the ITS script used to create it, as well as the SPL
> concatenated with the DTB containing the pubkey to the images directory.
> 
> The reason why the U-Boot fitImage is created by the Kernel is in order
> to make sure that, when UBOOT_SIGN_ENABLE is set (and the Kernel
> fitImage is signed), the U-Boot fitImage being created/signed contains
> the pubkey used by the Kernel recipe to sign the Kernel fitImage.
> 
> I added oe-selftest testcases and also tested this on upstream OpenBMC
> with AST2600 BMC devices.
> 
> Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>

I've merged this, I wanted to say a big thanks for writing some test cases
for these code paths. It should start to help a lot in this area in the
future. I'm going to be asking that future fixes in this area add/improve 
test cases to cover issues too.

Cheers,

Richard


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [OE-core] [PATCH v2 0/4] u-boot: Support for SPL verified boot
  2021-04-06 10:57 ` [OE-core] [PATCH v2 0/4] u-boot: Support for SPL verified boot Richard Purdie
@ 2021-04-06 13:21   ` Klaus Heinrich Kiwi
  2021-04-06 13:56     ` Richard Purdie
  0 siblings, 1 reply; 8+ messages in thread
From: Klaus Heinrich Kiwi @ 2021-04-06 13:21 UTC (permalink / raw)
  To: Richard Purdie, openembedded-core; +Cc: andrew, openbmc



On 4/6/2021 7:57 AM, Richard Purdie wrote:
> On Fri, 2021-03-26 at 17:14 -0300, Klaus Heinrich Kiwi wrote:
>> This patch series aims at extending U-Boot's verified boot support to
>> also include SPL.

>> Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
> 
> I've merged this, I wanted to say a big thanks for writing some test cases
> for these code paths. It should start to help a lot in this area in the
> future. I'm going to be asking that future fixes in this area add/improve
> test cases to cover issues too.
> 


Thanks Richard.

FYI, there's a patch I sent recently with relatively important fixes (for some
corner cases) that should apply on top of the patches above:

Subject: [PATCH] uboot: Fixes SPL verified boot on corner cases
Date: Mar 31, 2021

I'd recommend applying that patch as well, before yocto / other projects start
pulling from oe-core.

Thanks,

  -Klaus

-- 
Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [OE-core] [PATCH v2 0/4] u-boot: Support for SPL verified boot
  2021-04-06 13:21   ` Klaus Heinrich Kiwi
@ 2021-04-06 13:56     ` Richard Purdie
  0 siblings, 0 replies; 8+ messages in thread
From: Richard Purdie @ 2021-04-06 13:56 UTC (permalink / raw)
  To: Klaus Heinrich Kiwi, openembedded-core; +Cc: andrew, openbmc

On Tue, 2021-04-06 at 10:21 -0300, Klaus Heinrich Kiwi wrote:
> 
> On 4/6/2021 7:57 AM, Richard Purdie wrote:
> > On Fri, 2021-03-26 at 17:14 -0300, Klaus Heinrich Kiwi wrote:
> > > This patch series aims at extending U-Boot's verified boot support to
> > > also include SPL.
> 
> > > Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
> > 
> > I've merged this, I wanted to say a big thanks for writing some test cases
> > for these code paths. It should start to help a lot in this area in the
> > future. I'm going to be asking that future fixes in this area add/improve
> > test cases to cover issues too.
> > 
> 
> 
> Thanks Richard.
> 
> FYI, there's a patch I sent recently with relatively important fixes (for some
> corner cases) that should apply on top of the patches above:
> 
> Subject: [PATCH] uboot: Fixes SPL verified boot on corner cases
> Date: Mar 31, 2021
> 
> I'd recommend applying that patch as well, before yocto / other projects start
> pulling from oe-core.

Thanks, it didn't apply 100% cleanly which is why I'd deferred it but I've got
to apply and am testing...

Cheers,

Richard


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-04-06 13:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-26 20:14 [PATCH v2 0/4] u-boot: Support for SPL verified boot Klaus Heinrich Kiwi
2021-03-26 20:14 ` [PATCH v2 1/4] u-boot: Move definitions to common locations Klaus Heinrich Kiwi
2021-03-26 20:14 ` [PATCH v2 2/4] u-boot: Add infrastructure to SPL verified boot Klaus Heinrich Kiwi
2021-03-26 20:14 ` [PATCH v2 3/4] u-boot: Use a different Key for SPL signing Klaus Heinrich Kiwi
2021-03-26 20:14 ` [PATCH v2 4/4] oe-selftest: Add U-Boot fitImage signing testcases Klaus Heinrich Kiwi
2021-04-06 10:57 ` [OE-core] [PATCH v2 0/4] u-boot: Support for SPL verified boot Richard Purdie
2021-04-06 13:21   ` Klaus Heinrich Kiwi
2021-04-06 13:56     ` Richard Purdie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).