diff --git a/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary b/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary index b536502..110bf81 100644 --- a/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary +++ b/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary @@ -65,6 +65,59 @@ preallocate() { # shellcheck disable=SC2034 readonly -f preallocate +####################################### +# Validate that the rootfs attestation artifacts exist in the final ISO payload tree. +# Globals: +# None +# Arguments: +# 1: Rootfs attestation manifest path +# Returns: +# 0: on success +# 42: on failure +####################################### +require_rootfs_attestation_artifacts() { + declare manifest="${1}" + declare signature="${manifest}.sig" + declare artifact="" + + for artifact in "${manifest}" "${signature}"; do + + if [[ ! -e "${artifact}" ]]; then + + printf "\e[91m❌ Required rootfs attestation artifact missing: [%s]. \e[0m\n" "${artifact}" >&2 + return 42 + + fi + + if [[ -L "${artifact}" || ! -f "${artifact}" ]]; then + + printf "\e[91m❌ Required rootfs attestation artifact is not a regular file: [%s]. \e[0m\n" "${artifact}" >&2 + return 42 + + fi + + if [[ ! -s "${artifact}" ]]; then + + printf "\e[91m❌ Required rootfs attestation artifact is empty: [%s]. \e[0m\n" "${artifact}" >&2 + return 42 + + fi + + if [[ ! -r "${artifact}" ]]; then + + printf "\e[91m❌ Required rootfs attestation artifact is not readable: [%s]. \e[0m\n" "${artifact}" >&2 + return 42 + + fi + + done + + return 0 +} +### Prevents accidental 'unset -f'. +# shellcheck disable=SC2034 +readonly -f require_rootfs_attestation_artifacts + ####################################### # Create and sign the rootfs attestation manifest for the exact SquashFS payload copied into the LUKS mapper. # Globals: @@ -142,9 +195,12 @@ EOF # shellcheck disable=SC2034 readonly -f create_attestation -declare LUKSFS="${VAR_HANDLER_BUILD_DIR}/binary/live/ciss_rootfs.crypt" -declare ROOTFS="${VAR_HANDLER_BUILD_DIR}/binary/live/filesystem.squashfs" -declare ROOTFS_ATTESTATION="${VAR_HANDLER_BUILD_DIR}/binary/live/filesystem.squashfs.sha512sum.txt" +declare LIVE_PAYLOAD_DIR="${VAR_HANDLER_BUILD_DIR}/binary/live" +declare ROOTFS_ATTESTATION_NAME="filesystem.squashfs.sha512sum.txt" +declare ROOTFS_ATTESTATION_REL="live/${ROOTFS_ATTESTATION_NAME}" +declare LUKSFS="${LIVE_PAYLOAD_DIR}/ciss_rootfs.crypt" +declare ROOTFS="${LIVE_PAYLOAD_DIR}/filesystem.squashfs" +declare ROOTFS_ATTESTATION="${VAR_HANDLER_BUILD_DIR}/binary/${ROOTFS_ATTESTATION_REL}" declare DM_LAB="crypt_liveiso" declare DEVMAP="/dev/mapper/${DM_LAB}" declare LUKS_KEY_FILE="${VAR_TMP_SECRET}/${VAR_LUKS_KEY:-luks.txt}" @@ -162,8 +218,10 @@ declare -i VAR_ROOTFS_SIZE="$(stat -c%s -- "${ROOTFS}")" printf "\e[95m🧪 Attestation of filesystem.squashfs ... \e[0m\n" create_attestation "${ROOTFS}" "${ROOTFS_ATTESTATION}" +require_rootfs_attestation_artifacts "${ROOTFS_ATTESTATION}" -printf "\e[92m✅ Attestation of filesystem.squashfs successful. \e[0m\n" +printf "\e[92m✅ Attestation of filesystem.squashfs successful: ISO paths [/%s] and [/%s.sig]. \e[0m\n" \ + "${ROOTFS_ATTESTATION_REL}" "${ROOTFS_ATTESTATION_REL}" ### Safety margin: # - LUKS2-Header and Metadata @@ -250,6 +308,8 @@ shred -fzu -n 5 -- "${LUKS_KEY_FILE}" rm -f -- "${ROOTFS}" +require_rootfs_attestation_artifacts "${ROOTFS_ATTESTATION}" + umask "${__umask}" __umask="" diff --git a/config/includes.chroot/usr/lib/live/boot/0042_ciss_post_decrypt_attest b/config/includes.chroot/usr/lib/live/boot/0042_ciss_post_decrypt_attest index bd788bf..4061575 100644 --- a/config/includes.chroot/usr/lib/live/boot/0042_ciss_post_decrypt_attest +++ b/config/includes.chroot/usr/lib/live/boot/0042_ciss_post_decrypt_attest @@ -23,7 +23,7 @@ # SHA-512 digest and the exact byte length; allocation slack after that SquashFS payload is intentionally out of scope. # - Panics on missing, malformed, unauthentic, or mismatched evidence. -# set -eu +set -eu printf "\e[95m[INFO] Starting : [/usr/lib/live/boot/0042_ciss_post_decrypt_attest] \n\e[0m" @@ -39,7 +39,8 @@ export CDLB_MAPPER_DEV="${CDLB_MAPPER_DEV:-/dev/mapper/${CDLB_MAPPER_NAME}}" export CDLB_MNT_MEDIUM="${CDLB_MNT_MEDIUM:-/run/live/medium}" ### Locations of the attestation file of filesystem.squashfs on the verified live medium. -------------------------------------- -CDLB_ROOTFS_ATTEST_MANIFEST="${CDLB_ROOTFS_ATTEST_MANIFEST:-${CDLB_MNT_MEDIUM}/live/filesystem.squashfs.sha512sum.txt}" +CDLB_ROOTFS_ATTEST_NAME="${CDLB_ROOTFS_ATTEST_NAME:-filesystem.squashfs.sha512sum.txt}" +CDLB_ROOTFS_ATTEST_MANIFEST="${CDLB_ROOTFS_ATTEST_MANIFEST:-${CDLB_MNT_MEDIUM}/live/${CDLB_ROOTFS_ATTEST_NAME}}" CDLB_ROOTFS_ATTEST_SIGNATURE="${CDLB_ROOTFS_ATTEST_SIGNATURE:-${CDLB_ROOTFS_ATTEST_MANIFEST}.sig}" CDLB_ROOTFS_ATTEST_CHECK="${CDLB_ROOTFS_ATTEST_CHECK:-/run/ciss-rootfs-attestation.sha512sum}" CDLB_KEY_DIR="${CDLB_KEY_DIR:-/etc/ciss/keys}" @@ -73,6 +74,16 @@ log_ok() { printf '\e[92m[INFO] %s \n\e[0m' "$*"; } ####################################### log_er() { printf '\e[91m[FATAL] %s \n\e[0m' "$*"; } +### Provide a local fail-closed fallback when this file is executed as a subprocess outside the live-boot shell context. -------- +if ! command -v panic >/dev/null 2>&1; then + + panic() { + log_er "${*}" + exit 1 + } + +fi + ####################################### # Validate a boot-time attestation input file. # Globals: @@ -125,6 +136,52 @@ require_attestation_file() { return 0 } +####################################### +# Resolve rootfs attestation paths on known live medium mountpoints. +# Globals: +# CDLB_MNT_MEDIUM +# CDLB_ROOTFS_ATTEST_MANIFEST +# CDLB_ROOTFS_ATTEST_NAME +# CDLB_ROOTFS_ATTEST_SIGNATURE +# Arguments: +# None +# Returns: +# 0: on success +####################################### +resolve_rootfs_attestation_artifacts() { + medium_path="" + manifest_path="" + signature_path="" + + if [ -f "${CDLB_ROOTFS_ATTEST_MANIFEST}" ] && [ -f "${CDLB_ROOTFS_ATTEST_SIGNATURE}" ]; then + + return 0 + + fi + + for medium_path in "${CDLB_MNT_MEDIUM}" /run/live/medium /lib/live/mount/medium /cdrom; do + + [ -n "${medium_path}" ] || continue + + manifest_path="${medium_path}/live/${CDLB_ROOTFS_ATTEST_NAME}" + signature_path="${manifest_path}.sig" + + if [ -f "${manifest_path}" ] && [ -f "${signature_path}" ]; then + + CDLB_ROOTFS_ATTEST_MANIFEST="${manifest_path}" + CDLB_ROOTFS_ATTEST_SIGNATURE="${signature_path}" + return 0 + + fi + + done + + log_er "0042() : Rootfs attestation artifacts not found. Expected manifest/signature: [${CDLB_ROOTFS_ATTEST_MANIFEST}] [${CDLB_ROOTFS_ATTEST_SIGNATURE}]" + panic "0042() : Rootfs attestation artifacts not found. Expected manifest/signature: [${CDLB_ROOTFS_ATTEST_MANIFEST}] [${CDLB_ROOTFS_ATTEST_SIGNATURE}]" + + return 1 +} + ####################################### # Validate the decrypted rootfs payload device. # Globals: @@ -144,7 +201,11 @@ require_rootfs_payload_device() { fi - if [ -L "${artifact_path}" ] || { [ ! -b "${artifact_path}" ] && [ ! -f "${artifact_path}" ]; }; then + if [ -b "${artifact_path}" ]; then + + : + + elif [ -L "${artifact_path}" ] || [ ! -f "${artifact_path}" ]; then log_er "0042() : Rootfs payload must be a block device or regular test fixture: [${artifact_path}]" panic "0042() : Rootfs payload must be a block device or regular test fixture: [${artifact_path}]" @@ -270,6 +331,8 @@ verify_rootfs_payload() { return 0 } +resolve_rootfs_attestation_artifacts + HASH_FILE="${CDLB_ROOTFS_ATTEST_MANIFEST}" SIGN_FILE="${CDLB_ROOTFS_ATTEST_SIGNATURE}" KEYFILE="${CDLB_KEY_DIR}/${CDLB_EXP_FPR}.gpg"