#!/bin/bash # SPDX-Version: 3.0 # SPDX-CreationInfo: 2026-06-04; WEIDNER, Marc S.; # SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.live.builder.git # SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency # SPDX-FileCopyrightText: 2024-2026; WEIDNER, Marc S.; # SPDX-FileType: SOURCE # SPDX-License-Identifier: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1 # SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework. # SPDX-PackageName: CISS.debian.live.builder # SPDX-Security-Contact: security@coresecret.eu set -Ceuo pipefail declare TMP_DIR="" cleanup() { declare build_dir="${VAR_HANDLER_BUILD_DIR:-${PWD}}" if [[ -n "${TMP_DIR}" && -d "${TMP_DIR}" ]]; then case "${TMP_DIR}" in "${build_dir}/ciss.secureboot/"*) rm -rf -- "${TMP_DIR}" ;; *) printf "\e[91m++++ ++++ ++++ ++++ ++++ ++++ ++ [FATAL] Refusing to clean unexpected temporary path: '%s'. \e[0m\n" "${TMP_DIR}" >&2 return 42 ;; esac fi return 0 } trap cleanup EXIT die() { declare message="$1" printf "\e[91m++++ ++++ ++++ ++++ ++++ ++++ ++ [FATAL] %s \e[0m\n" "${message}" >&2 exit 42 } require_command() { declare command_name="$1" command -v "${command_name}" >/dev/null 2>&1 || die "Required command not found: '${command_name}'." return 0 } require_file() { declare file_path="$1" declare description="$2" [[ -f "${file_path}" ]] || die "Missing ${description}: '${file_path}'." return 0 } select_signed_uki() { declare uki_dir="$1" declare output_var="$2" declare -a signed_ukis=() [[ -d "${uki_dir}" ]] || die "Missing CISS UKI output directory: '${uki_dir}'." mapfile -d '' -t signed_ukis < <(find "${uki_dir}" -maxdepth 1 -type f -name "CISS-LIVE-*.signed.efi" -print0 | LC_ALL=C sort -z) if (( ${#signed_ukis[@]} != 1 )); then die "Expected exactly one signed CISS UKI in '${uki_dir}', found '${#signed_ukis[@]}'." fi printf -v "${output_var}" "%s" "${signed_ukis[0]}" return 0 } guard_private_key_leaks() { declare -a guard_roots=(binary chroot config/includes.binary config/includes.chroot config/includes.installer) declare guard_root="" declare private_file="" for guard_root in "${guard_roots[@]}"; do if [[ ! -d "${guard_root}" ]]; then continue fi while IFS= read -r -d '' private_file; do die "Refusing private Secure Boot key inside build artifact path: '${private_file}'." done < <(find "${guard_root}" -xdev -type f \( -name "ciss-efi-image.key" -o -name "ciss-module-signing.key" \) -print0) done return 0 } install_iso_tree_bootx64() { declare signed_uki="$1" declare output_var="$2" declare iso_tree_bootx64="" if [[ -d "binary/EFI/boot" ]]; then iso_tree_bootx64="binary/EFI/boot/bootx64.efi" elif [[ -d "binary/EFI/BOOT" ]]; then iso_tree_bootx64="binary/EFI/BOOT/BOOTX64.EFI" elif [[ -d "binary/EFI" ]]; then install -d -m 0755 "binary/EFI/BOOT" iso_tree_bootx64="binary/EFI/BOOT/BOOTX64.EFI" fi if [[ -n "${iso_tree_bootx64}" ]]; then install -m 0644 "${signed_uki}" "${iso_tree_bootx64}" printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ [INFO] Mirrored signed UKI into ISO EFI tree: '%s'. \e[0m\n" "${iso_tree_bootx64}" else printf "\e[93m++++ ++++ ++++ ++++ ++++ ++++ ++ [WARN] No binary/EFI tree found; only EFI boot image was updated. \e[0m\n" fi printf -v "${output_var}" "%s" "${iso_tree_bootx64}" return 0 } main() { declare profile="${VAR_CISS_SECUREBOOT_PROFILE:-debian-shim}" declare build_dir="${VAR_HANDLER_BUILD_DIR:-${PWD}}" declare secureboot_dir="${VAR_CISS_SECUREBOOT_DIR:-${VAR_WORKDIR:-${build_dir}}/ciss.secureboot}" declare secureboot_cert="${VAR_CISS_SECUREBOOT_EFI_CERT:-${secureboot_dir}/public/ciss-efi-image.crt}" declare output_root="" declare uki_dir="" declare manifest_dir="" declare signed_uki="" declare efi_img="binary/boot/grub/efi.img" declare uki_name="" declare kernel_version="" declare manifest="" declare tmp_img="" declare extracted_uki="" declare iso_tree_bootx64="" declare uki_size="" declare -i uki_kib=0 declare -i blocks=0 declare source_epoch="${SOURCE_DATE_EPOCH:-0}" declare volid="" if [[ "${profile}" != "ciss-uki" ]]; then printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ [INFO] Secure Boot profile '%s'; skipping CISS UKI EFI installation. \e[0m\n" "${profile}" return 0 fi printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ [INFO] Installing CISS signed UKI into EFI boot image ... \e[0m\n" cd "${build_dir}" require_command cmp require_command mcopy require_command mdir require_command mkfs.msdos require_command sbverify require_command sha512sum require_command stat require_command ukify require_file "${secureboot_cert}" "CISS EFI image signing certificate" require_file "${efi_img}" "live-build EFI boot image" guard_private_key_leaks output_root="${build_dir}/ciss.secureboot" uki_dir="${output_root}/uki" manifest_dir="${output_root}/manifests" select_signed_uki "${uki_dir}" signed_uki uki_name="${signed_uki##*/}" kernel_version="${uki_name#CISS-LIVE-}" kernel_version="${kernel_version%.signed.efi}" [[ -n "${kernel_version}" && "${kernel_version}" != "${uki_name}" ]] || die "Signed UKI name does not match CISS-LIVE-.signed.efi: '${signed_uki}'." install -d -m 0755 "${manifest_dir}" TMP_DIR="$(mktemp -d -p "${output_root}" "efi-img.XXXXXXXX")" tmp_img="${TMP_DIR}/efi.img" extracted_uki="${TMP_DIR}/BOOTX64.EFI" manifest="${manifest_dir}/CISS-LIVE-${kernel_version}.efi-install.txt" rm -f -- "${manifest}" uki_size="$(stat -c %s -- "${signed_uki}")" uki_kib=$(( (uki_size + 1023) / 1024 )) blocks=$(( (uki_kib + 8192 + 31) / 32 * 32 )) if (( blocks < 32768 )); then blocks=32768 fi if [[ ! "${source_epoch}" =~ ^[0-9]+$ ]]; then source_epoch="0" fi printf -v volid "%08x" "$((source_epoch % 4294967296))" printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ [INFO] Rebuilding EFI boot image with signed UKI as EFI/BOOT/BOOTX64.EFI. \e[0m\n" mkfs.msdos -C "${tmp_img}" "${blocks}" -i "${volid}" >/dev/null mmd -i "${tmp_img}" "::EFI" mmd -i "${tmp_img}" "::EFI/BOOT" mcopy -m -o -i "${tmp_img}" "${signed_uki}" "::EFI/BOOT/BOOTX64.EFI" mcopy -o -i "${tmp_img}" "::EFI/BOOT/BOOTX64.EFI" "${extracted_uki}" cmp -s "${signed_uki}" "${extracted_uki}" || die "Extracted BOOTX64.EFI differs from signed UKI before EFI image installation." sbverify --cert "${secureboot_cert}" "${extracted_uki}" >/dev/null install -m 0644 "${tmp_img}" "${efi_img}" rm -f -- "${extracted_uki}" mcopy -o -i "${efi_img}" "::EFI/BOOT/BOOTX64.EFI" "${extracted_uki}" cmp -s "${signed_uki}" "${extracted_uki}" || die "Installed EFI/BOOT/BOOTX64.EFI differs from signed UKI." sbverify --cert "${secureboot_cert}" "${extracted_uki}" >/dev/null install_iso_tree_bootx64 "${signed_uki}" iso_tree_bootx64 if [[ -n "${iso_tree_bootx64}" ]]; then cmp -s "${signed_uki}" "${iso_tree_bootx64}" || die "ISO EFI tree BOOTX64.EFI differs from signed UKI." sbverify --cert "${secureboot_cert}" "${iso_tree_bootx64}" >/dev/null fi guard_private_key_leaks { printf "CISS Secure Boot EFI image installation manifest\n" printf "EFI image: %s\n" "${efi_img}" printf "Installed path: EFI/BOOT/BOOTX64.EFI\n" printf "ISO EFI tree mirror: %s\n" "${iso_tree_bootx64:-none}" printf "Signed UKI: %s\n" "${signed_uki}" printf "FAT image blocks KiB: %s\n" "${blocks}" printf "FAT volume id: %s\n" "${volid}" printf "\nSHA512:\n" sha512sum "${efi_img}" "${signed_uki}" "${extracted_uki}" if [[ -n "${iso_tree_bootx64}" ]]; then sha512sum "${iso_tree_bootx64}" fi printf "\nEFI directory:\n" mdir -i "${efi_img}" "::EFI/BOOT" printf "\nukify inspect installed BOOTX64.EFI:\n" ukify inspect "${extracted_uki}" printf "\nsbverify installed BOOTX64.EFI:\n" sbverify --cert "${secureboot_cert}" "${extracted_uki}" } >| "${manifest}" 2>&1 printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ [INFO] EFI image installation verification written to '%s'. \e[0m\n" "${manifest}" printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ [INFO] CISS signed UKI installed as EFI/BOOT/BOOTX64.EFI. \e[0m\n" return 0 } main "$@" exit 0 # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh