From: Luca Boccassi Date: Tue, 25 Feb 2025 00:11:46 +0000 (+0000) Subject: mkosi-obs: sign bootloaders in ESPs X-Git-Tag: v26~353^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=70af7c73c43ad81e8fe33eb634d0cb5d91aea56a;p=thirdparty%2Fmkosi.git mkosi-obs: sign bootloaders in ESPs If there are bootloaders in the ESP(s), sign them too. Useful to ensure everything is signed also with the certificate in the project where the image is built. --- diff --git a/mkosi/resources/mkosi-obs/mkosi.build b/mkosi/resources/mkosi-obs/mkosi.build index 605c41f14..358d205cb 100755 --- a/mkosi/resources/mkosi-obs/mkosi.build +++ b/mkosi/resources/mkosi-obs/mkosi.build @@ -85,7 +85,52 @@ while read -r SIG; do fi fi done < <(find hashes/ukis hashes/kernels -type f \( -name '*efi.sig' -o -name 'vmlinu*.sig' \) -printf '%P\n') -rm -rf nss-db "$OUTPUTDIR"/*.sig hashes/ukis +rm -rf "$OUTPUTDIR"/*.sig hashes/ukis + +# If there are signed bootloaders, install them in the ESP +while read -r BOOTLOADER; do + unsigned="$(basename "${BOOTLOADER%.sig}")" + signed="$(basename "${BOOTLOADER%.sig}".signed)" + ddi="${OUTPUTDIR}/${BOOTLOADER%%/*}" + # remove leading directory from BOOTLOADER + dest="${BOOTLOADER#*/}" + dest="${dest%.sig}" + + if [ -f "${ddi}.zst" ]; then + unzstd "${ddi}.zst" + fi + + offset="$(systemd-repart --json=short "$ddi" | jq -r '.[] | select(.type == "esp") | .offset')" + if [ -z "$offset" ] || [ "$offset" = "null" ]; then + if [ -f "$ddi.zst" ]; then + rm -f "$ddi" + fi + continue + fi + + rm -f "$unsigned" + mcopy -i "${ddi}@@${offset}" "::$dest" "$unsigned" + + # ensure the EFI hash matches before and after attaching the signature + old_hash=$(pesign -n sql:"$nss_db" -h -P -i "$unsigned" | cut -d' ' -f1) + + pesign -n sql:"$nss_db" --force -c cert -i "$unsigned" -o "$signed" -d sha256 -I "hashes/bootloaders/${BOOTLOADER%.sig}" -R "hashes/bootloaders/${BOOTLOADER}" + + new_hash=$(pesign -n sql:"$nss_db" -h -i "$signed" | cut -d' ' -f1) + if [ "$old_hash" != "$new_hash" ]; then + echo "Pesign hash mismatch error: $old_hash $new_hash" + exit 1 + fi + + mcopy -o -i "${ddi}@@${offset}" "$signed" "::$dest" + + if [ -f "${ddi}.zst" ]; then + zstd --force "$ddi" + rm -f "$ddi" + fi +done < <(find "hashes/bootloaders/$(basename "$ddi")/" -type f -iname '*.efi.sig' -printf '%P\n') +rm -rf hashes/bootloaders +rm -rf nss-db # Second step: if there are PCR policy signatures, rebuild the JSON # blobs with the attached signatures diff --git a/mkosi/resources/mkosi-obs/mkosi.postoutput b/mkosi/resources/mkosi-obs/mkosi.postoutput index 710e1ebb0..19569aa53 100755 --- a/mkosi/resources/mkosi-obs/mkosi.postoutput +++ b/mkosi/resources/mkosi-obs/mkosi.postoutput @@ -15,8 +15,10 @@ declare -a KERNELS mapfile -t KERNELS < <(find "$OUTPUTDIR" -type f -name "vmlinu*" -printf '%P\n') declare -a ROOTHASHES mapfile -t ROOTHASHES < <(find "$OUTPUTDIR" -type f -name "*.roothash" -printf '%P\n') +declare -a DDIS +mapfile -t DDIS < <(find "$OUTPUTDIR" -type f -name "*.raw*") -if ((${#UKIS[@]} == 0)) && ((${#KERNELS[@]} == 0)) && ((${#ROOTHASHES[@]} == 0)); then +if ((${#UKIS[@]} == 0)) && ((${#KERNELS[@]} == 0)) && ((${#ROOTHASHES[@]} == 0)) && ((${#DDIS[@]} == 0)); then echo "No unsigned files found, exiting" exit 0 fi @@ -59,6 +61,38 @@ for f in "${ROOTHASHES[@]}"; do fi done +# Handle bootloaders separately from UKIs +for ddi in "${DDIS[@]}"; do + test -f "$ddi" || continue + if [[ $ddi == *.zst ]]; then + unzstd "${ddi}" + fi + offset="$(systemd-repart --json=short "${ddi%.zst}" | jq -r '.[] | select(.type == "esp") | .offset')" + if [ "$offset" = "null" ]; then + if [[ $ddi == *.zst ]]; then + rm -f "${ddi%.zst}" + fi + continue + fi + + rm -rf EFI + mcopy -s -i "${ddi%.zst}@@${offset}" ::EFI EFI || true + find EFI + + # UKIs are handled separately + rm -rf EFI/Linux + + while read -r BOOTLOADER; do + mkdir -p "hashes/bootloaders/$(basename "${ddi%.zst}")/$(dirname "$BOOTLOADER")" + pesign --force -n sql:"$nss_db" -i "$BOOTLOADER" -E "hashes/bootloaders/$(basename "${ddi%.zst}")/$BOOTLOADER" + done < <(find EFI -type f -iname '*.efi') + + if [[ $ddi == *.zst ]]; then + rm -f "${ddi%.zst}" + fi + rm -rf EFI +done + # Pack everything into a CPIO archive and place it where OBS expects it pushd hashes find . -type f | cpio -H newc -o >"$OUTPUTDIR/hashes.cpio.rsasign"