#!/bin/sh # bashsupport disable=BP5007 # shellcheck disable=SC2249 # shellcheck shell=sh # SPDX-Version: 3.0 # SPDX-CreationInfo: 2025-11-12; 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-2025; 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 # Purpose: Open /live/ciss_rootfs.crypt (LUKS) for final processing in '9990-overlay.sh' # Phase : premount (executed by live-boot inside the initramfs) _SAVED_SET_OPTS="$(set +o)" set -eu printf "\e[95m[INFO] Starting : [/usr/lib/live/boot/0024-ciss-crypt-squash] \n\e[0m" ####################################### # Ask for a passphrase on /dev/console, mask input with '*'. # Globals: # None # Arguments: # None # Returns: # 0: on success # 1: on failure / empty ####################################### ask_pass_console() { PASSPHRASE="" SAVED_STTY="" ### Save current console settings. SAVED_STTY=$(stty -g /dev/null || printf '') ### Non-canonical mode, no echo, 1 byte at a time. stty -echo -icanon time 0 min 1 /dev/null || return 1 cr=$(printf '\r') bs=$(printf '\b') del=$(printf '\177') while :; do ### Read exactly one byte from the console. c=$(dd bs=1 count=1 2>/dev/null /dev/console break fi ### If nothing read (race), loop again. [ -z "${c}" ] && continue case "${c}" in "${cr}") ### Enter: finish input. printf '\n' > /dev/console break ;; "${bs}"|"${del}") ### Backspace, delete: delete one character, if available. if [ -n "${PASSPHRASE}" ]; then PASSPHRASE=${PASSPHRASE%?} printf '\b \b' > /dev/console fi ;; *) ### Normal character: append and mask output. PASSPHRASE="${PASSPHRASE}${c}" printf '*' > /dev/console ;; esac done [ -n "${SAVED_STTY}" ] && stty "${SAVED_STTY}" /dev/null || : printf '%s' "${PASSPHRASE}" return 0 } ####################################### # Premount logging helper. # Globals: # None # Arguments: # *: String to log. ####################################### log() { msg="$*" if [ -w /dev/kmsg ]; then printf '<6>%s: %s\n' '0024-ciss-crypt-squash' "${msg}" > /dev/kmsg else printf '%s: %s\n' '0024-ciss-crypt-squash' "${msg}" fi } ### Declare variables. --------------------------------------------------------------------------------------------------------- export CDLB_ISO_LABEL="CISS.debian.live" export CDLB_LUKS_FS="/live/ciss_rootfs.crypt" export CDLB_LUKS_ROOTFS_MNT="/run/live/ciss-rootfs" export CDLB_MAPPER_NAME="crypt_liveiso" export CDLB_MAPPER_DEV="/dev/mapper/${CDLB_MAPPER_NAME}" export CDLB_MNT_MEDIUM="/run/live/medium" export CDLB_MNT_ROOTFS="/run/live/rootfs" export CDLB_REMOTE_WAIT_SECS="${CDLB_REMOTE_WAIT_SECS:-3600}" _PARAMETER="" _dev="" ### Read the kernel cmdline once. ---------------------------------------------------------------------------------------------- CMDLINE="$(cat /proc/cmdline 2>/dev/null || printf '')" for _PARAMETER in ${CMDLINE}; do case "${_PARAMETER}" in ciss_crypt_path=*) export CDLB_LUKS_FS="${_PARAMETER#ciss_crypt_path=}";; ciss_iso_label=* ) export CDLB_ISO_LABEL="${_PARAMETER#ciss_iso_label=}";; esac done printf "\e[92m[INFO] CDLB_LUKS_FS : [%s] \n\e[0m" "${CDLB_LUKS_FS}" printf "\e[92m[INFO] CDLB_ISO_LABEL : [%s] \n\e[0m" "${CDLB_ISO_LABEL}" mkdir -p /conf "${CDLB_MNT_MEDIUM}" "${CDLB_MNT_ROOTFS}" ### Mount the live medium (ISO) read-only, unless already mounted. ------------------------------------------------------------- if ! mountpoint -q "${CDLB_MNT_MEDIUM}"; then if [ -n "${CDLB_ISO_LABEL}" ] && [ -e "/dev/disk/by-label/${CDLB_ISO_LABEL}" ]; then mount -r -t iso9660 "/dev/disk/by-label/${CDLB_ISO_LABEL}" "${CDLB_MNT_MEDIUM}" 2>/dev/null \ || mount -r -t udf "/dev/disk/by-label/${CDLB_ISO_LABEL}" "${CDLB_MNT_MEDIUM}" 2>/dev/null \ || log "could not mount label=${CDLB_ISO_LABEL} (iso9660/udf)" fi fi if ! mountpoint -q "${CDLB_MNT_MEDIUM}"; then ### Fallback scan (covers SR drives and loop-mounted ISOs that udev exposed). for _dev in /dev/sr* /dev/cdrom /dev/disk/by-label/*; do ### Skip non-block entries early. [ -b "${_dev}" ] || continue ### Try ISO9660 first, then UDF; only unmount on failure. if mount -r -t iso9660 "${_dev}" "${CDLB_MNT_MEDIUM}" 2>/dev/null || mount -r -t udf "${_dev}" "${CDLB_MNT_MEDIUM}" 2>/dev/null; then mountpoint -q "${CDLB_MNT_MEDIUM}" 2>/dev/null && break else umount "${CDLB_MNT_MEDIUM}" 2>/dev/null || true fi done fi if ! mountpoint -q "${CDLB_MNT_MEDIUM}"; then printf "\e[91m[FATAL] Boot failure : No live medium mounted, defer to default live-boot path. \n\e[0m" sleep 60 log "[FATAL] Boot failure : No live medium mounted, defer to default live-boot path." panic "[FATAL] Boot failure : No live medium mounted, defer to default live-boot path." fi printf "\e[92m[INFO] MNT_MEDIUM : [%s] \n\e[0m" "${CDLB_MNT_MEDIUM}" ### Locate the encrypted root container on the medium. ------------------------------------------------------------------------- if [ ! -f "${CDLB_MNT_MEDIUM}${CDLB_LUKS_FS}" ]; then printf "\e[91m[FATAL] Boot failure : Encrypted root not found at: [%s%s] \n\e[0m" "${CDLB_MNT_MEDIUM}" "${CDLB_LUKS_FS}" sleep 60 log "[FATAL] Boot failure : Encrypted root not found at: [${CDLB_MNT_MEDIUM}${CDLB_LUKS_FS}]" panic "[FATAL] Boot failure : Encrypted root not found at: [${CDLB_MNT_MEDIUM}${CDLB_LUKS_FS}]" fi printf "\e[92m[INFO] CISS LUKS FS : [%s%s] \n\e[0m" "${CDLB_MNT_MEDIUM}" "${CDLB_LUKS_FS}" ### Attach a loop device read-only to the encrypted file. ---------------------------------------------------------------------- if ! LOOP="$(losetup -f --show -r "${CDLB_MNT_MEDIUM}${CDLB_LUKS_FS}")"; then printf "\e[91m[FATAL] Boot failure : losetup failed \n\e[0m" sleep 60 log "[FATAL] Boot failure : losetup failed " panic "[FATAL] Boot failure : losetup failed " fi printf "\e[92m[INFO] Loop device : [%s] \n\e[0m" "${LOOP}" ### Expose the loop device for unlock-wrapper.sh, dropbear forced-command. ----------------------------------------------------- mkdir -p /run 2>/dev/null || true echo "${LOOP}" > /run/ciss-loopdev 2>/dev/null || true chmod 0600 /run/ciss-loopdev 2>/dev/null || true printf "\e[92m[INFO] Exposed LOOP : [/run/ciss-loopdev] -> [%s]\n\e[0m" "${LOOP}" ### Prepare fifo for passphrase. ----------------------------------------------------------------------------------------------- mkdir -p /lib/cryptsetup 2>/dev/null || true if [ -p /lib/cryptsetup/passfifo ]; then rm -f /lib/cryptsetup/passfifo 2>/dev/null || true fi if ! mkfifo /lib/cryptsetup/passfifo 2>/dev/null; then printf "\e[92m[WARN] Boot failure : Failed to create [/lib/cryptsetup/passfifo] \n\e[0m" sleep 60 log "[WARN] Boot failure : Failed to create [/lib/cryptsetup/passfifo]" panic "[WARN] Boot failure : Failed to create [/lib/cryptsetup/passfifo]" fi chmod 0600 /lib/cryptsetup/passfifo 2>/dev/null || true ### Background broker: read FIFO, try cryptsetup per line. --------------------------------------------------------------------- ( set +e PASS="" while :; do if [ -b "${CDLB_MAPPER_DEV}" ]; then break fi if ! IFS= read -r PASS < /lib/cryptsetup/passfifo; then sleep 1 continue fi [ -n "${PASS}" ] || continue printf "\e[93m[INFO] CISS LUKS decryption : LUKS mapper [%s] trying to unlock via cryptsetup ... \n\e[0m" "${CDLB_MAPPER_DEV}" >/dev/console 2>/dev/null || true KEYLEN=${#PASS} printf '%s' "${PASS}" | cryptsetup open --tries 1 \ --type luks \ --keyfile-size="${KEYLEN}" \ --readonly "${LOOP}" "${CDLB_MAPPER_NAME}" --key-file - 2>/dev/console if [ -b "${CDLB_MAPPER_DEV}" ]; then printf "\e[92m[INFO] CISS LUKS decryption : LUKS mapper [%s] successfully opened. \n\e[0m" "${CDLB_MAPPER_DEV}" >/dev/console 2>/dev/null || true break fi done ) & PID_BROKER="$!" ### Background process console-prompt feed passphrases into FIFO. -------------------------------------------------------------- ( set +e PASS="" PASS_SENT=0 WAIT_LOOP=0 while :; do if [ -b "${CDLB_MAPPER_DEV}" ]; then break fi if [ "${PASS_SENT}" -eq 0 ]; then printf '\e[93m[INFO] Enter LUKS passphrase: \n\e[0m' > /dev/console # shellcheck disable=SC2310 PASS="$(ask_pass_console)" || continue printf '%s\n' "${PASS}" >| /lib/cryptsetup/passfifo 2>/dev/null || : PASS_SENT=1 WAIT_LOOP=0 else WAIT_LOOP=$((WAIT_LOOP + 1)) if [ "${WAIT_LOOP}" -ge 160 ]; then printf '\e[91m[WARN] Please try again : \n\e[0m' > /dev/console PASS_SENT=0 WAIT_LOOP=0 fi fi sleep 0.1 done return 0 ) & PID_PROMPT="$!" ### Main process: wait bounded time for the mapper to appear. ------------------------------------------------------------------ REMAINING="${CDLB_REMOTE_WAIT_SECS}" if [ ! -b "${CDLB_MAPPER_DEV}" ]; then printf "\e[93m[INFO] CISS LUKS decryption : Waiting up to %s seconds for [%s] to be unlocked ... \n\e[0m" "${REMAINING}" "${CDLB_MAPPER_DEV}" fi while [ "${REMAINING}" -gt 0 ]; do if [ -b "${CDLB_MAPPER_DEV}" ]; then break fi sleep 1 REMAINING=$((REMAINING - 1)) done if [ ! -b "${CDLB_MAPPER_DEV}" ]; then printf "\e[91m[WARN] CISS LUKS decryption : Timeout LUKS mapper [%s] not present after %s seconds. \n\e[0m" "${CDLB_MAPPER_DEV}" "${CDLB_REMOTE_WAIT_SECS}" kill "${PID_PROMPT}" 2>/dev/null || true kill "${PID_BROKER}" 2>/dev/null || true rm -f /lib/cryptsetup/passfifo 2>/dev/null || true sleep 60 log "[WARN] CISS LUKS decryption : Timeout LUKS mapper [${CDLB_MAPPER_DEV}] not present after ${CDLB_REMOTE_WAIT_SECS} seconds." panic "[WARN] CISS LUKS decryption : Timeout LUKS mapper [${CDLB_MAPPER_DEV}] not present after ${CDLB_REMOTE_WAIT_SECS} seconds." fi kill "${PID_PROMPT}" 2>/dev/null || true wait "${PID_BROKER}" 2>/dev/null || true rm -f /lib/cryptsetup/passfifo 2>/dev/null || true printf "\e[92m[INFO] CISS LUKS decryption : [%s] is now present.\n\e[0m" "${CDLB_MAPPER_DEV}" ### Expose the decrypted root device for live-boot overlay. The live-boot components will pick this up in '9990-overlay.sh'. --- cat << EOF >| /run/ciss-rootdev export CDLB_ISO_LABEL=${CDLB_ISO_LABEL} export CDLB_LUKS_FS=${CDLB_LUKS_FS} export CDLB_LUKS_ROOTFS_MNT=${CDLB_LUKS_ROOTFS_MNT} export CDLB_MAPPER_NAME=${CDLB_MAPPER_NAME} export CDLB_MAPPER_DEV=${CDLB_MAPPER_DEV} export CDLB_MNT_MEDIUM=${CDLB_MNT_MEDIUM} export CDLB_MNT_ROOTFS=${CDLB_MNT_ROOTFS} export CDLB_REMOTE_WAIT_SECS=${CDLB_REMOTE_WAIT_SECS} EOF chmod 0444 /run/ciss-rootdev 2>/dev/null || true ### Override '9990-main.sh' behavior to ensure 'Verify_checksums()' functions properly. ---------------------------------------- if [ ! -e /conf/param.conf ]; then printf "\e[92m[INFO] CISS LUKS decryption : Not existing [/conf/param.conf] \n\e[0m" : >| /conf/param.conf fi if ! grep -q '^PLAIN_ROOT=' /conf/param.conf 2>/dev/null; then printf 'PLAIN_ROOT=1\n' >> /conf/param.conf fi if ! grep -q '^livefs_root=' /conf/param.conf 2>/dev/null; then printf 'livefs_root=%s\n' "/run/live/medium" >> /conf/param.conf fi printf "\e[92m[INFO] CISS LUKS decryption : Final state [/conf/param.conf] \n\e[0m" cat /conf/param.conf >/dev/console 2>&1 || : log "Decrypted root device exposed at [/run/ciss-rootdev] -> [${CDLB_MAPPER_DEV}]" printf "\e[92m[INFO] CISS LUKS decryption : Decrypted root device exposed at: [/run/ciss-rootdev] -> [%s] \n\e[0m" "${CDLB_MAPPER_DEV}" ### Final sanity check. -------------------------------------------------------------------------------------------------------- if [ ! -b "${CDLB_MAPPER_DEV}" ]; then printf "\e[91m[WARN] Failed unlock : [%s] via dropbear and console. \n\e[0m" "${CDLB_LUKS_FS}" sleep 60 log "[WARN] Failed unlock : [${CDLB_LUKS_FS}] via dropbear and console." panic "[WARN] Failed unlock : [${CDLB_LUKS_FS}] via dropbear and console." fi eval "${_SAVED_SET_OPTS}" printf "\e[92m[INFO] Successfully applied : [/usr/lib/live/boot/0024-ciss-crypt-squash] \n\e[0m" # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh