new file mode 100644
@@ -0,0 +1,17 @@
+#
+# CIP Core, generic profile
+#
+# Copyright (c) Siemens AG, 2020
+#
+# Authors:
+# Quirin Gylstorff <quirin.gylstorff@siemens.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+header:
+ version: 8
+
+local_conf_header:
+ initramfs: |
+ IMAGE_INSTALL += "initramfs-abrootfs-secureboot"
@@ -10,7 +10,7 @@
#
inherit image
-
+inherit image_uuid
ISAR_RELEASE_CMD = "git -C ${LAYERDIR_cip-core} describe --tags --dirty --always --match 'v[0-9].[0-9]*'"
DESCRIPTION = "CIP Core image"
@@ -11,12 +11,12 @@
software =
{
version = "0.2";
- name = "ebsy secure boot update"
+ name = "secure boot update"
images: ({
- filename = "${EXTRACTED_PARTITION_NAME}";
+ filename = "${ROOTFS_PARTITION_NAME}";
device = "fedcba98-7654-3210-cafe-5e0710000001,fedcba98-7654-3210-cafe-5e0710000002";
type = "roundrobin";
- compressed = true;
+ compressed = "true";
filesystem = "ext4";
});
files: ({
new file mode 100644
@@ -0,0 +1,51 @@
+#
+# CIP Core, generic profile
+#
+# Copyright (c) Siemens AG, 2020
+#
+# Authors:
+# Quirin Gylstorff <quirin.gylstorff@siemens.com>
+#
+# SPDX-License-Identifier: MIT
+#
+
+inherit dpkg-raw
+
+DESCRIPTION = "Add user defined secureboot certifcates to the buildchroot and the script to \
+ sign an image with the given keys"
+
+# variables
+SB_CERT_PATH = "/usr/share/ebg-secure-boot"
+SB_CERTDB ??= ""
+SB_VERIFY_CERT ??= ""
+SB_KEY_NAME ??= "demoDB"
+
+# used to sign the image
+DEBIAN_DEPENDS = "pesign, sbsigntool"
+
+# this package cannot be install together with:
+DEBIAN_CONFLICTS = "ebg-secure-boot-snakeoil"
+
+SRC_URI = " \
+ file://sign_secure_image.sh.tmpl \
+ file://control.tmpl"
+SRC_URI_append = " ${@ d.getVar(SB_CERTDB) or "" }"
+SRC_URI_append = " ${@ d.getVar(SB_VERIFY_CERT) or "" }"
+TEMPLATE_FILES = "sign_secure_image.sh.tmpl"
+TEMPLATE_VARS += "SB_CERT_PATH SB_CERTDB SB_VERIFY_CERT SB_KEY_NAME"
+
+TEMPLATE_FILES += "control.tmpl"
+TEMPLATE_VARS += "PN MAINTAINER DPKG_ARCH DEBIAN_DEPENDS DESCRIPTION DEBIAN_CONFLICTS"
+
+do_install() {
+ TARGET=${D}${SB_CERT_PATH}
+ install -m 0700 -d ${TARGET}
+ cp -a ${WORKDIR}/${SB_CERTDB} ${TARGET}/${SB_CERTDB}
+ chmod 700 ${TARGET}/${SB_CERTDB}
+ install -m 0600 ${WORKDIR}/${SB_VERIFY_CERT} ${TARGET}/${SB_VERIFY_CERT}
+ TARGET=${D}/usr/bin
+ install -d ${TARGET}
+ install -m 755 ${WORKDIR}/sign_secure_image.sh ${TARGET}/sign_secure_image.sh
+}
+
+addtask do_install after do_transform_template
new file mode 100644
@@ -0,0 +1 @@
+For a secure boot image this directory needs to contain the certdb directory and the db.crt file.
new file mode 100644
@@ -0,0 +1,12 @@
+Source: ${PN}
+Section: misc
+Priority: optional
+Standards-Version: 3.9.6
+Maintainer: ${MAINTAINER}
+Build-Depends: debhelper (>= 9)
+
+Package: ${PN}
+Architecture: ${DPKG_ARCH}
+Depends: ${DEBIAN_DEPENDS}
+Description: ${DESCRIPTION}
+Conflicts: ${DEBIAN_CONFLICTS}
new file mode 100644
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -e
+set -x
+signee=$1
+signed=$2
+
+usage(){
+ echo "sign with debian snakeoil"
+ echo "$0 signee signed"
+ echo "signee: path to the image to be signed"
+ echo "signed: path to store the signed image"
+}
+
+
+if [ -z "$signee" ] || [ -z "$signed" ]; then
+ usage
+ exit 1
+fi
+
+pesign --force --verbose --padding -n ${SB_CERT_PATH}/${SB_CERTDB} -c "${SB_KEY_NAME}" -s -i $signee -o $signed
+sbverify --cert ${SB_CERT_PATH}/${SB_VERIFY_CERT} $signed
+exit 0
deleted file mode 100644
@@ -1,31 +0,0 @@
-#!/bin/sh
-if [ -d /usr/share/secureboot ]; then
- patch -s -p0 /usr/share/initramfs-tools/scripts/local /usr/share/secureboot/secure-boot-debian-local.patch
-fi
-
-INITRAMFS_CONF=/etc/initramfs-tools/initramfs.conf
-if [ -f ${INITRAMFS_CONF} ]; then
- sed -i -E 's/(^MODULES=).*/\1${INITRAMFS_MODULES}/' ${INITRAMFS_CONF}
- sed -i -E 's/(^BUSYBOX=).*/\1${INITRAMFS_BUSYBOX}/' ${INITRAMFS_CONF}
- sed -i -E 's/(^COMPRESS=).*/\1${INITRAMFS_COMPRESS}/' ${INITRAMFS_CONF}
- sed -i -E 's/(^KEYMAP=).*/\1${INITRAMFS_KEYMAP}/' ${INITRAMFS_CONF}
- sed -i -E 's/(^DEVICE=).*/\1${INITRAMFS_NET_DEVICE}/' ${INITRAMFS_CONF}
- sed -i -E 's/(^NFSROOT=).*/\1${INITRAMFS_NFSROOT}/' ${INITRAMFS_CONF}
- sed -i -E 's/(^RUNSIZE=).*/\1${INITRAMFS_RUNSIZE}/' ${INITRAMFS_CONF}
- if grep -Fxq "ROOT=" "${INITRAMFS_CONF}"; then
- sed -i -E 's/(^ROOT=).*/\1${INITRAMFS_ROOT}/' ${INITRAMFS_CONF}
- else
- sed -i -E "\$aROOT=${INITRAMFS_ROOT}" ${INITRAMFS_CONF}
- fi
-fi
-
-MODULES_LIST_FILE=/etc/initramfs-tools/modules
-if [ -f ${MODULES_LIST_FILE} ]; then
- for modname in ${INITRAMFS_MODULE_LIST}; do
- if ! grep -Fxq "$modname" "${MODULES_LIST_FILE}"; then
- echo "$modname" >> "${MODULES_LIST_FILE}"
- fi
- done
-fi
-
-update-initramfs -v -u
new file mode 100755
@@ -0,0 +1,16 @@
+#!/bin/sh
+name=${SB_NAME:-snakeoil}
+keydir=${SB_KEYDIR:-./keys}
+if [ ! -d ${keydir} ]; then
+ mkdir -p ${keydir}
+fi
+inkey=${INKEY:-/usr/share/ovmf/PkKek-1-snakeoil.key}
+incert=${INCERT:-/usr/share/ovmf/PkKek-1-snakeoil.pem}
+nick_name=${IN_NICK:-snakeoil}
+TMP=$(mktemp -d)
+mkdir -p ${keydir}/${name}certdb
+certutil -N --empty-password -d ${keydir}/${name}certdb
+openssl pkcs12 -export -out ${TMP}/foo_key.p12 -inkey $inkey -in $incert -name $nick_name
+pk12util -i ${TMP}/foo_key.p12 -d ${keydir}/${name}certdb
+cp $incert ${keydir}/$(basename $incert)
+rm -rf $TMP
new file mode 100755
@@ -0,0 +1,51 @@
+#!/bin/sh
+name=${SB_NAME:-demo}
+keydir=${SB_KEYDIR:-./keys}
+if [ ! -d ${keydir} ]; then
+ mkdir -p ${keydir}
+fi
+openssl req -new -x509 -newkey rsa:4096 -subj "/CN=${name}PK/" -outform PEM \
+ -keyout ${keydir}/${name}PK.key -out ${keydir}/${name}PK.crt -days 3650 -nodes -sha256
+openssl req -new -x509 -newkey rsa:4096 -subj "/CN=${name}KEK/" -outform PEM \
+ -keyout ${keydir}/${name}KEK.key -out ${keydir}/${name}KEK.crt -days 3650 -nodes -sha256
+openssl req -new -x509 -newkey rsa:4096 -subj "/CN=${name}DB/" -outform PEM \
+ -keyout ${keydir}/${name}DB.key -out ${keydir}/${name}DB.crt -days 3650 -nodes -sha256
+openssl x509 -in ${keydir}/${name}PK.crt -out ${keydir}/${name}PK.cer -outform DER
+openssl x509 -in ${keydir}/${name}KEK.crt -out ${keydir}/${name}KEK.cer -outform DER
+openssl x509 -in ${keydir}/${name}DB.crt -out ${keydir}/${name}DB.cer -outform DER
+
+openssl pkcs12 -export -out ${keydir}/${name}DB.p12 \
+ -in ${keydir}/${name}DB.crt -inkey ${keydir}/${name}DB.key -passout pass:
+
+GUID=$(uuidgen --random)
+echo $GUID > ${keydir}/${name}GUID
+
+cert-to-efi-sig-list -g $GUID ${keydir}/${name}PK.crt ${keydir}/${name}PK.esl
+cert-to-efi-sig-list -g $GUID ${keydir}/${name}KEK.crt ${keydir}/${name}KEK.esl
+cert-to-efi-sig-list -g $GUID ${keydir}/${name}DB.crt ${keydir}/${name}DB.esl
+rm -f ${keydir}/${name}noPK.esl
+touch ${keydir}/${name}noPK.esl
+
+sign-efi-sig-list -g $GUID \
+ -k ${keydir}/${name}PK.key -c ${keydir}/${name}PK.crt \
+ PK ${keydir}/${name}PK.esl ${keydir}/${name}PK.auth
+sign-efi-sig-list -g $GUID \
+ -k ${keydir}/${name}PK.key -c ${keydir}/${name}PK.crt \
+ PK ${keydir}/${name}noPK.esl ${keydir}/${name}noPK.auth
+sign-efi-sig-list -g $GUID \
+ -k ${keydir}/${name}PK.key -c ${keydir}/${name}PK.crt \
+ KEK ${keydir}/${name}KEK.esl ${keydir}/${name}KEK.auth
+sign-efi-sig-list -g $GUID \
+ -k ${keydir}/${name}PK.key -c ${keydir}/${name}PK.crt \
+ DB ${keydir}/${name}DB.esl ${keydir}/${name}DB.auth
+
+chmod 0600 ${keydir}/${name}*.key
+mkdir -p ${keydir}/${name}certdb
+certutil -N --empty-password -d ${keydir}/${name}certdb
+
+certutil -A -n 'PK' -d ${keydir}/${name}certdb -t CT,CT,CT -i ${keydir}/${name}PK.crt
+pk12util -W "" -d ${keydir}/${name}certdb -i ${keydir}/${name}DB.p12
+certutil -d ${keydir}/${name}certdb -A -i ${keydir}/${name}DB.crt -n "" -t u
+
+certutil -d ${keydir}/${name}certdb -K
+certutil -d ${keydir}/${name}certdb -L
@@ -80,17 +80,29 @@ class EfibootguardBootPlugin(SourcePlugin):
boot_files = source_params.get("files", "").split(' ')
+ uefi_kernel = source_params.get("unified-kernel")
cmdline = bootloader.append
- root_dev = source_params.get("root", None)
- if not root_dev:
- msger.error("Specify root in source params")
- exit(1)
+ if uefi_kernel:
+ boot_image = cls._create_unified_kernel_image(rootfs_dir,
+ cr_workdir,
+ cmdline,
+ uefi_kernel,
+ deploy_dir,
+ kernel_image,
+ initrd_image,
+ source_params)
+ boot_files.append(boot_image)
+ else:
+ root_dev = source_params.get("root", None)
+ if not root_dev:
+ msger.error("Specify root in source params")
+ exit(1)
root_dev = root_dev.replace(":", "=")
- cmdline += " root=%s rw" % root_dev
- boot_files.append(kernel_image)
- boot_files.append(initrd_image)
- cmdline += "initrd=%s" % initrd_image if initrd_image else ""
+ cmdline += " root=%s rw" % root_dev
+ boot_files.append(kernel_image)
+ boot_files.append(initrd_image)
+ cmdline += "initrd=%s" % initrd_image if initrd_image else ""
part_rootfs_dir = "%s/disk/%s.%s" % (cr_workdir,
part.label, part.lineno)
@@ -160,3 +172,62 @@ class EfibootguardBootPlugin(SourcePlugin):
part.size = bootimg_size
part.source_file = bootimg
+
+ @classmethod
+ def _create_unified_kernel_image(cls, rootfs_dir, cr_workdir, cmdline,
+ uefi_kernel, deploy_dir, kernel_image,
+ initrd_image, source_params):
+ rootfs_path = rootfs_dir.get('ROOTFS_DIR')
+ os_release_file = "{root}/etc/os-release".format(root=rootfs_path)
+ efistub = "{rootfs_path}/usr/lib/systemd/boot/efi/linuxx64.efi.stub"\
+ .format(rootfs_path=rootfs_path)
+ msger.debug("osrelease path: %s", os_release_file)
+ kernel_cmdline_file = "{cr_workdir}/kernel-command-line-file.txt"\
+ .format(cr_workdir=cr_workdir)
+ with open(kernel_cmdline_file, "w") as cmd_fd:
+ cmd_fd.write(cmdline)
+ uefi_kernel_name = "linux.efi"
+ uefi_kernel_file = "{deploy_dir}/{uefi_kernel_name}"\
+ .format(deploy_dir=deploy_dir, uefi_kernel_name=uefi_kernel_name)
+ kernel = "{deploy_dir}/{kernel_image}"\
+ .format(deploy_dir=deploy_dir, kernel_image=kernel_image)
+ initrd = "{deploy_dir}/{initrd_image}"\
+ .format(deploy_dir=deploy_dir, initrd_image=initrd_image)
+ objcopy_cmd = 'objcopy \
+ --add-section .osrel={os_release_file} \
+ --change-section-vma .osrel=0x20000 \
+ --add-section .cmdline={kernel_cmdline_file} \
+ --change-section-vma .cmdline=0x30000 \
+ --add-section .linux={kernel} \
+ --change-section-vma .linux=0x2000000 \
+ --add-section .initrd={initrd} \
+ --change-section-vma .initrd=0x3000000 \
+ {efistub} {uefi_kernel_file}'.format(
+ os_release_file=os_release_file,
+ kernel_cmdline_file=kernel_cmdline_file,
+ kernel=kernel,
+ initrd=initrd,
+ efistub=efistub,
+ uefi_kernel_file=uefi_kernel_file)
+ exec_cmd(objcopy_cmd)
+
+ return cls._sign_file(name=uefi_kernel_name,
+ signee=uefi_kernel_file,
+ deploy_dir=deploy_dir,
+ source_params=source_params)
+
+ @classmethod
+ def _sign_file(cls, name, signee, deploy_dir, source_params):
+ sign_script = source_params.get("signwith")
+ if sign_script and os.path.exists(sign_script):
+ msger.info("sign with script %s", sign_script)
+ name = name.replace(".efi", ".signed.efi")
+ sign_cmd = "{sign_script} {signee} {deploy_dir}/{name}"\
+ .format(sign_script=sign_script, signee=signee,
+ deploy_dir=deploy_dir, name=name)
+ exec_cmd(sign_cmd)
+ elif sign_script and not os.path.exists(sign_script):
+ msger.error("Could not find script %s", sign_script)
+ exit(1)
+
+ return name
@@ -64,10 +64,17 @@ class EfibootguardEFIPlugin(SourcePlugin):
exec_cmd(create_dir_cmd)
for bootloader in bootloader_files:
- cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (deploy_dir,
- bootloader,
- part_rootfs_dir,
- bootloader)
+ signed_bootloader = cls._sign_file(bootloader,
+ "{}/{}".format(deploy_dir,
+ bootloader
+ ),
+ cr_workdir,
+ source_params)
+ # important the bootloader in deploy_dir is no longer signed
+ cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (cr_workdir,
+ signed_bootloader,
+ part_rootfs_dir,
+ bootloader)
exec_cmd(cp_cmd, True)
du_cmd = "du --apparent-size -ks %s" % part_rootfs_dir
blocks = int(exec_cmd(du_cmd).split()[0])
@@ -100,3 +107,28 @@ class EfibootguardEFIPlugin(SourcePlugin):
part.size = efi_part_image_size
part.source_file = efi_part_image
+
+
+ @classmethod
+ def _sign_file(cls, name, signee, cr_workdir, source_params):
+ sign_script = source_params.get("signwith")
+ if sign_script and os.path.exists(sign_script):
+ work_name = name.replace(".efi", ".signed.efi")
+ sign_cmd = "{sign_script} {signee} \
+ {cr_workdir}/{work_name}".format(sign_script=sign_script,
+ signee=signee,
+ cr_workdir=cr_workdir,
+ work_name=work_name)
+ exec_cmd(sign_cmd)
+ elif sign_script and not os.path.exists(sign_script):
+ msger.error("Could not find script %s", sign_script)
+ exit(1)
+ else:
+ # if we do nothing copy the signee to the work directory
+ work_name = name
+ cp_cmd = "cp {signee} {cr_workdir}/{work_name}".format(
+ signee=signee,
+ cr_workdir=cr_workdir,
+ work_name=work_name)
+ exec_cmd(cp_cmd)
+ return work_name
new file mode 100755
@@ -0,0 +1,12 @@
+#!/bin/sh
+ovmf_code=${OVMF_CODE:-/usr/share/OVMF/OVMF_CODE.secboot.fd}
+ovmf_vars=${OVMF_VARS:-./OVMF_VARS.fd}
+DISK=$1
+qemu-system-x86_64 -enable-kvm -M q35 \
+ -cpu host,hv_relaxed,hv_vapic,hv-spinlocks=0xfff -smp 2 -m 2G -no-hpet \
+ -global ICH9-LPC.disable_s3=1 \
+ -global isa-fdc.driveA= \
+ -boot menu=on \
+ -drive if=pflash,format=raw,unit=0,readonly=on,file=${ovmf_code} \
+ -drive if=pflash,format=raw,file=${ovmf_vars} \
+ -drive file=fat:rw:$DISK
@@ -15,6 +15,8 @@ usage()
echo "Usage: $0 ARCHITECTURE [QEMU_OPTIONS]"
echo -e "\nSet QEMU_PATH environment variable to use a locally " \
"built QEMU version"
+ echo -e "\nSet SECURE_BOOT environment variable to boot a secure boot environment " \
+ "This environment also needs the variables OVMF_VARS and OVMF_CODE set"
exit 1
}
@@ -22,17 +24,25 @@ if [ -n "${QEMU_PATH}" ]; then
QEMU_PATH="${QEMU_PATH}/"
fi
+if [ -z "${DISTRO_RELEASE}" ]; then
+ DISTRO_RELEASE="buster"
+fi
+if [ -z "${TARGET_IMAGE}" ];then
+ TARGET_IMAGE="cip-core-image"
+fi
+
case "$1" in
x86|x86_64|amd64)
DISTRO_ARCH=amd64
QEMU=qemu-system-x86_64
QEMU_EXTRA_ARGS=" \
- -cpu host -smp 4 \
- -enable-kvm -machine q35 \
+ -cpu qemu64 \
+ -smp 4 \
+ -machine q35,accel=kvm:tcg \
-device ide-hd,drive=disk \
-device virtio-net-pci,netdev=net"
KERNEL_CMDLINE=" \
- root=/dev/sda vga=0x305 console=ttyS0"
+ root=/dev/sda vga=0x305"
;;
arm64|aarch64)
DISTRO_ARCH=arm64
@@ -71,21 +81,41 @@ case "$1" in
;;
esac
-if [ -z "${DISTRO_RELEASE}" ]; then
- DISTRO_RELEASE="buster"
-fi
-
-IMAGE_PREFIX="$(dirname $0)/build/tmp/deploy/images/qemu-${DISTRO_ARCH}/cip-core-image-cip-core-${DISTRO_RELEASE}-qemu-${DISTRO_ARCH}"
-IMAGE_FILE=$(ls ${IMAGE_PREFIX}.ext4.img)
+IMAGE_PREFIX="$(dirname $0)/build/tmp/deploy/images/qemu-${DISTRO_ARCH}/${TARGET_IMAGE}-cip-core-${DISTRO_RELEASE}-qemu-${DISTRO_ARCH}"
if [ -z "${DISPLAY}" ]; then
QEMU_EXTRA_ARGS="${QEMU_EXTRA_ARGS} -nographic"
+ case "$1" in
+ x86|x86_64|amd64)
+ KERNEL_CMDLINE="${KERNEL_CMDLINE} console=ttyS0"
+ esac
+fi
+
+
+
+if [ -n "SECURE_BOOT" ]; then
+ ovmf_code=${OVMF_CODE:-/usr/share/OVMF/OVMF_CODE.secboot.fd}
+ ovmf_vars=${OVMF_VARS:-./OVMF_VARS.fd}
+ QEMU_EXTRA_ARGS=" \
+ ${QEMU_EXTRA_ARGS} \
+ -global ICH9-LPC.disable_s3=1 \
+ -global isa-fdc.driveA= \
+ "
+ BOOT_FILES="-drive if=pflash,format=raw,unit=0,readonly=on,file=${ovmf_code} \
+ -drive if=pflash,format=raw,file=${ovmf_vars} \
+ -drive file=${IMAGE_PREFIX}.wic.img,discard=unmap,if=none,id=disk,format=raw"
+else
+ IMAGE_FILE=$(ls ${IMAGE_PREFIX}.ext4.img)
+
+ KERNEL_FILE=$(ls ${IMAGE_PREFIX}-vmlinuz* | tail -1)
+ INITRD_FILE=$(ls ${IMAGE_PREFIX}-initrd.img* | tail -1)
+
+ BOOT_FILES=-kernel ${KERNEL_FILE} -append "${KERNEL_CMDLINE}" \
+ -initrd ${INITRD_FILE}
fi
shift 1
${QEMU_PATH}${QEMU} \
- -drive file=${IMAGE_FILE},discard=unmap,if=none,id=disk,format=raw \
-m 1G -serial mon:stdio -netdev user,id=net \
- -kernel ${IMAGE_PREFIX}-vmlinuz -append "${KERNEL_CMDLINE}" \
- -initrd ${IMAGE_PREFIX}-initrd.img ${QEMU_EXTRA_ARGS} "$@"
+ ${BOOT_FILES} ${QEMU_EXTRA_ARGS} "$@"
new file mode 100644
@@ -0,0 +1,2 @@
+# EFI partition containing efibootguard bootloader binary
+part --source efibootguard-efi --ondisk sda --size 16M --extra-space 0 --overhead-factor 1 --label efi --align 1024 --part-type=EF00 --active --sourceparams "signwith=/usr/bin/sign_secure_image.sh"
@@ -1,5 +1,9 @@
# short-description: Qemu-amd64 with Efibootguard and SWUpdate
# long-description: Disk image for qemu-amd64 with EFI Boot Guard and SWUpdate
+include ebg-signed-bootloader.inc
+
+# EFI Boot Guard environment/config partitions plus Kernel files
+part --source efibootguard-boot --ondisk sda --size 32M --extra-space 0 --overhead-factor 1 --label BOOT0 --align 1024 --part-type=0700 --sourceparams "revision=2,unified-kernel=y,signwith=/usr/bin/sign_secure_image.sh"
+part --source efibootguard-boot --ondisk sda --size 32M --extra-space 0 --overhead-factor 1 --label BOOT1 --align 1024 --part-type=0700 --sourceparams "revision=1,unified-kernel=y,signwith=/usr/bin/sign_secure_image.sh"
-include ebg-sysparts.inc
include swupdate-partition.inc