#!/bin/bash # SPDX-Version: 3.0 # SPDX-FileCopyrightText: 2026; WEIDNER, Marc S.; # SPDX-FileType: SOURCE # SPDX-License-Identifier: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1 # SPDX-PackageName: CISS.debian.live.builder set -Ceuo pipefail declare ROOT_DIR="" declare SHA512SUM="" declare SHASUM="" declare TMP_BASE="" declare TMP_ROOT="" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" SHA512SUM="$(command -v sha512sum)" SHASUM="$(command -v shasum || true)" TMP_BASE="${TMPDIR:-/tmp}" TMP_BASE="${TMP_BASE%/}" TMP_ROOT="$(mktemp -d "${TMP_BASE}/ciss-boot-attestation.XXXXXXXX")" cleanup() { case "${TMP_ROOT}" in "${TMP_BASE}/ciss-boot-attestation."*) rm -rf -- "${TMP_ROOT}" ;; *) printf 'Refusing to clean unexpected test path: %s\n' "${TMP_ROOT}" >&2 return 1 ;; esac } trap cleanup EXIT fail() { printf 'FAIL: %s\n' "${1}" >&2 exit 1 } prepare_checksum_hook() { declare source_hook="${1}" declare target_hook="${2}" declare fault_mode="${3}" declare test_bin="${4}" declare test_tty="${5}" declare test_runtime="" test_runtime="$(dirname "${test_tty}")" sed \ -e "s|/usr/bin/|${test_bin}/|g" \ -e "s|/run/ciss-|${test_runtime}/ciss-|g" \ -e "s|_TTY=\"/dev/tty8\"|_TTY=\"${test_tty}\"|" \ "${source_hook}" > "${target_hook}" if [[ "${fault_mode}" == "unknown-state" ]]; then sed \ -e 's/_RETURN_PGP="na"/_RETURN_PGP="unknown"/' \ -e 's/_RETURN_SHA="${?}"/_RETURN_SHA="unknown"/g' \ "${target_hook}" > "${target_hook}.new" mv "${target_hook}.new" "${target_hook}" fi } install_test_sha512sum() { declare test_bin="${1}" if printf '' | "${SHA512SUM}" -c >/dev/null 2>&1; then ln -s "${SHA512SUM}" "${test_bin}/sha512sum" elif [[ -n "${SHASUM}" ]]; then printf '#!/bin/sh\nexec "%s" -a 512 "$@"\n' "${SHASUM}" > "${test_bin}/sha512sum" chmod 0755 "${test_bin}/sha512sum" else fail "No SHA-512 tool with checksum verification support is available." fi } run_checksum_case() { declare source_hook="${1}" declare case_name="${2}" declare expected_status="${3}" declare expected_message="${4}" declare case_dir="" declare hook_copy="" declare output_file="" declare test_bin="" declare test_tty="" declare source_id="" declare fault_mode="" declare panic_returns="false" declare status=0 source_id="$(printf '%s' "${source_hook#"${ROOT_DIR}"/}" | tr '/' '_')" case_dir="${TMP_ROOT}/${source_id}-${case_name}" hook_copy="${case_dir}/0030-ciss-verify-checksums" output_file="${case_dir}/output.log" test_bin="${case_dir}/bin" test_tty="${case_dir}/tty.log" mkdir -p "${case_dir}" "${test_bin}" : >| "${test_tty}" case "${case_name}" in valid) install_test_sha512sum "${test_bin}" printf 'trusted rootfs payload\n' > "${case_dir}/payload" (cd "${case_dir}" && "${test_bin}/sha512sum" payload > sha512sum.txt) ;; missing-manifest) install_test_sha512sum "${test_bin}" ;; unsupported-manifest) install_test_sha512sum "${test_bin}" printf 'unsupported\n' > "${case_dir}/md5sum.txt" ;; failed-checksum) install_test_sha512sum "${test_bin}" printf 'trusted rootfs payload\n' > "${case_dir}/payload" (cd "${case_dir}" && "${test_bin}/sha512sum" payload > sha512sum.txt) printf 'tampered rootfs payload\n' >| "${case_dir}/payload" ;; missing-tool) install_test_sha512sum "${test_bin}" printf 'trusted rootfs payload\n' > "${case_dir}/payload" (cd "${case_dir}" && "${test_bin}/sha512sum" payload > sha512sum.txt) rm -f "${test_bin}/sha512sum" ;; unknown-state) fault_mode="unknown-state" panic_returns="true" install_test_sha512sum "${test_bin}" printf 'trusted rootfs payload\n' > "${case_dir}/payload" (cd "${case_dir}" && "${test_bin}/sha512sum" payload > sha512sum.txt) ;; *) fail "Unknown checksum test case: ${case_name}" ;; esac prepare_checksum_hook "${source_hook}" "${hook_copy}" "${fault_mode}" "${test_bin}" "${test_tty}" set +e # shellcheck disable=SC2034,SC2329 ( set +C CDLB_SCRIPT_FULL="${hook_copy}" LIVE_BOOT_CMDLINE="verify-checksums=sha512" LIVE_VERIFY_CHECKSUMS="" log_begin_msg() { :; } log_end_msg() { :; } log_success_msg() { :; } panic() { printf 'PANIC: %s\n' "${1}" >&2 if [[ "${panic_returns}" == "true" ]]; then return 0 fi exit 97 } sleep() { :; } # shellcheck source=/dev/null . "${hook_copy}" Verify_checksums "${case_dir}" ) > "${output_file}" 2>&1 status="${?}" set -e [[ "${status}" -eq "${expected_status}" ]] || { cat "${output_file}" >&2 fail "${source_hook} ${case_name}: expected status ${expected_status}, got ${status}" } grep -Fq "${expected_message}" "${output_file}" || { cat "${output_file}" >&2 fail "${source_hook} ${case_name}: missing expected message '${expected_message}'" } } test_rootfs_payload_tamper() { declare case_dir="${TMP_ROOT}/rootfs-payload-tamper" declare test_bin="${case_dir}/bin" declare payload="${case_dir}/crypt_liveiso" declare manifest="${case_dir}/ciss_rootfs.crypt.decrypted.sha512sum.txt" declare build_hook="${ROOT_DIR}/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary" declare boot_hook="${ROOT_DIR}/config/includes.chroot/usr/lib/live/boot/0042_ciss_post_decrypt_attest" mkdir -p "${case_dir}" "${test_bin}" install_test_sha512sum "${test_bin}" printf 'trusted selected rootfs mapper payload\n' > "${payload}" "${test_bin}/sha512sum" "${payload}" > "${manifest}" "${test_bin}/sha512sum" -c --strict --quiet "${manifest}" printf 'tampered selected rootfs mapper payload\n' >> "${payload}" if "${test_bin}/sha512sum" -c --strict --quiet "${manifest}" >/dev/null 2>&1; then fail "Modified selected rootfs payload unexpectedly passed checksum verification." fi # shellcheck disable=SC2016 grep -Fq 'sha512sum "${MAPPER_DEV}" >| "${ROOTFS_ATTESTATION}"' "${build_hook}" || \ fail "Build hook does not generate the attestation from the decrypted mapper." # shellcheck disable=SC2016 grep -Fq '/usr/bin/sha512sum -c --strict --quiet "${HASH_FILE}"' "${boot_hook}" || \ fail "Boot hook does not verify the selected rootfs payload with sha512sum -c." # shellcheck disable=SC2016 grep -Fq '[ "${_ATTESTED_PAYLOAD}" != "${CDLB_MAPPER_DEV}" ]' "${boot_hook}" || \ fail "Boot hook does not require the manifest to target the selected rootfs payload." } declare -a CHECKSUM_HOOKS=( "${ROOT_DIR}/config/includes.chroot/usr/lib/live/boot/0030-ciss-verify-checksums" "${ROOT_DIR}/scripts/usr/lib/live/boot/0030-ciss-verify-checksums" ) declare checksum_hook="" for checksum_hook in "${CHECKSUM_HOOKS[@]}"; do run_checksum_case "${checksum_hook}" "valid" 0 "Verification of [sha checksum] file successful" run_checksum_case "${checksum_hook}" "missing-manifest" 97 "No supported checksum manifest found." run_checksum_case "${checksum_hook}" "unsupported-manifest" 97 "No supported checksum manifest found." run_checksum_case "${checksum_hook}" "failed-checksum" 97 "No supported checksum manifest was verified successfully." run_checksum_case "${checksum_hook}" "missing-tool" 97 "No supported checksum verification tool was available." run_checksum_case "${checksum_hook}" "unknown-state" 1 "Checksum verification ended in an unsupported state." done test_rootfs_payload_tamper printf 'PASS: checksum verification fails closed and modified rootfs payloads fail attestation.\n'