From d3cbc9b4a51eab7b4d19d62f84d2a2e53a2f8f02 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Tue, 25 Feb 2025 00:12:36 +0000 Subject: [PATCH] mkosi-obs: add support for UEFI SecureBoot self enrollment Create authvars and store them in the ESP with the project cert used as PK/KEK/db --- mkosi/resources/mkosi-obs/mkosi.build | 46 ++++++++++++++++++++++ mkosi/resources/mkosi-obs/mkosi.postoutput | 16 ++++++++ 2 files changed, 62 insertions(+) diff --git a/mkosi/resources/mkosi-obs/mkosi.build b/mkosi/resources/mkosi-obs/mkosi.build index 358d205cb..dc5ed8917 100755 --- a/mkosi/resources/mkosi-obs/mkosi.build +++ b/mkosi/resources/mkosi-obs/mkosi.build @@ -33,6 +33,7 @@ mkdir nss-db nss_db="$PWD/nss-db" certutil -N -d sql:"$nss_db" --empty-password certutil -A -d sql:"$nss_db" -n cert -t CT,CT,CT -i /usr/src/packages/SOURCES/_projectcert.crt +openssl x509 -inform PEM -in /usr/src/packages/SOURCES/_projectcert.crt -outform DER -out _projectcert.cer cp -r /usr/src/packages/SOURCES/"$IMAGE_ID"* "$OUTPUTDIR" rm -f "$OUTPUTDIR/hashes.cpio.rsasign*" "$OUTPUTDIR"/*.sha* @@ -225,4 +226,49 @@ while read -r SIG; do done < <(find hashes/roothashes -type f -name '*.sig') rm -rf hashes/roothashes +# Sixth step: prepare EFI authvars for self-enrollment +# as implemented by https://github.com/openSUSE/pesign-obs-integration/blob/master/pesign-repackage.spec.in#L162 +while read -r SIG; do + test -x /usr/lib/rpm/pesign/kernel-sign-file || break + f="${SIG%.sig}" + /usr/lib/rpm/pesign/kernel-sign-file -N -P -d -C _projectcert.cer -i pkcs7 -s "$SIG" sha256 _projectcert.cer "$f" + fbase="${f##*/}" + fbase="${fbase%.auth}" + fbase="${fbase%%-*}" + perl -0777 -npe 's/\A(?:[\040-\176]\0)+.{18}\0\0.{14}\0\0//s' < "$f" > "$f.orig" + sign-efi-sig-list -t "${SOURCE_DATE_EPOCH:-$(date +%s)}" -i "$f.p7sd" "$fbase" "$f.orig" "$f.tmp" + mv "$f.tmp" "$f" + rm -f "$f.p7s" "$f.p7sd" "$f.orig" +done < <(find hashes/authvars -type f -name '*.auth.sig') +declare -a AUTHVARS +mapfile -t AUTHVARS < <(find hashes/authvars -type f -name "*.auth") +if (( ${#AUTHVARS[@]} > 0 )); then + for ddi in "$OUTPUTDIR"/*.raw*; do + test -f "$ddi" || continue + if [[ $ddi == *.zst ]]; then + unzstd "${ddi}" + recompress=1 + fi + offset="$(systemd-repart --json=short "${ddi%.zst}" | jq -r '.[] | select(.type == "esp") | .offset')" + if [ -z "$offset" ] || [ "$offset" = "null" ]; then + if [[ $ddi == *.zst ]]; then + rm -f "${ddi%.zst}" + fi + continue + fi + + mmd -D s -i "${ddi%.zst}@@${offset}" ::loader ::loader/keys ::loader/keys/auto || true + for authvar in "${AUTHVARS[@]}"; do + test -f "$authvar" || continue + mcopy -o -i "${ddi%.zst}@@${offset}" "$authvar" "::loader/keys/auto/$(basename "$authvar")" + done + + if ((recompress)); then + zstd --force "${ddi%.zst}" + rm -f "${ddi%.zst}" + fi + done +fi +rm -rf hashes/authvars + rm -rf hashes "$nss_db" diff --git a/mkosi/resources/mkosi-obs/mkosi.postoutput b/mkosi/resources/mkosi-obs/mkosi.postoutput index 19569aa53..4d80d0cd5 100755 --- a/mkosi/resources/mkosi-obs/mkosi.postoutput +++ b/mkosi/resources/mkosi-obs/mkosi.postoutput @@ -93,6 +93,22 @@ for ddi in "${DDIS[@]}"; do rm -rf EFI done +# If there is at least one DDI then there might be an ESP, so prepare the authvars for self-enrollment +if ((${#DDIS[@]} > 0)); then + mkdir -p hashes/authvars + pushd hashes/authvars 2>/dev/null + # Same as the GUID used by bootctl + guid=a5c059a1-94e4-4aa7-87b5-ab155c2bf072 + cert-to-efi-sig-list -g "$guid" /usr/src/packages/SOURCES/_projectcert.crt db.esl + cp db.esl KEK.esl + cp db.esl PK.esl + env + for i in *.esl; do + sign-efi-sig-list -o -g "$guid" -t "${SOURCE_DATE_EPOCH:-$(date +%s)}" "${i%.esl}" "$i" "${i%.esl}.auth" + done + popd 2>/dev/null +fi + # 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" -- 2.47.2