[oe-core][RFC 2/3] u-boot: Add infrastructure to SPL verified boot
Klaus Heinrich Kiwi
klaus at linux.vnet.ibm.com
Sat Mar 6 22:28:21 AEDT 2021
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 at linux.vnet.ibm.com>
---
meta/classes/kernel-fitimage.bbclass | 7 +
meta/classes/uboot-sign.bbclass | 306 +++++++++++++++++++++++++--
2 files changed, 296 insertions(+), 17 deletions(-)
diff --git a/meta/classes/kernel-fitimage.bbclass b/meta/classes/kernel-fitimage.bbclass
index 76e2e6c136..3b72d5495a 100644
--- a/meta/classes/kernel-fitimage.bbclass
+++ b/meta/classes/kernel-fitimage.bbclass
@@ -694,6 +694,13 @@ kernel_do_deploy_append() {
# ${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/"
+ if [ "${SPL_SIGN_ENABLE}" = "1" -a -n "${UBOOT_BINARY}" -a -n "${SPL_DTB_BINARY}" ] ; then
+ # If we're also signing the uboot fit, now we need to
+ # deploy it, 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/u-boot-fitImage-${MACHINE}.${UBOOT_SUFFIX}"
+ fi
fi
fi
}
diff --git a/meta/classes/uboot-sign.bbclass b/meta/classes/uboot-sign.bbclass
index d57bef6669..c362cbfd9c 100644
--- a/meta/classes/uboot-sign.bbclass
+++ b/meta/classes/uboot-sign.bbclass
@@ -36,6 +36,7 @@ inherit uboot-config
# Signature activation.
UBOOT_SIGN_ENABLE ?= "0"
+SPL_SIGN_ENABLE ?= "0"
# Default value for deployment filenames.
UBOOT_DTB_IMAGE ?= "u-boot-${MACHINE}-${PV}-${PR}.dtb"
@@ -77,8 +78,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 about to sign the SPL
+python() {
+ if d.getVar('SPL_SIGN_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 +103,64 @@ 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() {
+ # Deploy the U-boot its file, spl dtb and the spl nodtb binary
+
+ if [ -e "${UBOOT_ITS}" ] ; then
+ echo "Copying uboot-fit-image.its source file..."
+ install -m 0644 ${UBOOT_ITS} "${DEPLOYDIR}/${UBOOT_ITS_IMAGE}"
+ ln -sf ${UBOOT_ITS_IMAGE} ${DEPLOYDIR}/${UBOOT_ITS_SYMLINK}
+ ln -sf ${UBOOT_ITS_IMAGE} ${DEPLOYDIR}/${UBOOT_ITS}
+ fi
+
+ if [ -e "${SPL_DIR}/${SPL_DTB_BINARY}" ] ; then
+ # We only deploy u-boot-spl.dtb real file if we are NOT
+ # signing the kernel, otherwise the kernel PN will do
+ # it for us (see kernel-fitimage.bbclass)
+ if [ "${UBOOT_SIGN_ENABLE}" != "1" ] ; then
+ install -m 0644 ${SPL_DIR}/${SPL_DTB_BINARY} \
+ ${DEPLOYDIR}/${SPL_DTB_IMAGE}
+ fi;
+ 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 (with pubkey)
+ deployed_spl_dtb_binary='${DEPLOY_DIR_IMAGE}/${SPL_DTB_IMAGE}'
+ 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 +178,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 +210,230 @@ 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
+}
+
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" -a -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" -a -n "${UBOOT_DTB_BINARY}" ]; then
+ install_helper
+ fi
+ if [ "${SPL_SIGN_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 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_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 = "U-boot FIT";
+ #address-cells = <1>;
+
+ images {
+ uboot {
+ description = "U-Boot image";
+ data = /incbin/("${uboot_nodtb_bin}");
+ type = "standalone";
+ os = "U-Boot";
+ arch = "${UBOOT_ARCH}";
+ compression = "none";
+ load = <${UBOOT_LOADADDRESS}>;
+ entry = <${UBOOT_ENTRYPOINT}>;
+ hash {
+ algo = "${uboot_csum}";
+ };
+ signature {
+ algo = "${uboot_csum},${uboot_sign_algo}";
+ key-name-hint = "${uboot_sign_keyname}";
+ };
+ };
+ fdt {
+ description = "U-Boot FDT";
+ data = /incbin/("${uboot_dtb}");
+ type = "flat_dt";
+ arch = "${UBOOT_ARCH}";
+ compression = "none";
+ hash {
+ algo = "${uboot_csum}";
+ };
+ signature {
+ algo = "${uboot_csum},${uboot_sign_algo}";
+ key-name-hint = "${uboot_sign_keyname}";
+ };
+ };
+ };
+
+ configurations {
+ default = "conf";
+ conf {
+ description = "Boot with signed U-Boot FIT";
+ loadables = "uboot";
+ fdt = "fdt";
+ hash {
+ algo = "${uboot_csum}";
+ };
+ signature {
+ algo = "${uboot_csum},${uboot_sign_algo}";
+ key-name-hint = "${uboot_sign_keyname}";
+ sign-images = "loadables", "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}
+
+ #
+ # 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 "${UBOOT_SIGN_KEYDIR}" \
+ -K "${spl_dtb}" \
+ -r ${uboot_bin} \
+ ${UBOOT_MKIMAGE_SIGN_ARGS}
+
+}
+
+do_uboot_assemble_fitimage() {
+ # This function runs in both UBOOT_PN as well as KERNEL_PN contexts. The reason
+ # for that is that we need to be able to support SPL verified boot standalone,
+ # as well as in the scenario where U-boot verified boot is enabled. On the latter
+ # case, we can only sign our U-BOOT fit after the KERNEL_PN signed the fitimage,
+ # as well as placed the pubkey in the U-boot DTB. Note that the Signed U-boot
+ # FIT and SPL with the pubkey will only be available in the deploy dir, not on
+ # the u-boot package
+ if [ "${SPL_SIGN_ENABLE}" = "1" -a -n "${SPL_DTB_BINARY}" ] ; then
+ if [ "${PN}" = "${UBOOT_PN}" ] ; then
+ if [ -n "${UBOOT_CONFIG}" ]; then
+ for config in ${UBOOT_MACHINE}; do
+ cd ${B}/${config}
+ uboot_fitimage_assemble ${UBOOT_ITS} ${UBOOT_NODTB_BINARY} ${UBOOT_DTB_BINARY} u-boot-fitImage ${SPL_DIR}/${SPL_DTB_BINARY}
+ done
+ else
+ cd ${B}
+ uboot_fitimage_assemble ${UBOOT_ITS} ${UBOOT_NODTB_BINARY} ${UBOOT_DTB_BINARY} u-boot-fitImage ${SPL_DIR}/${SPL_DTB_BINARY}
+ fi
+ elif [ "${UBOOT_SIGN_ENABLE}" = "1" -a "${PN}" = "${KERNEL_PN}" ] ; then
+ # 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
+ # As for the u-boot.dtb (with fitimage's pubkey), it should come from the dependent
+ # do_assemble_fitimage task
+ cp -P ${STAGING_DATADIR}/${@os.path.splitext(d.getVar("SPL_DTB_BINARY"))[0]}*.dtb ${B}
+ cp -P ${STAGING_DATADIR}/u-boot-nodtb*.${UBOOT_SUFFIX} ${B}
+ cd ${B}
+ uboot_fitimage_assemble ${UBOOT_ITS} ${UBOOT_NODTB_BINARY} ${UBOOT_DTB_BINARY} u-boot-fitImage ${SPL_DTB_BINARY}
fi
fi
}
+addtask uboot_assemble_fitimage before do_install after do_compile
+
+python () {
+ if d.getVar('UBOOT_SIGN_ENABLE') == '1' and d.getVar('PN') == d.getVar('KERNEL_PN'):
+ d.appendVarFlag('do_uboot_assemble_fitimage', 'depends', ' %s:do_assemble_fitimage' % d.getVar('KERNEL_PN'))
+}
+
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
+}
+
+do_deploy_append_pn-${UBOOT_PN}() {
+ if [ "${SPL_SIGN_ENABLE}" = "1" -a "${UBOOT_SIGN_ENABLE}" != "1" ] ; then
+ # Only deploy u-boot-fitimage if the KERNEL_PN is not already doing so
+ install -m 0644 ${B}/u-boot-fitImage "${DEPLOYDIR}/u-boot-fitImage-${MACHINE}.${UBOOT_SUFFIX}"
+ 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')
# Make "bitbake u-boot -cdeploy" deploys the signed u-boot.dtb
- d.appendVarFlag('do_deploy', 'depends', ' %s:do_deploy' % kernel_pn)
+ d.appendVarFlag('do_deploy', 'depends', ' %s:do_deploy' % d.getVar('KERNEL_PN'))
}
--
2.25.1
More information about the openbmc
mailing list