Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions bin/build_heads_fwupd_capsule.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-3.0-or-later

set -euo pipefail

rom=""
guid=""
board=""
generation=""
version=""
output=""
local_user=""

usage() {
cat <<EOF
Usage: $0 --rom FILE --guid GUID --board BOARD --generation N --version VERSION
--output FILE [--local-user GPG_KEY]
EOF
}

while (($#)); do
case "$1" in
--rom)
rom=$2
shift 2
;;
--guid)
guid=$2
shift 2
;;
--board)
board=$2
shift 2
;;
--generation)
generation=$2
shift 2
;;
--version)
version=$2
shift 2
;;
--output)
output=$2
shift 2
;;
--local-user)
local_user=$2
shift 2
;;
-h | --help)
usage
exit 0
;;
*)
usage >&2
exit 2
;;
esac
done

[ -s "$rom" ] || { echo "ROM is missing or empty" >&2; exit 1; }
[[ $guid =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]] || {
echo "GUID must be a lowercase canonical GUID" >&2
exit 1
}
[[ $board =~ ^[A-Za-z0-9_-]+$ ]] || { echo "Board name is invalid" >&2; exit 1; }
[[ $generation =~ ^[0-9]+$ ]] || { echo "Generation must be an integer" >&2; exit 1; }
[ -n "$version" ] || { echo "Version is required" >&2; exit 1; }
[ -n "$output" ] || { echo "Output path is required" >&2; exit 1; }

tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/heads-fwupd-capsule.XXXXXX")
trap 'rm -rf "$tmpdir"' EXIT

cp "$rom" "$tmpdir/firmware.rom"
rom_size=$(wc -c <"$tmpdir/firmware.rom" | tr -d ' ')
rom_sha256=$(sha256sum "$tmpdir/firmware.rom" | awk '{print $1}')
cat >"$tmpdir/manifest" <<EOF
format=1
guid=$guid
board=$board
generation=$generation
version=$version
size=$rom_size
sha256=$rom_sha256
EOF

gpg_args=(--batch --yes --armor --detach-sign --output "$tmpdir/manifest.asc")
if [ -n "$local_user" ]; then
gpg_args+=(--local-user "$local_user")
fi
gpg "${gpg_args[@]}" "$tmpdir/manifest"

tar -C "$tmpdir" -cf "$tmpdir/payload.tar" firmware.rom manifest manifest.asc
payload_size=$(wc -c <"$tmpdir/payload.tar" | tr -d ' ')
image_size=$((28 + payload_size))

guid_to_efi_hex() {
local compact=${1//-/}
printf '%s%s%s%s' \
"${compact:6:2}${compact:4:2}${compact:2:2}${compact:0:2}" \
"${compact:10:2}${compact:8:2}" \
"${compact:14:2}${compact:12:2}" \
"${compact:16}"
}

le32() {
local hex
printf -v hex '%08x' "$1"
printf '%s' "${hex:6:2}${hex:4:2}${hex:2:2}${hex:0:2}"
}

{
printf '%s' "$(guid_to_efi_hex "$guid")$(le32 28)$(le32 0)$(le32 "$image_size")" | xxd -r -p
cat "$tmpdir/payload.tar"
} >"$output"

echo "$output"
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-3.0-or-later

set -e

# shellcheck source=/dev/null
. /etc/functions.sh

[ -s "$1" ] || DIE "QEMU firmware update payload is empty"
sha256sum "$1" >/tmp/heads-fwupd-qemu-applied.sha256
STATUS_OK "QEMU file-backed firmware writer accepted the update"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBGqPAxUBCAC4yy0MKn5SaIxvQn93tnul4DU6ZX3hL2tXWWjwxv9dPxK3ll5Y
z7p2lnGeMQChS1CttI2tHP2aKrlOdirrU/seZMTZftNu5LBQciIK6bYe0Iuydz2Z
6xpawcrCpuiAw0QARIErn2uB2CGMjHRY7aPb+k7L58kGxzMr/5eGx9cP06xrgOY9
tL9RCrKZVi7F//ydPl8lTshCIBlxFxn2wCrwCDy8djJE7w3zOBkobPd5VdMwCznq
mMsbFGJXZloHR3p7JRjOCytEFmJO0D2lnlKAjM7yVdn4T942gm+IPCvFepYx3UT+
IXNR0EjEST8uQiG16ZdK7LN/XG55yXpd72wBABEBAAG0O1N0YXIgTGFicyBIZWFk
cyBRRU1VIHRlc3Qga2V5IDxoZWFkcy1xZW11QHN0YXJsYWJzLnN5c3RlbXM+iQFO
BBMBCgA4FiEE4GKn3RF6gBzu/bQ1pcgDVTX2or0FAmqPAxUCGwMFCwkIBwIGFQoJ
CAsCBBYCAwECHgECF4AACgkQpcgDVTX2or2CEAf8CiWJ2AmjrxTYLqavrHuGkVig
9vunbmhqA03lw0rkSI/0DVn/SNq64AntD9EheOwPfSuAtTfX9jdNI5QgntKr+IBp
qrJzxqPITjPLYLkWi9rNEF792DfOem93YpGjWfwEWZu5jAptkwzevsTJIXYGtPv5
D4I0UpMaO2L5uXs08zkmTSCSZgfSgdUNRztuULymsFARvQrge8lTEuiZqNzXEW+d
2o+x1+vIDCq9bDu59ZrxRDEXdTfRdZ6Uyg6OTf77aeZMFAVBbPypyCEmpJrYkh9p
w0Vh5B27hqSJ9jYbi6DPwVuGD+wyRDuDCPC3rX5hIAnYS2dKzdl4CoaOCG7K4w==
=hi7E
-----END PGP PUBLIC KEY BLOCK-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# QEMU fixture for exercising the fwupd capsule handoff without writing flash.
include $(pwd)/boards/qemu-coreboot-fbwhiptail-tpm2/qemu-coreboot-fbwhiptail-tpm2.config

export CONFIG_BOARD_NAME=qemu-coreboot-fbwhiptail-tpm2-fwupd
export CONFIG_HEADS_FWUPD=y
export CONFIG_HEADS_FWUPD_CAPSULE_GUID=0617fcc9-0266-5650-964b-8d8deb52d992
export CONFIG_HEADS_FWUPD_GENERATION=0
export CONFIG_HEADS_FWUPD_MAX_CAPSULE_SIZE=20971520
export CONFIG_HEADS_FWUPD_MAX_ROM_SIZE=16777216
export CONFIG_HEADS_FWUPD_VENDOR_KEYRING=/etc/heads-fwupd-qemu-test-key.asc
export CONFIG_HEADS_FWUPD_WRITER=/bin/heads-fwupd-qemu-writer.sh
export CONFIG_HEADS_FWUPD_ASSUME_YES=y
export CONFIG_HEADS_FWUPD_REBOOT=n

QEMU_SMBIOS_ARGS := -smbios "type=1,manufacturer=Star Labs,product=starlabs_qemu,family=QEMU"
5 changes: 5 additions & 0 deletions initrd/bin/gui-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,11 @@ if [ -x /bin/hotp_verification ]; then
detect_usb_security_dongle_branding
fi

if [ "$CONFIG_HEADS_FWUPD" = "y" ]; then
/bin/heads-fwupd.sh || whiptail_error --title "Firmware Update Rejected" \
--msgbox "A staged firmware update could not be authenticated or did not match this system. It was not applied." 0 80
fi

if detect_boot_device; then
# /boot device with installed OS found
clean_boot_check
Expand Down
Loading