V8.00.000.2025.06.17
All checks were successful
🔁 Render Graphviz Diagrams. / 🔁 Render Graphviz Diagrams. (push) Successful in 39s
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 1m45s

Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
2025-07-20 19:43:09 +02:00
parent 55a0cb6884
commit e1f09ca170
27 changed files with 1100 additions and 909 deletions

View File

@@ -0,0 +1,376 @@
#!/bin/bash
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu
# SPDX-Comment: unlock_wrapper.sh to be executed after dropbear SSH login as forced command
set -Ceuo pipefail
IFS=$(printf ' \n\t')
# shellcheck disable=SC2155
declare -gr CURRENTDATE=$(date +"%F %T")
declare -gir MAX_RETRIES=2
#######################################
# Generates informative shell prompt.
# Globals:
# PS1
# Arguments:
# None
#######################################
prompt_string() {
declare -gx PS1="\
\[\033[1;91m\]\d\[\033[0m\]|\[\033[1;91m\]\u\[\033[0m\]@\
\[\033[1;95m\]\h\[\033[0m\]:\
\[\033[1;96m\]\w\[\033[0m\]/>>\
\$(if [[ \$? -eq 0 ]]; then \
# Show exit status in green if zero
echo -e \"\[\033[1;92m\]\$?\[\033[0m\]\"; \
else \
# Show exit status in red otherwise
echo -e \"\[\033[1;91m\]\$?\[\033[0m\]\"; \
fi)\
|~\$ "
}
#######################################
# Trap function to be called on 'ERR'.
# Arguments:
# $1: ${?}
# $2: ${BASH_SOURCE[0]}
# $3: ${LINENO}
# $4: ${FUNCNAME[0]:-main}
# $5: ${BASH_COMMAND}
#######################################
trap_on_err() {
declare -r errcode="$1"
declare -r errscrt="$2"
declare -r errline="$3"
declare -r errfunc="$4"
declare -r errcmmd="$5"
trap - ERR
stty echo
if [[ ${errcode} -eq 0 ]]; then
print_scr_scc
prompt_string
exit 0
else
print_scr_err "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}"
sleep 15
sync
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
fi
}
#######################################
# Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the Nuke Routine
# Globals:
# DEVICES_LUKS
# DEVICES_NUKE
# Arguments:
# None
#######################################
trap_on_term() {
trap - INT
stty echo
printf "\n"
printf "\e[0;91m✘ System caught a 'SIGINT'. System Power Off in 3 seconds. \e[0m\n" >&2
sync
sleep 3
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
}
#######################################
# Print Error Message for 'non-0' Trap on 'EXIT' on Terminal.
# Arguments:
# $1: ${?}
# $2: ${BASH_SOURCE[0]}
# $3: ${LINENO}
# $4: ${FUNCNAME[0]:-main}
# $5: ${BASH_COMMAND}
#######################################
print_scr_err() {
declare -r scr_err_errcode="$1"
declare -r scr_err_errscrt="$2"
declare -r scr_err_errline="$3"
declare -r scr_err_errfunc="$4"
declare -r scr_err_errcmmd="$5"
printf "\n"
printf "\e[0;91m✘ System caught an 'ERROR'. System Power Off in 15 seconds. \e[0m\n" >&2
printf "\n"
printf "\e[0;91m✘ Error : %s \e[0m\n" "${scr_err_errcode}" >&2
printf "\e[0;91m✘ Line : %s \e[0m\n" "${scr_err_errline}" >&2
printf "\e[0;91m✘ Script : %s \e[0m\n" "${scr_err_errscrt}" >&2
printf "\e[0;91m✘ Function : %s \e[0m\n" "${scr_err_errfunc}" >&2
printf "\e[0;91m✘ Command : %s \e[0m\n" "${scr_err_errcmmd}" >&2
printf "\n"
}
#######################################
# Print Error Message for '0' Trap on 'ERR' on Terminal.
# Arguments:
# none
#######################################
print_scr_scc() {
printf "\e[0;92m✅ Script exited successfully. Proceeding with booting. \e[0m\n"
printf "\n"
}
#######################################
# Gather information of all LUKS Devices available on the system
# Arguments:
# None
#######################################
gather_luks_devices() {
declare prev=() curr=() dev="" tries=0
while ((tries < 10)); do
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device)
if [[ ${curr[*]} == "${prev[*]}" ]]; then
break
fi
prev=("${curr[@]}")
tries=$((tries + 1))
sleep 1
done
### Print one device per line for mapfile compatibility
for dev in "${curr[@]}"; do
printf '%s\n' "${dev}"
done
}
#######################################
# Gather information of all NUKE Devices available on the system
# Globals:
# DEVICES_LUKS
# Arguments:
# None
#######################################
gather_nuke_devices() {
### 'DEVICES_LUKS' must already be a bash array of device paths
declare dev=""
declare result=()
for dev in "${DEVICES_LUKS[@]}"; do
### Check slot 31 for 'luks2'
if cryptsetup luksDump "${dev}" 2> /dev/null | grep -qE '^[[:space:]]*31: luks2'; then
result+=("${dev}")
fi
done
### Print one device per line for mapfile compatibility
for dev in "${result[@]}"; do
printf '%s\n' "${dev}"
done
}
#######################################
# Read passphrase interactively.
# Arguments:
# None
#######################################
passphrase_ask() {
declare -g PASSPHRASE=""
printf "\n"
stty -echo
printf "\e[0;95m🔐 Enter passphrase for decryption: \e[0m\n"
read -r PASSPHRASE
stty echo
printf "\n"
}
#######################################
# Test the entered passphrase against the dedicated Nuke Keyslot #31.
# Arguments:
# $1: DEVICE
# $2: PASSWD
#######################################
passphrase_test() {
declare -r DEVICE="$1"
declare -r PASPHR="$2"
printf '%s' "${PASPHR}" | cryptsetup open --batch-mode --test-passphrase --key-slot 31 "${DEVICE}" > /dev/null 2>&1
}
#######################################
# Check the integrity and authenticity of this script itself.
# Arguments:
# $0: Script Name
#######################################
verify_coresecret() {
### Directory of this script
# shellcheck disable=SC2155
declare dir="$(dirname "$(readlink -f "${0}")")"
# shellcheck disable=SC2155
declare script="$(basename "${0}")"
declare algo
for algo in sha512 sha384; do
# shellcheck disable=SC2155
declare hashfile="${dir}/${script}.${algo}"
# shellcheck disable=SC2155
declare sigfile="${hashfile}.sig"
# shellcheck disable=SC2155
declare cmd="${algo}sum"
printf "\e[0;95m🔏 Verifying signature of: [%s] \e[0m\n" "${hashfile}"
gpgv --keyring /etc/keys/pubring.gpg "${sigfile}" "${hashfile}" || {
printf "\e[0;91m✘ Signature verification failed for: [%s] \e[0m\n" "${hashfile}" >&2
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2
sync
sleep 3
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
}
printf "\e[0;92m🔏 Verifying signature of: [%s] successful. \e[0m\n" "${hashfile}"
printf "\e[0;95m🔢 Recomputing Hash: [%s] \e[0m\n" "${algo}"
# shellcheck disable=SC2155
declare computed=$($cmd "${dir}/${script}" | awk '{print $1}')
# shellcheck disable=SC2155
declare expected=$(cat "${hashfile}")
if [[ ${computed} != "${expected}" ]]; then
printf "\e[0;91m✘ Hash mismatch for: [%s] \e[0m\n" "${algo}" >&2
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2
sync
sleep 3
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
fi
printf "\e[0;92m🔢 Recomputing Hash: [%s] successful. \e[0m\n" "${algo}"
done
printf "\e[0;92m🔏 All signatures and hashes verified successfully. Proceeding. \e[0m\n"
}
### Main Programm
trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR
trap 'trap_on_term' INT TERM
printf "\e[0;91mCoresecret Connection established.\e[0m\n"
printf "\e[0;91mStarting Time: %s\e[0m\n" "${CURRENTDATE}"
printf "\n"
verify_coresecret
### Read newline-separated output into an array
mapfile -t DEVICES_LUKS < <(gather_luks_devices)
mapfile -t DEVICES_NUKE < <(gather_nuke_devices)
### Debug output: list each element with its index
#for idx in "${!DEVICES_LUKS[@]}"; do
# printf 'Luks[%d]: %s\n' "${idx}" "${DEVICES_LUKS[${idx}]}"
#done
### Debug output: list each element with its index
#for idx in "${!DEVICES_NUKE[@]}"; do
# printf 'Nuke[%d]: %s\n' "${idx}" "${DEVICES_NUKE[${idx}]}"
#done
### # If there are no LUKS devices at all, drop to bash
[[ -n ${DEVICES_LUKS[*]} ]] || {
printf "\e[0;92m✘ No LUKS Devices found. Dropping to bash ... \e[0m\n"
prompt_string
exec /bin/bash -i
}
### If there are LUKS devices but no Nuke devices, try unlocking flow
if [[ -n ${DEVICES_LUKS[*]} ]] && [[ -z ${DEVICES_NUKE[*]} ]]; then
### Attempt interactive unlock with cryptroot-unlock
if cryptroot-unlock; then
exit 0
else
printf "\n"
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
prompt_string
exec /bin/bash -i
fi
elif [[ -n ${DEVICES_LUKS[*]} ]] && [[ -n ${DEVICES_NUKE[*]} ]]; then
declare -i attempt=1
declare NUKED=false
declare TEST_DEV="${DEVICES_NUKE[0]}"
while ((attempt <= MAX_RETRIES)); do
printf "\e[0;95m🔐Attempt %s/%s: \e[0m\n" "${attempt}" "${MAX_RETRIES}"
passphrase_ask
declare -g PASSWD="${PASSPHRASE}"
if passphrase_test "${TEST_DEV}" "${PASSWD}"; then
for dev in "${DEVICES_NUKE[@]}"; do
cryptsetup erase --batch-mode "${dev}" > /dev/null 2>&1
printf "%s:\e[0;95m✘ LUKS Device Header malfunction. \e[0m\n" "${dev}"
done
declare -r NUKED=true
unset PASSWD
break
else
declare code="$?"
case "${code}" in
1) printf "\e[0;91m✘ No usable key slot is available. \e[0m\n" ;;
2) printf "\e[0;91m✘ No key available with this passphrase. \e[0m\n" ;;
3) printf "\e[0;93m✘ Out of memory. \e[0m\n" ;;
*) printf "\e[0;91m✘ Unexpected Return Code. \e[0m\n" ;;
esac
fi
attempt=$((attempt + 1))
done
if [[ ${NUKED} == true ]]; then
stty echo
sleep 3
sync
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
fi
if cryptroot-unlock; then
exit 0
else
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
prompt_string
exec /bin/bash -i
fi
fi
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -24,6 +24,7 @@ recipe:
firmware: "UEFI" # MUST be "UEFI" for "gpt" || "BIOS": firmware: "UEFI" # MUST be "UEFI" for "gpt" || "BIOS":
id: "guben0afx256r" # MUST be equal to the second part of the recipe-variables string. id: "guben0afx256r" # MUST be equal to the second part of the recipe-variables string.
name: "ciss.2025.gpt.btrfs.ephemeral.non-raid.256GiB.rescue" name: "ciss.2025.gpt.btrfs.ephemeral.non-raid.256GiB.rescue"
nuke: true # Activates Nuke-Mechanism in '/etc/crypttab' keyscript and via dropbear SSH forced command.
raid: # mdadm RAID settings only (not yet supported). raid: # mdadm RAID settings only (not yet supported).
enable: false enable: false
disks: disks:
@@ -44,7 +45,6 @@ recipe:
enable: false # MUST be "false" for "/boot/efi" enable: false # MUST be "false" for "/boot/efi"
ephemeral: false # MUST be "false" for "/boot/efi" ephemeral: false # MUST be "false" for "/boot/efi"
integrity: false # MUST be "false" for "/boot/efi" integrity: false # MUST be "false" for "/boot/efi"
nuke: false # MUST be "false" for "/boot/efi"
cipher: "" cipher: ""
hash: "" hash: ""
itertime: "" itertime: ""
@@ -79,7 +79,6 @@ recipe:
enable: true enable: true
ephemeral: false # MUST be "false" for "/boot" ephemeral: false # MUST be "false" for "/boot"
integrity: false # MUST be "false" for "/boot" integrity: false # MUST be "false" for "/boot"
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -114,7 +113,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: false
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -149,7 +147,6 @@ recipe:
enable: true # MUST be "true" for ephemeral "SWAP" enable: true # MUST be "true" for ephemeral "SWAP"
ephemeral: true # MUST be "true" for ephemeral "SWAP" ephemeral: true # MUST be "true" for ephemeral "SWAP"
integrity: false # MUST be "false" for ephemeral "SWAP" integrity: false # MUST be "false" for ephemeral "SWAP"
nuke: false # MUST be "false" for ephemeral "SWAP"
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -184,7 +181,6 @@ recipe:
enable: true # MUST be "true" for ephemeral "/tmp" enable: true # MUST be "true" for ephemeral "/tmp"
ephemeral: true # MUST be "true" for ephemeral "/tmp" ephemeral: true # MUST be "true" for ephemeral "/tmp"
integrity: false # MUST be "false" for ephemeral "/tmp" integrity: false # MUST be "false" for ephemeral "/tmp"
nuke: false # MUST be "false" for ephemeral "/tmp"
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -219,7 +215,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -254,7 +249,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -289,7 +283,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -324,7 +317,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -359,7 +351,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -394,7 +385,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -429,7 +419,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"
@@ -464,7 +453,6 @@ recipe:
enable: true enable: true
ephemeral: false ephemeral: false
integrity: false integrity: false
nuke: true
cipher: "aes-xts-plain64" cipher: "aes-xts-plain64"
hash: "sha512" hash: "sha512"
itertime: "3000" itertime: "3000"

View File

@@ -0,0 +1 @@
Ceterum_censeo_Bruxellam_et_Berolinum_delenda_esse!

View File

@@ -14,7 +14,7 @@ include_toc: true
This is an automatically generated overview of the secure ``Centurion Net`` ``CISS.debian.installer`` building system. This is an automatically generated overview of the secure ``Centurion Net`` ``CISS.debian.installer`` building system.
![Centurion Net](/docs/graphviz/ciss.debian.live.builder.png) ![Centurion Net](/docs/graphviz/ciss.debian.installer.png)
--- ---
**[no tracking | no logging | no advertising | no profiling | no bullshit](https://coresecret.eu/)** **[no tracking | no logging | no advertising | no profiling | no bullshit](https://coresecret.eu/)**

View File

@@ -0,0 +1,37 @@
// SPDX-Version: 3.0
// SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
// SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
// SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
// SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
// SPDX-FileType: SOURCE
// SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
// SPDX-Comment: This file is part of the CISS.debian.installer.secure framework.
// SPDX-PackageName: CISS.debian.installer
// SPDX-Security-Contact: security@coresecret.eu
digraph CISS_debian_installer_bootflow {
rankdir=LR;
node [shape=box, style=filled, fillcolor=lightgray, fontname="Helvetica"];
Initramfs [label="initramfs boot", fillcolor=lightblue];
Crypttab [label="/etc/crypttab", fillcolor=lightblue];
CryptrootScript [label="local-top/cryptroot", fillcolor=lightblue];
Cryptsetup [label="cryptsetup luksOpen", fillcolor=orange];
Keyscript [label="keyscript (e.g. nuke_aware.sh)", fillcolor=yellow];
Askpass [label="askpass (console/GUI/Dropbear)", fillcolor=white];
NukeCheck [label="if password matches NUKE_HASH → nuke()", fillcolor=red, fontcolor=white];
PASSPHRASEOut [label="printf '%s' \"$PASSPHRASE\" + exit 0", fillcolor=green];
Decryption [label="LUKS device unlocked", fillcolor=darkgreen, fontcolor=white];
RootFS [label="mount /dev/mapper/cryptroot → /", fillcolor=lightblue];
Initramfs -> Crypttab;
Crypttab -> CryptrootScript;
CryptrootScript -> Cryptsetup;
Cryptsetup -> Keyscript;
Keyscript -> Askpass;
Askpass -> NukeCheck;
NukeCheck -> PASSPHRASEOut [label="if no match"];
PASSPHRASEOut -> Cryptsetup [label="stdin"];
Cryptsetup -> Decryption;
Decryption -> RootFS;
}

View File

@@ -9,7 +9,7 @@
// SPDX-PackageName: CISS.debian.installer // SPDX-PackageName: CISS.debian.installer
// SPDX-Security-Contact: security@coresecret.eu // SPDX-Security-Contact: security@coresecret.eu
digraph CISS_debian_live_builder { digraph CISS_debian_installer {
// ----------------------------- // -----------------------------
// General settings // General settings
// ----------------------------- // -----------------------------

View File

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -44,8 +44,9 @@ yaml_parser() {
esac esac
done < "${VAR_PRESEED}" done < "${VAR_PRESEED}"
sed -i '/^software_[0-9]\+=/d' "${VAR_PRESEED}" sed -i '/^grub_parameter_[0-9]\+=/d' "${VAR_PRESEED}"
sed -i '/^ntp_server_[0-9]\+=/d' "${VAR_PRESEED}" sed -i '/^ntp_server_[0-9]\+=/d' "${VAR_PRESEED}"
sed -i '/^software_[0-9]\+=/d' "${VAR_PRESEED}"
### Substitute all key= by key="" ### Substitute all key= by key=""
sed -i -E 's/^(.*)=\s*$/\1=""/' "${VAR_PRESEED}" sed -i -E 's/^(.*)=\s*$/\1=""/' "${VAR_PRESEED}"

View File

@@ -47,10 +47,10 @@ yaml_reader() {
fi fi
done < "${var_if}" done < "${var_if}"
if [[ -n ${VAR_RECIPE_STRING} ]]; then if [[ -n "${VAR_RECIPE_STRING}" ]]; then
do_log "info" "false" "Found active recipe string: '${VAR_RECIPE_STRING}'." do_log "info" "true" "Found active recipe string: '${VAR_RECIPE_STRING}'."
else else
do_log "fatal" "false" "Found NO active recipe string: '${VAR_RECIPE_STRING}'." >&2 do_log "fatal" "true" "Found NO active recipe string: '${VAR_RECIPE_STRING}'." >&2
exit "${ERR_NO_VALID_RECIPE}" exit "${ERR_NO_VALID_RECIPE}"
fi fi
@@ -79,9 +79,9 @@ END { print max }
declare -gx VAR_RECIPE_DEV_COUNTER="${var_highest_dev}" declare -gx VAR_RECIPE_DEV_COUNTER="${var_highest_dev}"
if [[ -n ${VAR_RECIPE_DEV_COUNTER} ]]; then if [[ -n ${VAR_RECIPE_DEV_COUNTER} ]]; then
do_log "info" "false" "Found highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'." do_log "info" "true" "Found highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'."
else else
do_log "fatal" "false" "Found NO highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'." >&2 do_log "fatal" "true" "Found NO highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'." >&2
exit "${ERR_NO_VALID_RECIPE}" exit "${ERR_NO_VALID_RECIPE}"
fi fi
@@ -115,6 +115,10 @@ END { print max }
do_log "info" "false" "Highest number of partitions for ${var_device}: ${HMP_RECIPE_DEV_PARTITIONS[${var_device}]}" do_log "info" "false" "Highest number of partitions for ${var_device}: ${HMP_RECIPE_DEV_PARTITIONS[${var_device}]}"
done done
### Extract the chosen Nuke mechanism
declare recipe_nuke_var="recipe_${VAR_RECIPE_STRING}_control_nuke"
declare -gx VAR_NUKE="${!recipe_nuke_var}"
### Extract chosen partition table ### Extract chosen partition table
declare recipe_table_var="recipe_${VAR_RECIPE_STRING}_control_table" declare recipe_table_var="recipe_${VAR_RECIPE_STRING}_control_table"
declare -gx VAR_RECIPE_TABLE="${!recipe_table_var}" declare -gx VAR_RECIPE_TABLE="${!recipe_table_var}"

View File

@@ -34,10 +34,10 @@ partition_encryption() {
### Declare Arrays and Variables. ### Declare Arrays and Variables.
declare -Agx HMP_EPHEMERAL_DEV HMP_EPHEMERAL_ENCLABEL HMP_EPHEMERAL_FS_LABEL HMP_PATH_LUKSUUID HMP_PATH_ENCLABEL declare -Agx HMP_EPHEMERAL_DEV HMP_EPHEMERAL_ENCLABEL HMP_EPHEMERAL_FS_LABEL HMP_PATH_LUKSUUID HMP_PATH_ENCLABEL
declare var_dev var_part \ declare var_dev var_part \
var_encryption_enable var_encryption_ephemeral var_encryption_integrity var_encryption_nuke var_encryption_cipher \ var_encryption_enable var_encryption_ephemeral var_encryption_integrity var_encryption_cipher \
var_encryption_hash var_encryption_iter var_encryption_key var_encryption_label var_encryption_meta \ var_encryption_hash var_encryption_iter var_encryption_key var_encryption_label var_encryption_meta \
var_encryption_pbkdf var_encryption_rng var_filesystem_label var_mount_path var_uuid var_encryption_pbkdf var_encryption_rng var_filesystem_label var_mount_path var_uuid
declare -a ary_devs ary_parts declare -a ary_devs=() ary_parts=() ary_luks_opts=()
### Iterate over all devices in the recipe. ### Iterate over all devices in the recipe.
readarray -t ary_devs < <(yq e -r ".recipe.${VAR_RECIPE_STRING}.dev | keys | .[]" "${VAR_SETUP_PART}") readarray -t ary_devs < <(yq e -r ".recipe.${VAR_RECIPE_STRING}.dev | keys | .[]" "${VAR_SETUP_PART}")
@@ -51,7 +51,6 @@ partition_encryption() {
var_encryption_enable=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.enable" "${VAR_SETUP_PART}") var_encryption_enable=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.enable" "${VAR_SETUP_PART}")
var_encryption_ephemeral=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.ephemeral" "${VAR_SETUP_PART}") var_encryption_ephemeral=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.ephemeral" "${VAR_SETUP_PART}")
var_encryption_integrity=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.integrity" "${VAR_SETUP_PART}") var_encryption_integrity=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.integrity" "${VAR_SETUP_PART}")
var_encryption_nuke=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.nuke" "${VAR_SETUP_PART}")
var_encryption_cipher=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.cipher" "${VAR_SETUP_PART}") var_encryption_cipher=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.cipher" "${VAR_SETUP_PART}")
var_encryption_hash=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.hash" "${VAR_SETUP_PART}") var_encryption_hash=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.hash" "${VAR_SETUP_PART}")
var_encryption_iter=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.itertime" "${VAR_SETUP_PART}") var_encryption_iter=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.itertime" "${VAR_SETUP_PART}")
@@ -67,21 +66,26 @@ partition_encryption() {
continue continue
fi fi
declare -a ary_luks_opts=( if [[ "${var_mount_path,,}" == "/boot" ]]; then
--key-file="${DIR_CNF}/password.txt" ary_luks_opts=( "--key-file=${DIR_CNF}/password_luks_boot.txt" )
--type luks2 else
--cipher "${var_encryption_cipher}" ary_luks_opts=( "--key-file=${DIR_CNF}/password_luks_common.txt" )
--hash "${var_encryption_hash}" fi
--iter-time "${var_encryption_iter}"
--key-size "${var_encryption_key}" ary_luks_opts+=(
--label "${var_encryption_label}" "--type luks2"
--luks2-metadata-size "${var_encryption_meta}" "--cipher ${var_encryption_cipher}"
--pbkdf "${var_encryption_pbkdf}" "--hash ${var_encryption_hash}"
--"${var_encryption_rng}" "--iter-time ${var_encryption_iter}"
--batch-mode --verbose "--key-size ${var_encryption_key}"
"--label ${var_encryption_label}"
"--luks2-metadata-size ${var_encryption_meta}"
"--pbkdf ${var_encryption_pbkdf}"
"--${var_encryption_rng}"
"--batch-mode --verbose"
) )
[[ "${var_encryption_integrity,,}" == "true" ]] && ary_luks_opts+=(--integrity hmac-sha512) [[ "${var_encryption_integrity,,}" == "true" ]] && ary_luks_opts+=( "--integrity hmac-sha512" )
if [[ "${var_encryption_ephemeral,,}" == "true" ]]; then if [[ "${var_encryption_ephemeral,,}" == "true" ]]; then
@@ -113,22 +117,28 @@ partition_encryption() {
if [[ "${var_encryption_integrity,,}" == "true" ]]; then if [[ "${var_encryption_integrity,,}" == "true" ]]; then
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' dm-integrity encrypted." do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' dm-integrity encrypted."
else else
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' encrypted." do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' encrypted."
fi fi
cryptsetup luksHeaderBackup --header-backup-file="${DIR_BAK}/luks_header_${var_dev}${var_part}.bak" "/dev/${var_dev}${var_part}" cryptsetup luksHeaderBackup --header-backup-file="${DIR_BAK}/luks_header_${var_dev}${var_part}.bak" "/dev/${var_dev}${var_part}"
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' LUKS Header saved: '${DIR_BAK}/luks_header_${var_dev}${var_part}.bak'." do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' LUKS Header saved: '${DIR_BAK}/luks_header_${var_dev}${var_part}.bak'."
### Opening encrypted container. ### Opening encrypted container.
if [[ "${var_mount_path,,}" == "/boot" ]]; then
cryptsetup luksOpen "/dev/${var_dev}${var_part}" \ cryptsetup luksOpen "/dev/${var_dev}${var_part}" \
--key-file="${DIR_CNF}/password.txt" \ --key-file="${DIR_CNF}/password_luks_boot.txt" \
"${var_encryption_label}" "${var_encryption_label}"
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' opened as '/dev/mapper/${var_encryption_label}'." else
cryptsetup luksOpen "/dev/${var_dev}${var_part}" \
--key-file="${DIR_CNF}/password_luks_common.txt" \
"${var_encryption_label}"
fi
do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' opened as '/dev/mapper/${var_encryption_label}'."
### Store UUID of the LUKS container. ### Store UUID of the LUKS container.
var_uuid=$(blkid -s UUID -o value "/dev/mapper/${var_encryption_label}") var_uuid=$(blkid -s UUID -o value "/dev/mapper/${var_encryption_label}")

View File

@@ -39,6 +39,7 @@ write_crypttab() {
# HMP_PATH_ENCLABEL # HMP_PATH_ENCLABEL
# HMP_PATH_LUKSUUID # HMP_PATH_LUKSUUID
# TARGET # TARGET
# VAR_NUKE
# dropbear_boot # dropbear_boot
# Arguments: # Arguments:
# None # None
@@ -49,6 +50,7 @@ generate_crypttab() {
declare var_key var_encryption_label var_luks_uuid declare var_key var_encryption_label var_luks_uuid
### Generate '${TARGET}/etc/crypttab' header. ### Generate '${TARGET}/etc/crypttab' header.
install -d -m 0755 "${TARGET}/etc"
: >| "${TARGET}/etc/crypttab" : >| "${TARGET}/etc/crypttab"
chmod 0600 "${TARGET}/etc/crypttab" chmod 0600 "${TARGET}/etc/crypttab"
@@ -79,6 +81,13 @@ EOF
if [[ "${dropbear_boot,,}" == "true" ]]; then if [[ "${dropbear_boot,,}" == "true" ]]; then
if [[ "${VAR_NUKE,,}" == "true" && "${var_key,,}" == "/" ]]; then
write_crypttab "${var_encryption_label}" "UUID=${var_luks_uuid}" "none" "luks,discard,initramfs,keyscript=/lib/cryptsetup/scripts/unlock_wrapper.sh"
continue
fi
write_crypttab "${var_encryption_label}" "UUID=${var_luks_uuid}" "none" "luks,discard,initramfs" write_crypttab "${var_encryption_label}" "UUID=${var_luks_uuid}" "none" "luks,discard,initramfs"
else else
@@ -98,14 +107,13 @@ EOF
case "${var_key}" in case "${var_key}" in
SWAP) SWAP)
write_crypttab "${var_ephemeral_enclabel}" "LABEL=${var_ephemeral_fs_label}" "/dev/random" "swap,offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096" write_crypttab "${var_ephemeral_enclabel}" "LABEL=${var_ephemeral_fs_label}" "/dev/random" "swap,offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096"
continue
;; ;;
/tmp) /tmp)
write_crypttab "${var_ephemeral_enclabel}" "LABEL=${var_ephemeral_fs_label}" "/dev/random" "offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096,tmp=ext4" write_crypttab "${var_ephemeral_enclabel}" "LABEL=${var_ephemeral_fs_label}" "/dev/random" "offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096,tmp=ext4"
continue
;; ;;
*) *)
do_log "error" "false" "Only 'SWAP' and '/tmp' are valid Partitions for Ephemeral Encryption. Given value was: '${var_key}'." do_log "error" "false" "Only 'SWAP' and '/tmp' are valid Partitions for Ephemeral Encryption. Given value was: '${var_key}'."
continue
;; ;;
esac esac

View File

@@ -58,16 +58,16 @@ setup_network() {
declare -a ary_ipv4_ns ary_ipv6_ns declare -a ary_ipv4_ns ary_ipv6_ns
ary_ipv4_ns+=("${network_static_ipv4nameserver_0}") ary_ipv4_ns+=("${network_static_ipv4nameserver_0}")
[[ -v "${network_static_ipv4nameserver_1}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_1}") [[ -v network_static_ipv4nameserver_1 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_1}")
[[ -v "${network_static_ipv4nameserver_2}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_2}") [[ -v network_static_ipv4nameserver_2 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_2}")
[[ -v "${network_static_ipv4nameserver_fallback_0}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_0}") [[ -v network_static_ipv4nameserver_fallback_0 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_0}")
[[ -v "${network_static_ipv4nameserver_fallback_1}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_1}") [[ -v network_static_ipv4nameserver_fallback_1 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_1}")
ary_ipv6_ns+=("${network_static_ipv6nameserver_0}") ary_ipv6_ns+=("${network_static_ipv6nameserver_0}")
[[ -v "${network_static_ipv6nameserver_1}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_1}") [[ -v network_static_ipv6nameserver_1 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_1}")
[[ -v "${network_static_ipv6nameserver_2}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_2}") [[ -v network_static_ipv6nameserver_2 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_2}")
[[ -v "${network_static_ipv6nameserver_fallback_0}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_0}") [[ -v network_static_ipv6nameserver_fallback_0 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_0}")
[[ -v "${network_static_ipv6nameserver_fallback_1}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_1}") [[ -v network_static_ipv6nameserver_fallback_1 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_1}")
### Check current network connection and configure variables ### Check current network connection and configure variables
var_auto_nic=$(ip -o link show | awk -F': ' '/state UP/ && $2!="lo" {print $2; exit}') var_auto_nic=$(ip -o link show | awk -F': ' '/state UP/ && $2!="lo" {print $2; exit}')

View File

@@ -118,7 +118,7 @@ GRUB_BACKGROUND="/etc/default/grub.d/${var_background}"
# The resolution used on graphical terminal # The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE # note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command 'vbeinfo' # you can see them in real GRUB with the command 'vbeinfo'
GRUB_GFXMODE=1920x1080,1280x1024,800x600 GRUB_GFXMODE=1920x1080,1280x1024,1024x768,800x600
GRUB_GFXPAYLOAD_LINUX=keep GRUB_GFXPAYLOAD_LINUX=keep
EOF EOF
@@ -166,6 +166,11 @@ EOF
[[ "${var_update_grub_required}" == "true" ]] && do_in_target "${TARGET}" update-grub [[ "${var_update_grub_required}" == "true" ]] && do_in_target "${TARGET}" update-grub
### Setting the permissions to read and write for root only prevents non-root users from seeing the boot parameters or changing them.
chown root:root "${TARGET}/boot/grub/grub.cfg"
chmod 0600 "${TARGET}/boot/grub/grub.cfg"
chmod -R 0700 "${TARGET}/etc/grub.d"
return 0 return 0
} }
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -0,0 +1,95 @@
#!/bin/bash
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu
guard_sourcing
#######################################
# Append GRUB superuser block to 40_custom.
# Arguments:
# 1: Username
# 2: Password
#######################################
#######################################
# Append GRUB superuser block to '/etc/grub.d/40_custom'.
# Globals:
# DIR_CNF
# ERR_READ_GRUB_FILE
# TARGET
# VAR_DEBUG_TRACE
# Arguments:
# None
# Returns:
# 0: on success
# ERR_READ_GRUB_FILE
#######################################
setup_grub_password() {
declare var_username="superadmin"
declare var_password=""
declare var_password_file="${DIR_CNF}/password_grub.txt"
declare var_of="${TARGET}/etc/grub.d/40_custom"
declare var_grub_entry
### No tracing for security reasons
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set +x
if [[ ! -f "${var_password_file}" ]] || ! IFS= read -r var_password < "${var_password_file}"; then
return "${ERR_READ_GRUB_FILE}"
fi
### Turn on tracing again
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set -x
var_grub_entry=$(generate_grub_password_pbkdf2 "${var_username}" "${var_password}")
### Append if not already present
if ! grep -q "set superusers=" "${var_of}"; then
{
echo ""
echo "### Added by CISS.debian.installer ###"
echo "$var_grub_entry"
echo "### End by CISS.debian.installer ###"
} >> "$var_of"
fi
do_in_target "${TARGET}" update-grub
return 0
}
#######################################
# Generate PBKDF2 password hash for GRUB.
# Arguments:
# 1: Username (default to superadmin).
# 2: User password.
# Returns:
# 0: on success
#######################################
generate_grub_password_pbkdf2() {
declare var_user="${1:-superadmin}"
declare var_pass="${2:?error: password required}"
expect <<EOF
log_user 0
spawn grub-mkpasswd-pbkdf2
expect "Enter password:"
send "$var_pass\r"
expect "Reenter password:"
send "$var_pass\r"
expect {
-re {PBKDF2 hash of your password is (\S+)} {
puts "set superusers=\"$var_user\"\npassword_pbkdf2 $var_user \$expect_out(1,string)"
}
}
EOF
return 0
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -27,7 +27,7 @@ guard_sourcing
# 0: on success # 0: on success
####################################### #######################################
setup_grub_bootparameter() { setup_grub_bootparameter() {
declare var_param declare var_nuke_string="" var_param=""
grub_extract_current_string grub_extract_current_string
@@ -47,6 +47,11 @@ setup_grub_bootparameter() {
done done
if [[ "${VAR_NUKE}" == "true" ]]; then
var_nuke_string="nuke=${VAR_NUKE_HASH}"
VAR_GRUB_CMDLINE_LINUX+=" ${var_nuke_string}"
fi
grub_finalize_string grub_finalize_string
do_in_target "${TARGET}" update-grub do_in_target "${TARGET}" update-grub

View File

@@ -10,9 +10,6 @@
# SPDX-PackageName: CISS.debian.installer # SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu # SPDX-Security-Contact: security@coresecret.eu
### Options in "GRUB_CMDLINE_LINUX" are always effective.
### Options in "GRUB_CMDLINE_LINUX_DEFAULT" are effective ONLY during normal boot (NOT during recovery mode).
guard_sourcing guard_sourcing
####################################### #######################################
@@ -28,6 +25,13 @@ setup_kernel_modules() {
### Entropy collection improvements ### Entropy collection improvements
mkdir -p "${TARGET}/usr/lib/modules-load.d" mkdir -p "${TARGET}/usr/lib/modules-load.d"
cat << EOF >| "${TARGET}/usr/lib/modules-load.d/30_security-misc.conf" cat << EOF >| "${TARGET}/usr/lib/modules-load.d/30_security-misc.conf"
## The jitterentropy_rng kernel module provides a reliable and hardware-independent source of cryptographic entropy by measuring
## minute variations in CPU execution timing (jitter). These microsecond-level differences are unpredictable and rooted in
## physical randomness, making them suitable for high-quality entropy generation. Unlike other RNG methods that rely on hardware
## features like TPMs or Intel's RDRAND—which may not be available or trusted—jitterentropy_rng works across all platforms,
## including virtual machines and air-gapped systems. It is compliant with NIST SP 800-90B and BSI TR-02102-4, ensuring secure
## entropy even during early boot stages, such as in initramfs or before full userland is available. It is the most secure,
## standards-compliant, and universally applicable entropy source for hardened Linux environments.
## https://www.whonix.org/wiki/Dev/Entropy ## https://www.whonix.org/wiki/Dev/Entropy
## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927972 ## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927972
## https://forums.whonix.org/t/jitterentropy-rngd/7204 ## https://forums.whonix.org/t/jitterentropy-rngd/7204
@@ -37,4 +41,21 @@ EOF
do_log "info" "true" "Installed: '/usr/lib/modules-load.d/30_security-misc.conf'." do_log "info" "true" "Installed: '/usr/lib/modules-load.d/30_security-misc.conf'."
return 0 return 0
} }
#######################################
# Blacklist some kind of potential hazardous modules via '/etc/modprobe.d/0000_ciss_debian_installer.conf'.
# Globals:
# TARGET
# VAR_SETUP_PATH
# Arguments:
# None
# Returns:
# 0: on success
#######################################
setup_modprobe() {
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/etc/modprobe.d/0000_ciss_debian_installer.cnf" \
"${TARGET}/etc/modprobe.d/0000_ciss_debian_installer.conf"
do_log "info" "true" "Installed: '/etc/modprobe.d/0000_ciss_debian_installer.conf'."
return 0
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -10,9 +10,6 @@
# SPDX-PackageName: CISS.debian.installer # SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu # SPDX-Security-Contact: security@coresecret.eu
### Options in "GRUB_CMDLINE_LINUX" are always effective.
### Options in "GRUB_CMDLINE_LINUX_DEFAULT" are effective ONLY during normal boot (NOT during recovery mode).
guard_sourcing guard_sourcing
####################################### #######################################

View File

@@ -53,9 +53,9 @@ setup_dropbear() {
### Prepare dropbear authorized_keys ### Prepare dropbear authorized_keys
declare -a ary_user=() declare -a ary_user=()
ary_user+=("${user_root_ssh_pubkeys_0}") ary_user+=("${user_root_ssh_pubkeys_0}")
[[ -v "${user_root_ssh_pubkeys_1}" ]] && ary_user+=("${user_root_ssh_pubkeys_1}") [[ -v user_root_ssh_pubkeys_1 ]] && ary_user+=("${user_root_ssh_pubkeys_1}")
[[ -v "${user_root_ssh_pubkeys_2}" ]] && ary_user+=("${user_root_ssh_pubkeys_2}") [[ -v user_root_ssh_pubkeys_2 ]] && ary_user+=("${user_root_ssh_pubkeys_2}")
[[ -v "${user_root_ssh_pubkeys_3}" ]] && ary_user+=("${user_root_ssh_pubkeys_3}") [[ -v user_root_ssh_pubkeys_3 ]] && ary_user+=("${user_root_ssh_pubkeys_3}")
touch "${TARGET}/etc/dropbear/initramfs/authorized_keys" && chmod 0600 "${TARGET}/etc/dropbear/initramfs/authorized_keys" touch "${TARGET}/etc/dropbear/initramfs/authorized_keys" && chmod 0600 "${TARGET}/etc/dropbear/initramfs/authorized_keys"
printf "%s\n" "${ary_user[@]}" > "${TARGET}/etc/dropbear/initramfs/authorized_keys" printf "%s\n" "${ary_user[@]}" > "${TARGET}/etc/dropbear/initramfs/authorized_keys"
@@ -106,6 +106,8 @@ setup_dropbear() {
### Install the script to be called inside initramfs environment for unlocking LUKS and NUKE Devices. ### Install the script to be called inside initramfs environment for unlocking LUKS and NUKE Devices.
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper.sh" \ install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper.sh" \
"${TARGET}/includes/initramfs-tools/files/" "${TARGET}/includes/initramfs-tools/files/"
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper.sh" \
"${TARGET}/usr/lib/cryptsetup/scripts/"
### Install the script to be called inside Host environment for signing 'unlock_wrapper.sh'-script. ### Install the script to be called inside Host environment for signing 'unlock_wrapper.sh'-script.
install -D -m 0700 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper_signer.sh" \ install -D -m 0700 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper_signer.sh" \
@@ -131,7 +133,7 @@ EOF
### Install the variable file to be called inside initramfs environment for setting up dropbear firewall. ### Install the variable file to be called inside initramfs environment for setting up dropbear firewall.
install -D -m 0600 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/dropbear_fw.cnf" \ install -D -m 0600 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/dropbear_fw.cnf" \
"${TARGET}/includes/initramfs-tools/files/" "${TARGET}/includes/initramfs-tools/files/dropbear_fw.conf"
### Install the firewall script to be called inside initramfs environment for setting up dropbear firewall. ### Install the firewall script to be called inside initramfs environment for setting up dropbear firewall.
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/dropbear_fw.sh" \ install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/dropbear_fw.sh" \
@@ -169,6 +171,8 @@ EOF
# 0: on success # 0: on success
####################################### #######################################
write_dropbear_conf() { write_dropbear_conf() {
[[ -z "${dropbear_port:-}" ]] && dropbear_port="2222"
cat << EOF >| "${TARGET}/etc/dropbear/initramfs/dropbear.conf" cat << EOF >| "${TARGET}/etc/dropbear/initramfs/dropbear.conf"
# #
# Configuration options for the dropbear-initramfs boot scripts. # Configuration options for the dropbear-initramfs boot scripts.
@@ -185,7 +189,7 @@ write_dropbear_conf() {
# -K: Keepalive interval in seconds # -K: Keepalive interval in seconds
# -p: Specify port (and optionally address) # -p: Specify port (and optionally address)
# -w: Disable root login (SHOULD NOT be implemented for initramfs) # -w: Disable root login (SHOULD NOT be implemented for initramfs)
DROPBEAR_OPTIONS="-b /etc/dropbear/initramfs/banner -c /usr/local/bin/unlock_wrapper.sh -E -I 300 -K 60 -p ${dropbear_port:-2222}" DROPBEAR_OPTIONS="-b /etc/dropbear/banner -c /usr/local/bin/unlock_wrapper.sh -E -I 300 -K 60 -p ${dropbear_port}"
# #
# On local (non-NFS) mounts, interfaces matching this pattern are # On local (non-NFS) mounts, interfaces matching this pattern are

View File

@@ -0,0 +1,124 @@
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu
### Version Master V8.03.864.2025.07.15
# The kernel allows unprivileged users to indirectly cause certain modules to be loaded via module auto-loading. This allows an
# attacker to auto-load a vulnerable module which is then exploited. One such example is CVE-2017-6074, in which an attacker
# could trigger the DCCP kernel module to be loaded by initiating a DCCP connection and then exploit a vulnerability in said
# kernel module. Specific kernel modules can be blacklisted by inserting files into '/etc/modprobe.d' with instructions on which
# kernel modules to blacklist.
##### Disable Uncommon Network Protocols #####
install dccp /bin/true
install sctp /bin/true
install rds /bin/true
install tipc /bin/true
install n-hdlc /bin/true
install ax25 /bin/true
install netrom /bin/true
install x25 /bin/true
install rose /bin/true
install decnet /bin/true
install econet /bin/true
install af_802154 /bin/true
install ipx /bin/true
install appletalk /bin/true
install psnap /bin/true
install p8023 /bin/true
install p8022 /bin/true
install can /bin/true
install atm /bin/true
# DCCP Datagram Congestion Control Protocol
# SCTP Stream Control Transmission Protocol
# RDS Reliable Datagram Sockets
# TIPC Transparent Inter-process Communication
# HDLC High-Level Data Link Control
# AX25 Amateur X.25
# NetRom
# X25
# ROSE
# DECnet
# Econet
# af_802154 IEEE 802.15.4
# IPX Internetwork Packet Exchange
# AppleTalk
# PSNAP Subnetwork Access Protocol
# p8023 Novell raw IEEE 802.3
# p8022 IEEE 802.2
# CAN Controller Area Network
# ATM
##### Disable Uncommon Filesystems #####
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true
blacklist cramfs
blacklist freevxfs
blacklist jffs2
blacklist hfs
blacklist hfsplus
blacklist squashfs
blacklist udf
##### Disable Uncommon Network Filesystems #####
install cifs /bin/true
install nfs /bin/true
install nfsv3 /bin/true
install nfsv4 /bin/true
install ksmbd /bin/true
install gfs2 /bin/true
blacklist cifs
blacklist nfs
blacklist nfsv3
blacklist nfsv4
blacklist ksmbd
blacklist gfs2
# The vivid driver is only useful for testing purposes and has been the cause of privilege escalation vulnerabilities, so it should be disabled.
install vivid /bin/true
##### Disable access to USB #####
install usb_storage /bin/true
blacklist usb-storage
##### Disable access to IEEE1394 #####
install firewire-core /bin/true
##### Blacklist automatic loading of miscellaneous modules #####
##### https://git.launchpad.net/ubuntu/+source/kmod/tree/debian/modprobe.d/blacklist.conf?h=ubuntu/disco #####
# evbug is a debug tool that should be loaded explicitly
blacklist evbug
# these drivers are very simple
blacklist usbmouse
blacklist usbkbd
# causes no end of confusion by creating unexpected network interfaces
blacklist eth1394
# ugly and loud noise, getting on everyone's nerves
blacklist pcspkr
# Descriptions partly Copyright (c) 2022 madaidan, https://madaidans-insecurities.github.io/index.html
# Descriptions partly Copyright https://git.launchpad.net/ubuntu/+source/kmod/tree/debian/modprobe.d/blacklist.conf?h=ubuntu/disco
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf

View File

@@ -9,14 +9,184 @@
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework. # SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.installer # SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu # SPDX-Security-Contact: security@coresecret.eu
# SPDX-Comment: unlock_wrapper.sh to be executed after dropbear SSH login as forced command # SPDX-Comment: unlock_wrapper.sh to be executed as '/etc/crypttab' keyscript and as dropbear SSH forced command.
set -Ceuo pipefail set -Ceuo pipefail
IFS=$(printf ' \n\t')
#######################################
# Variable declaration
#######################################
declare -r ASKPASS='/lib/cryptsetup/askpass'
declare -r REGEX='^\$[a-z0-9]+\$[./A-Za-z0-9]+\$[./A-Za-z0-9]+$'
# shellcheck disable=SC2155 # shellcheck disable=SC2155
declare -gr CURRENTDATE=$(date +"%F %T") declare -r CURRENTDATE=$(date +"%F %T")
declare -gir MAX_RETRIES=2 declare -r GRE='\e[0;92m'
declare -r MAG='\e[0;95m'
declare -r RED='\e[0;91m'
declare -r RES='\e[0m'
declare -r NL='\n'
declare -g NUKE_ENABLED='false'
declare -g NUKE_HASH=''
declare -g PASSPHRASE=''
#######################################
# Print-colored text.
# Arguments:
# 1: Color code.
# *: Text to print.
#######################################
color_echo() { declare c="$1"; shift; declare msg="${*}"; printf "%s%s %s%s" "${c}" "${msg}" "${RES}" "${NL}"; }
#######################################
# Die helper: print and exit hard.
# Globals:
# NC
# RED
# Arguments:
# 1: Message string to print.
#######################################
die() { printf "%s✘ %s%s\n" "${RED}" "$1" "${RES}" >&2; power_off 3; }
#######################################
# Drop to bash environment.
# Arguments:
# None
#######################################
drop_bash() { stty echo; prompt_string; exec /bin/bash -i; }
#######################################
# Extract the 'nuke='-parameter from '/proc/cmdline'.
# Globals:
# NUKE_ENABLED
# NUKE_HASH
# RED
# Arguments:
# None
# Returns:
# 0: if 'nuke=' was found and extracted.
# 1: if not found.
#######################################
extract_nuke_hash() {
declare ARG="" CMDLINE=""
### Read '/proc/cmdline' into a single line safely.
read -r CMDLINE < /proc/cmdline
for ARG in ${CMDLINE}; do
case "${ARG}" in
nuke=*)
NUKE_HASH="${ARG#nuke=}"
if [[ "${NUKE_HASH}" =~ ${REGEX} ]]; then
NUKE_ENABLED="true"
return 0
else
### If there is a malformed Grub Bootparameter 'nuke=HASH', drop to bash.
color_echo "${RED}" "✘ Nuke Hash Malformat : [${REGEX}] [${NUKE_HASH}]." >&2
color_echo "${RED}" "✘ Dropping to bash ...:" >&2
drop_bash
fi
;;
esac
done
### No 'nuke=HASH' entry found.
return 1
}
#######################################
# Gather information of all LUKS Devices available on the system.
# Arguments:
# None
#######################################
gather_luks_devices() {
declare prev=() curr=()
declare -i tries=0
while ((tries < 10)); do
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device | sort)
if cmp <(printf '%s\n' "${curr[@]}") <(printf '%s\n' "${prev[@]}") >/dev/null; then
break
fi
prev=("${curr[@]}")
tries=$((tries + 1))
sleep 1
done
printf '%s\n' "${curr[@]}"
}
#######################################
# Erase LUKS headers on all LUKS devices and shutdown system.
# Globals:
# DEVICES_LUKS
# RED
# Arguments:
# None
#######################################
nuke() {
declare dev=""
for dev in "${DEVICES_LUKS[@]}"; do
cryptsetup erase --batch-mode "${dev}" || true
color_echo "${RED}" "✘ Error: LUKS Device Header malfunction: [${dev}]."
done
secure_unset_pass
color_echo "${RED}" "✘ Error: LUKS Device malfunction. System Power Off in 16 seconds."
power_off 16
}
#######################################
# Unified power-off routine.
# Arguments:
# 1: Sleep time before power-off in seconds (Default to 0 seconds).
#######################################
power_off() {
declare -r wait="${1:-0}"
sleep "${wait}"
sync
echo 1 >| /proc/sys/kernel/sysrq
echo o >| /proc/sysrq-trigger
### The System powers off immediately; no further code is executed.
}
#######################################
# Print Error Message for Trap on 'ERR' on Terminal.
# Globals:
# NL
# RED
# Arguments:
# 1: ${?}
# 2: ${BASH_SOURCE[0]}
# 3: ${LINENO}
# 4: ${FUNCNAME[0]:-main}
# 5: ${BASH_COMMAND}
#######################################
print_scr_err() {
declare -r scr_err_errcode="$1"
declare -r scr_err_errscrt="$2"
declare -r scr_err_errline="$3"
declare -r scr_err_errfunc="$4"
declare -r scr_err_errcmmd="$5"
printf "%s" "${NL}"
color_echo "${RED}" "✘ System caught an 'ERROR'. System Power Off in 16 seconds." >&2
printf "%s" "${NL}"
color_echo "${RED}" "✘ Error : [${scr_err_errcode}]" >&2
color_echo "${RED}" "✘ Line : [${scr_err_errline}]" >&2
color_echo "${RED}" "✘ Script : [${scr_err_errscrt}]" >&2
color_echo "${RED}" "✘ Function : [${scr_err_errfunc}]" >&2
color_echo "${RED}" "✘ Command : [${scr_err_errcmmd}]" >&2
printf "%s" "${NL}"
}
#######################################
# Print Error Message for '0'-Exit-Code on Terminal.
# Globals:
# GRE
# Arguments:
# None
#######################################
print_scr_scc() { color_echo "${GRE}" "✅ Script exited successfully. Proceeding with booting."; }
####################################### #######################################
# Generates informative shell prompt. # Generates informative shell prompt.
@@ -40,14 +210,56 @@ fi)\
|~\$ " |~\$ "
} }
#######################################
# Read Passphrase interactively.
# Globals:
# ASKPASS
# NUKE_ENABLED
# NUKE_HASH
# PASSPHRASE
# Arguments:
# None
# Returns:
# 0: on success
#######################################
read_passphrase() {
declare -a METHODS=("sha512crypt" "yescrypt" "scrypt" "bcrypt")
declare METHOD="" SALT=""
PASSPHRASE="$(${ASKPASS} "Enter passphrase: ")"
if [[ "${NUKE_ENABLED,,}" == 'true' ]]; then
### Validate NUKE_HASH format (e.g., $id$salt$hash)
if [[ "${NUKE_HASH}" =~ ${REGEX} ]]; then
SALT="$(cut -d'$' -f3 <<< "${NUKE_HASH}")"
for METHOD in "${METHODS[@]}"; do
if mkpasswd -m "${METHOD}" -S "${SALT}" "${PASSPHRASE}" 2>/dev/null | grep -qF -- "${NUKE_HASH}"; then
nuke
fi
done
fi
fi
return 0
}
#######################################
# Securely unset the passphrase variable.
# Globals:
# PASSPHRASE
# Arguments:
# None
#######################################
secure_unset_pass() { unset PASSPHRASE; PASSPHRASE=""; }
####################################### #######################################
# Trap function to be called on 'ERR'. # Trap function to be called on 'ERR'.
# Arguments: # Arguments:
# $1: ${?} # 1: ${?}
# $2: ${BASH_SOURCE[0]} # 2: ${BASH_SOURCE[0]}
# $3: ${LINENO} # 3: ${LINENO}
# $4: ${FUNCNAME[0]:-main} # 4: ${FUNCNAME[0]:-main}
# $5: ${BASH_COMMAND} # 5: ${BASH_COMMAND}
####################################### #######################################
trap_on_err() { trap_on_err() {
declare -r errcode="$1" declare -r errcode="$1"
@@ -55,322 +267,127 @@ trap_on_err() {
declare -r errline="$3" declare -r errline="$3"
declare -r errfunc="$4" declare -r errfunc="$4"
declare -r errcmmd="$5" declare -r errcmmd="$5"
trap - ERR trap - ERR INT TERM
stty echo stty echo
if [[ ${errcode} -eq 0 ]]; then
print_scr_scc
prompt_string
exit 0
else
print_scr_err "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}" print_scr_err "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}"
sleep 15 power_off 16
sync
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
fi
} }
####################################### #######################################
# Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the Nuke Routine # Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the nuke routine.
# Globals: # Globals:
# DEVICES_LUKS # NL
# DEVICES_NUKE # RED
# Arguments: # Arguments:
# None # None
####################################### #######################################
trap_on_term() { trap_on_term() {
trap - INT trap - ERR INT TERM
stty echo stty echo
printf "\n" printf "%s" "${NL}"
printf "\e[0;91m✘ System caught a 'SIGINT'. System Power Off in 3 seconds. \e[0m\n" >&2 color_echo "${RED}" "✘ Received termination signal. System Power Off in 3 seconds." >&2
sync power_off 3
sleep 3
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
}
#######################################
# Print Error Message for 'non-0' Trap on 'EXIT' on Terminal.
# Arguments:
# $1: ${?}
# $2: ${BASH_SOURCE[0]}
# $3: ${LINENO}
# $4: ${FUNCNAME[0]:-main}
# $5: ${BASH_COMMAND}
#######################################
print_scr_err() {
declare -r scr_err_errcode="$1"
declare -r scr_err_errscrt="$2"
declare -r scr_err_errline="$3"
declare -r scr_err_errfunc="$4"
declare -r scr_err_errcmmd="$5"
printf "\n"
printf "\e[0;91m✘ System caught an 'ERROR'. System Power Off in 15 seconds. \e[0m\n" >&2
printf "\n"
printf "\e[0;91m✘ Error : %s \e[0m\n" "${scr_err_errcode}" >&2
printf "\e[0;91m✘ Line : %s \e[0m\n" "${scr_err_errline}" >&2
printf "\e[0;91m✘ Script : %s \e[0m\n" "${scr_err_errscrt}" >&2
printf "\e[0;91m✘ Function : %s \e[0m\n" "${scr_err_errfunc}" >&2
printf "\e[0;91m✘ Command : %s \e[0m\n" "${scr_err_errcmmd}" >&2
printf "\n"
}
#######################################
# Print Error Message for '0' Trap on 'ERR' on Terminal.
# Arguments:
# none
#######################################
print_scr_scc() {
printf "\e[0;92m✅ Script exited successfully. Proceeding with booting. \e[0m\n"
printf "\n"
}
#######################################
# Gather information of all LUKS Devices available on the system
# Arguments:
# None
#######################################
gather_luks_devices() {
declare prev=() curr=() dev="" tries=0
while ((tries < 10)); do
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device)
if [[ ${curr[*]} == "${prev[*]}" ]]; then
break
fi
prev=("${curr[@]}")
tries=$((tries + 1))
sleep 1
done
### Print one device per line for mapfile compatibility
for dev in "${curr[@]}"; do
printf '%s\n' "${dev}"
done
}
#######################################
# Gather information of all NUKE Devices available on the system
# Globals:
# DEVICES_LUKS
# Arguments:
# None
#######################################
gather_nuke_devices() {
### 'DEVICES_LUKS' must already be a bash array of device paths
declare dev=""
declare result=()
for dev in "${DEVICES_LUKS[@]}"; do
### Check slot 31 for 'luks2'
if cryptsetup luksDump "${dev}" 2> /dev/null | grep -qE '^[[:space:]]*31: luks2'; then
result+=("${dev}")
fi
done
### Print one device per line for mapfile compatibility
for dev in "${result[@]}"; do
printf '%s\n' "${dev}"
done
}
#######################################
# Read passphrase interactively.
# Arguments:
# None
#######################################
passphrase_ask() {
declare -g PASSPHRASE=""
printf "\n"
stty -echo
printf "\e[0;95m🔐 Enter passphrase for decryption: \e[0m\n"
read -r PASSPHRASE
stty echo
printf "\n"
}
#######################################
# Test the entered passphrase against the dedicated Nuke Keyslot #31.
# Arguments:
# $1: DEVICE
# $2: PASSWD
#######################################
passphrase_test() {
declare -r DEVICE="$1"
declare -r PASPHR="$2"
printf '%s' "${PASPHR}" | cryptsetup open --batch-mode --test-passphrase --key-slot 31 "${DEVICE}" > /dev/null 2>&1
} }
####################################### #######################################
# Check the integrity and authenticity of this script itself. # Check the integrity and authenticity of this script itself.
# Globals:
# GRE
# MAG
# RED
# Arguments: # Arguments:
# $0: Script Name # 0: Script Name
####################################### #######################################
verify_coresecret() { verify_script() {
### Directory of this script declare dir; dir="$(dirname "$(readlink -f "${0}")")"
# shellcheck disable=SC2155 declare script; script="$(basename "${0}")"
declare dir="$(dirname "$(readlink -f "${0}")")" declare -a algo=("sha512" "sha384")
# shellcheck disable=SC2155 declare cmd="" computed="" expected="" hashfile="" item="" sigfile=""
declare script="$(basename "${0}")"
declare algo
for algo in sha512 sha384; do for item in "${algo[@]}"; do
# shellcheck disable=SC2155 hashfile="${dir}/${script}.${item}"
declare hashfile="${dir}/${script}.${algo}" sigfile="${hashfile}.sig"
# shellcheck disable=SC2155 cmd="${item}sum"
declare sigfile="${hashfile}.sig"
# shellcheck disable=SC2155
declare cmd="${algo}sum"
printf "\e[0;95m🔏 Verifying signature of: [%s] \e[0m\n" "${hashfile}" color_echo "${MAG}" "🔏 Verifying signature of: [${hashfile}]"
gpgv --keyring /etc/keys/pubring.gpg "${sigfile}" "${hashfile}" || { gpgv --keyring /etc/keys/pubring.gpg "${sigfile}" "${hashfile}" || {
printf "\e[0;91m✘ Signature verification failed for: [%s] \e[0m\n" "${hashfile}" >&2 color_echo "${RED}" "✘ Signature verification failed for: [${hashfile}]"
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2 color_echo "${RED}" "✘ System Power Off in 3 seconds ...."
sync power_off 3
sleep 3
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
} }
printf "\e[0;92m🔏 Verifying signature of: [%s] successful. \e[0m\n" "${hashfile}" color_echo "${GRE}" "🔏 Verifying signature of: [${hashfile}] successful."
printf "\e[0;95m🔢 Recomputing Hash: [%s] \e[0m\n" "${algo}" color_echo "${MAG}" "🔢 Recomputing Hash: [${item}]"
# shellcheck disable=SC2155 computed=$(${cmd} "${dir}/${script}" | awk '{print $1}')
declare computed=$($cmd "${dir}/${script}" | awk '{print $1}') expected=$(cat "${hashfile}")
# shellcheck disable=SC2155
declare expected=$(cat "${hashfile}")
if [[ ${computed} != "${expected}" ]]; then if [[ "${computed}" != "${expected}" ]]; then
printf "\e[0;91m✘ Hash mismatch for: [%s] \e[0m\n" "${algo}" >&2 color_echo "${RED}" "✘ Recomputed hash mismatch for : [${item}]" >&2
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2 color_echo "${RED}" "✘ System Power Off in 3 seconds ...." >&2
sync power_off 3
sleep 3
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
fi fi
printf "\e[0;92m🔢 Recomputing Hash: [%s] successful. \e[0m\n" "${algo}" color_echo "${GRE}" "🔢 Recomputing Hash: [${item}] successful."
done done
printf "\e[0;92m🔏 All signatures and hashes verified successfully. Proceeding. \e[0m\n" color_echo "${GRE}" "🔏 All signatures and hashes verified successfully. Proceeding."
} }
### Main Programm #######################################
trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR # Main Programm Sequence
trap 'trap_on_term' INT TERM # Globals:
# CURRENTDATE
# DEVICES_LUKS
# GRE
# MAG
# NL
# PASSPHRASE
# RED
# Arguments:
# None
#######################################
main() {
trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR
trap 'trap_on_term' INT TERM
printf "\e[0;91mCoresecret Connection established.\e[0m\n" color_echo "${RED}" "Coresecret Connection established."
printf "\e[0;91mStarting Time: %s\e[0m\n" "${CURRENTDATE}" color_echo "${RED}" "Starting Time: ${CURRENTDATE}"
printf "\n" color_echo "${MAG}" "Integrity self-check ..."
printf "%s" "${NL}"
verify_coresecret verify_script
### Read newline-separated output into an array ### Read newline-separated output into an array.
mapfile -t DEVICES_LUKS < <(gather_luks_devices) color_echo "${MAG}" "Scanning for LUKS devices ..."
mapfile -t DEVICES_NUKE < <(gather_nuke_devices) printf "%s" "${NL}"
mapfile -t DEVICES_LUKS < <(gather_luks_devices)
### Debug output: list each element with its index ### If there are no LUKS devices at all, drop to bash.
#for idx in "${!DEVICES_LUKS[@]}"; do if (( ${#DEVICES_LUKS[@]} == 0 )); then
# printf 'Luks[%d]: %s\n' "${idx}" "${DEVICES_LUKS[${idx}]}" color_echo "${RED}" "✘ No LUKS Devices found. Dropping to bash ..."
#done drop_bash
fi
### Debug output: list each element with its index ### Extract the 'nuke='-parameter from '/proc/cmdline'.
#for idx in "${!DEVICES_NUKE[@]}"; do extract_nuke_hash
# printf 'Nuke[%d]: %s\n' "${idx}" "${DEVICES_NUKE[${idx}]}"
#done
### # If there are no LUKS devices at all, drop to bash ### Read passphrase interactively.
[[ -n ${DEVICES_LUKS[*]} ]] || { read_passphrase
printf "\e[0;92m✘ No LUKS Devices found. Dropping to bash ... \e[0m\n"
prompt_string
exec /bin/bash -i
}
### If there are LUKS devices but no Nuke devices, try unlocking flow if printf "%s" "${PASSPHRASE}" | cryptroot-unlock; then
if [[ -n ${DEVICES_LUKS[*]} ]] && [[ -z ${DEVICES_NUKE[*]} ]]; then
### Attempt interactive unlock with cryptroot-unlock
if cryptroot-unlock; then
secure_unset_pass
exit 0 exit 0
else else
printf "\n" printf "%s" "${NL}"
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n" color_echo "${RED}" "✘ Unsuccessful command 'cryptroot-unlock'."
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n" color_echo "${GRE}" "✘ No LUKS operations performed. Dropping to bash ..."
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n" color_echo "${GRE}" "✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'."
prompt_string drop_bash
exec /bin/bash -i
fi fi
}
elif [[ -n ${DEVICES_LUKS[*]} ]] && [[ -n ${DEVICES_NUKE[*]} ]]; then main "${@}"
declare -i attempt=1
declare NUKED=false
declare TEST_DEV="${DEVICES_NUKE[0]}"
while ((attempt <= MAX_RETRIES)); do
printf "\e[0;95m🔐Attempt %s/%s: \e[0m\n" "${attempt}" "${MAX_RETRIES}"
passphrase_ask
declare -g PASSWD="${PASSPHRASE}"
if passphrase_test "${TEST_DEV}" "${PASSWD}"; then
for dev in "${DEVICES_NUKE[@]}"; do
cryptsetup erase --batch-mode "${dev}" > /dev/null 2>&1
printf "%s:\e[0;95m✘ LUKS Device Header malfunction. \e[0m\n" "${dev}"
done
declare -r NUKED=true
unset PASSWD
break
else
declare code="$?"
case "${code}" in
1) printf "\e[0;91m✘ No usable key slot is available. \e[0m\n" ;;
2) printf "\e[0;91m✘ No key available with this passphrase. \e[0m\n" ;;
3) printf "\e[0;93m✘ Out of memory. \e[0m\n" ;;
*) printf "\e[0;91m✘ Unexpected Return Code. \e[0m\n" ;;
esac
fi
attempt=$((attempt + 1))
done
if [[ ${NUKED} == true ]]; then
stty echo
sleep 3
sync
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
fi
if cryptroot-unlock; then
exit 0
else
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
prompt_string
exec /bin/bash -i
fi
fi
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -1,447 +0,0 @@
#!/bin/bash
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu
# SPDX-Comment: unlock_wrapper_advanced.sh to be executed as '/etc/crypttab' keyscript and as dropbear SSH forced command.
set -Ceuo pipefail
#######################################
# Variable declaration
#######################################
declare -ir MAX_RETRIES=2
declare -r ASKPASS='/lib/cryptsetup/askpass'
# shellcheck disable=SC2155
declare -r CURRENTDATE=$(date +"%F %T")
# shellcheck disable=SC2155
declare -r IFS=$(printf ' \n\t')
declare -r GRE='\e[0;92m'
declare -r MAG='\e[0;95m'
declare -r RED='\e[0;91m'
declare -r RES='\e[0m'
declare -r NL='\n'
declare -g NUKE_ENABLED='false'
declare -g NUKE_HASH=''
declare -g PASSPHRASE=''
#######################################
# Print-colored text.
# Arguments:
# $1 - color code
# $@ - text to print
#######################################
color_echo() { declare c="$1"; shift; printf "%s%s %s%s" "${c}" "${*}" "${RES}" "${NL}"; }
#######################################
# Die helper: print and exit hard.
# Globals:
# NC
# RED
# Arguments:
# 1: Message string to print.
#######################################
die() { printf "%s✘ %s%s\n" "${RED}" "$1" "${RES}" >&2; power_off 3; }
#######################################
# Drop to bash environment.
# Arguments:
# None
#######################################
drop_bash() { prompt_string; exec /bin/bash -i; }
#######################################
# Extract the 'nuke='-parameter from '/proc/cmdline'.
# Globals:
# NL
# NUKE_ENABLED
# NUKE_HASH
# RED
# RES
# Arguments:
# None
# Returns:
# 0: if 'nuke=' was found and extracted.
# 1: if not found.
#######################################
extract_nuke_hash() {
declare ARG="" CMDLINE="" REGEX='(\$[^$]+){3,}'
### Read '/proc/cmdline' into a single line safely.
read -r CMDLINE < /proc/cmdline
for ARG in ${CMDLINE}; do
case "${ARG}" in
nuke=*)
NUKE_HASH="${ARG#nuke=}"
if echo "${NUKE_HASH}" | grep -qE "${REGEX}"; then
NUKE_ENABLED="true"
return 0
else
### If there is a malformed Grub Bootparameter 'nuke=HASH', drop to bash.
color_echo "${RED}" "✘ Nuke Hash Malformat : [${REGEX}] [${NUKE_HASH}]." >&2
color_echo "${RED}" "✘ Dropping to bash ...:" >&2
drop_bash
fi
;;
esac
done
### No 'nuke=HASH' entry found.
return 1
}
#######################################
# Gather information of all LUKS Devices available on the system.
# Arguments:
# None
#######################################
gather_luks_devices() {
declare prev=() curr=()
declare -i tries=0
while ((tries < 10)); do
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device | sort)
if cmp <(printf '%s\n' "${curr[@]}") <(printf '%s\n' "${prev[@]}") >/dev/null; then
break
fi
prev=("${curr[@]}")
tries=$((tries + 1))
sleep 1
done
printf '%s\n' "${curr[@]}"
}
#######################################
# Erase LUKS headers on all LUKS devices and shutdown system.
# Globals:
# NUKE_DEVICES
#######################################
nuke() {
declare dev=""
for dev in "${DEVICES_LUKS[@]}"; do
cryptsetup erase --batch-mode "${dev}" || true
color_echo "${RED}" "✘ Error: LUKS Device Header malfunction: [${dev}]."
done
secure_unset_pass
color_echo "${RED}" "✘ Error: LUKS Device malfunction. System Power Off in 16 seconds."
power_off 16
}
#######################################
# Unified power-off routine.
# Arguments:
# 1: Sleep time before power-off in seconds (Default to 0 seconds).
#######################################
power_off() {
declare -r wait="${1:-0}"
sleep "${wait}"
sync
echo 1 >| /proc/sys/kernel/sysrq
echo o >| /proc/sysrq-trigger
# The System powers off immediately; no further code is executed.
}
#######################################
# Generates informative shell prompt.
# Globals:
# PS1
# Arguments:
# None
#######################################
prompt_string() {
declare -gx PS1="\
\[\033[1;91m\]\d\[\033[0m\]|\[\033[1;91m\]\u\[\033[0m\]@\
\[\033[1;95m\]\h\[\033[0m\]:\
\[\033[1;96m\]\w\[\033[0m\]/>>\
\$(if [[ \$? -eq 0 ]]; then \
# Show exit status in green if zero
echo -e \"\[\033[1;92m\]\$?\[\033[0m\]\"; \
else \
# Show exit status in red otherwise
echo -e \"\[\033[1;91m\]\$?\[\033[0m\]\"; \
fi)\
|~\$ "
}
#######################################
# Trap function to be called on 'ERR'.
# Arguments:
# 1: ${?}
# 2: ${BASH_SOURCE[0]}
# 3: ${LINENO}
# 4: ${FUNCNAME[0]:-main}
# 5: ${BASH_COMMAND}
#######################################
trap_on_err() {
declare -r errcode="$1"
declare -r errscrt="$2"
declare -r errline="$3"
declare -r errfunc="$4"
declare -r errcmmd="$5"
trap - ERR INT TERM
stty echo
print_scr_err "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}"
power_off 16
}
#######################################
# Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the nuke routine.
# Globals:
# NL
# RED
# RES
# Arguments:
# None
#######################################
trap_on_term() {
trap - ERR INT TERM
stty echo
printf "%s" "${NL}"
color_echo "${RED}" "✘ System caught a 'SIGINT'. System Power Off in 3 seconds." >&2
power_off 3
}
#######################################
# Print Error Message for Trap on 'ERR' on Terminal.
# Globals:
# NL
# RED
# RES
# Arguments:
# 1: ${?}
# 2: ${BASH_SOURCE[0]}
# 3: ${LINENO}
# 4: ${FUNCNAME[0]:-main}
# 5: ${BASH_COMMAND}
#######################################
print_scr_err() {
declare -r scr_err_errcode="$1"
declare -r scr_err_errscrt="$2"
declare -r scr_err_errline="$3"
declare -r scr_err_errfunc="$4"
declare -r scr_err_errcmmd="$5"
printf "%s" "${NL}"
color_echo "${RED}" "✘ System caught an 'ERROR'. System Power Off in 16 seconds." >&2
printf "%s" "${NL}"
color_echo "${RED}" "✘ Error : [${scr_err_errcode}]" >&2
color_echo "${RED}" "✘ Line : [${scr_err_errline}]" >&2
color_echo "${RED}" "✘ Script : [${scr_err_errscrt}]" >&2
color_echo "${RED}" "✘ Function : [${scr_err_errfunc}]" >&2
color_echo "${RED}" "✘ Command : [${scr_err_errcmmd}]" >&2
printf "%s" "${NL}"
}
#######################################
# Print Error Message for '0'-Exit-Code on Terminal.
# Arguments:
# none
#######################################
print_scr_scc() { color_echo "${GRE}" "✅ Script exited successfully. Proceeding with booting."; }
#######################################
# Read Passphrase interactively.
# Globals:
# ASKPASS
# NUKE_ENABLED
# NUKE_HASH
# PASSPHRASE
# Arguments:
# None
# Returns:
# 0: on success
#######################################
read_passphrase() {
declare -a METHODS=("sha512crypt" "yescrypt" "scrypt" "bcrypt")
declare METHOD="" SALT=""
PASSPHRASE="$(${ASKPASS} "Enter passphrase: ")"
if [[ "${NUKE_ENABLED,,}" == 'true' ]]; then
### Validate NUKE_HASH format (e.g., $id$salt$hash)
if [[ "${NUKE_HASH}" =~ ^\$[a-z0-9]+\$[a-zA-Z0-9./]+\$ ]]; then
SALT="$(cut -d'$' -f3 <<< "${NUKE_HASH}")"
for METHOD in "${METHODS[@]}"; do
if mkpasswd -m "${METHOD}" -S "${SALT}" "${PASSPHRASE}" 2>/dev/null | grep -qF -- "${NUKE_HASH}"; then
nuke
fi
done
fi
fi
printf "%s" "${PASSPHRASE}"
return 0
}
#######################################
# Securely unset the passphrase variable.
# Globals:
# PASSPHRASE
#######################################
secure_unset_pass() { unset PASSPHRASE; PASSPHRASE=""; }
#######################################
# Check the integrity and authenticity of this script itself.
# Arguments:
# 0: Script Name
#######################################
verify_script() {
declare dir; dir="$(dirname "$(readlink -f "${0}")")"
declare script; script="$(basename "${0}")"
declare -a algo=("sha512" "sha384")
declare cmd="" computed="" expected="" hashfile="" item="" sigfile=""
for item in "${algo[@]}"; do
hashfile="${dir}/${script}.${item}"
sigfile="${hashfile}.sig"
cmd="${item}sum"
color_echo "${MAG}" "🔏 Verifying signature of: [${hashfile}]"
gpgv --keyring /etc/keys/pubring.gpg "${sigfile}" "${hashfile}" || {
color_echo "${RED}" "✘ Signature verification failed for: [${hashfile}]"
color_echo "${RED}" "✘ System Power Off in 3 seconds ...."
power_off 3
}
color_echo "${GRE}" "🔏 Verifying signature of: [${hashfile}] successful."
color_echo "${MAG}" "🔢 Recomputing Hash: [${item}]"
computed=$(${cmd} "${dir}/${script}" | awk '{print $1}')
expected=$(cat "${hashfile}")
if [[ "${computed}" != "${expected}" ]]; then
color_echo "${RED}" "✘ Recomputed hash mismatch for : [${item}]" >&2
color_echo "${RED}" "✘ System Power Off in 3 seconds ...." >&2
power_off 3
fi
color_echo "${GRE}" "🔢 Recomputing Hash: [${item}] successful."
done
color_echo "${GRE}" "🔏 All signatures and hashes verified successfully. Proceeding."
}
### Main Programm Sequence ###
main() {
trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR
trap 'trap_on_term' INT TERM
color_echo "${RED}" "Coresecret Connection established."
color_echo "${RED}" "Starting Time: ${CURRENTDATE}"
color_echo "${MAG}" "Integrity self-check ..."
printf "%s" "${NL}"
verify_script
### Read newline-separated output into an array.
color_echo "${MAG}" "Scanning for LUKS devices ..."
printf "%s" "${NL}"
mapfile -t DEVICES_LUKS < <(gather_luks_devices)
### If there are no LUKS devices at all, drop to bash.
if (( ${#DEVICES_LUKS[@]} == 0 )); then
printf "%s✘ No LUKS Devices found. Dropping to bash ... %s %s" "${RED}" "${RES}" "${NC}"
drop_bash
fi
### Extract the 'nuke='-parameter from '/proc/cmdline'.
extract_nuke_hash
### Read passphrase interactively.
read_passphrase
### If there are LUKS devices but no Nuke devices, try unlocking flow
if [[ -n ${DEVICES_LUKS[*]} ]] && [[ -z ${DEVICES_NUKE[*]} ]]; then
### Attempt interactive unlock with cryptroot-unlock
if cryptroot-unlock; then
exit 0
else
printf "\n"
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
prompt_string
exec /bin/bash -i
fi
elif [[ -n ${DEVICES_LUKS[*]} ]] && [[ -n ${DEVICES_NUKE[*]} ]]; then
declare -i attempt=1
declare NUKED=false
declare TEST_DEV="${DEVICES_NUKE[0]}"
while ((attempt <= MAX_RETRIES)); do
printf "\e[0;95m🔐Attempt %s/%s: \e[0m\n" "${attempt}" "${MAX_RETRIES}"
passphrase_ask
declare -g PASSWD="${PASSPHRASE}"
if passphrase_test "${TEST_DEV}" "${PASSWD}"; then
for dev in "${DEVICES_NUKE[@]}"; do
cryptsetup erase --batch-mode "${dev}" > /dev/null 2>&1
printf "%s:\e[0;95m✘ LUKS Device Header malfunction. \e[0m\n" "${dev}"
done
declare -r NUKED=true
unset PASSWD
break
else
declare code="$?"
case "${code}" in
1) printf "\e[0;91m✘ No usable key slot is available. \e[0m\n" ;;
2) printf "\e[0;91m✘ No key available with this passphrase. \e[0m\n" ;;
3) printf "\e[0;93m✘ Out of memory. \e[0m\n" ;;
*) printf "\e[0;91m✘ Unexpected Return Code. \e[0m\n" ;;
esac
fi
attempt=$((attempt + 1))
done
if [[ ${NUKED} == true ]]; then
stty echo
sleep 3
sync
set +C
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
fi
if cryptroot-unlock; then
exit 0
else
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
prompt_string
exec /bin/bash -i
fi
fi
}
main "$@"
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -9,6 +9,7 @@
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework. # SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.installer # SPDX-PackageName: CISS.debian.installer
# SPDX-Security-Contact: security@coresecret.eu # SPDX-Security-Contact: security@coresecret.eu
# SPDX-Comment: Hook script (initramfs) for setting up the CISS.debian.installer hardened dropbear environment, incl. Luks Nuke.
set -e set -e
@@ -20,6 +21,11 @@ esac
. /usr/share/initramfs-tools/hook-functions . /usr/share/initramfs-tools/hook-functions
if [ ! -e /etc/initramfs-tools/files/unlock-wrapper.sh ]; then
echo "Missing unlock-wrapper.sh in /etc/initramfs-tools/files/"
exit 1
fi
### Ensure directory structure in initramfs ### Ensure directory structure in initramfs
mkdir -p "${DESTDIR}/etc/dropbear" mkdir -p "${DESTDIR}/etc/dropbear"
mkdir -p "${DESTDIR}/etc/keys" mkdir -p "${DESTDIR}/etc/keys"
@@ -76,6 +82,6 @@ install -m 0444 /etc/initramfs-tools/files/unlock-wrapper.sh.sha512.sig "${DESTD
install -m 0444 /root/.ciss/keys/pubring.gpg "${DESTDIR}/etc/keys/pubring.gpg" install -m 0444 /root/.ciss/keys/pubring.gpg "${DESTDIR}/etc/keys/pubring.gpg"
### Install Dropbear Banner ### Install Dropbear Banner
install -m 0444 /etc/dropbear/initramfs/banner "${DESTDIR}/etc/dropbear/initramfs/banner" install -m 0444 /etc/dropbear/initramfs/banner "${DESTDIR}/etc/dropbear/banner"
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -12,100 +12,54 @@
guard_sourcing guard_sourcing
#######################################
# Generates 'nuke=HASH' Bootparameter.
# Globals:
# DIR_CNF
# ERR_READ_NUKE_FILE
# VAR_DEBUG_TRACE
# VAR_NUKE_HASH
# Arguments:
# None
# Returns:
# 0: on success
# ERR_READ_NUKE_FILE
#######################################
nuke_passphrase() {
declare -r var_nuke_pwd_file="${DIR_CNF}/password_luks_nuke.txt"
declare var_temp_nuke_hash="" var_temp_plain_nuke_pwd="" var_salt=""
declare pw_file="${2}" ### No tracing for security reasons
if [[ -z "${pw_file}" ]]; then [[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set +x
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi if [[ ! -f "${var_nuke_pwd_file}" ]] || ! IFS= read -r var_temp_plain_nuke_pwd < "${var_nuke_pwd_file}"; then
printf "%s❌ Error: --root-password-file missing password file path argument.%s%s" "${C_RED}" "${C_RES}" "${NL}" >&2 return "${ERR_READ_NUKE_FILE}"
# shellcheck disable=SC2162
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s' ${C_GRE}" "${C_RES}"
exit "${ERR_MISS_PWD_P}"
fi fi
### Turn on tracing again
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set -x
if [[ ! -f "${pw_file}" ]]; then var_salt=$(tr -dc 'A-Za-z0-9' < /dev/random | head -c 16)
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "%s❌ Error: --root-password-file password file '%s' does not exist.%s%s" "${pw_file}" >&2
# shellcheck disable=SC2162
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
exit "${ERR_MISS_PWD_F}"
fi
declare owner ### No tracing for security reasons
owner=$(stat -c '%U:%G' "${pw_file}") [[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set +x
if [[ "${owner}" != "root:root" ]]; then var_temp_nuke_hash=$(mkpasswd --method=sha-512 --salt="${var_salt}" --rounds=8388608 "${var_temp_plain_nuke_pwd}")
chown root:root "${pw_file}" || { ### Turn on tracing again
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi [[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set -x
printf "%s❌ Error: --root-password-file failed to set owner root:root on '%s'.%s%s" "${pw_file}" >&2
# shellcheck disable=SC2162
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
exit "${ERR_OWNS_PWD_F}"
}
fi
declare perms declare -grx VAR_NUKE_HASH="${var_temp_nuke_hash}"
perms=$(stat -c '%a' "${pw_file}") unset var_temp_nuke_hash var_temp_plain_nuke_pwd
if [[ "${perms}" -ne 400 ]]; then
chmod 400 "${pw_file}" || {
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "%s❌ Error: --root-password-file failed to set permissions 0400 on '%s'.%s%s" "${pw_file}" >&2
# shellcheck disable=SC2162
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
exit "${ERR_RGHT_PWD_F}"
}
fi
declare plaintext_pw do_log "debug" "true" "NUKE hash starts with: ${VAR_NUKE_HASH:0:12}..."
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
if ! IFS= read -r plaintext_pw < "${pw_file}"; then
:
fi
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
declare pw_length
pw_length=${#plaintext_pw}
if (( pw_length < 20 || pw_length > 64 )); then
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "%s❌ Error: --root-password-file password MUST be between 20 and 64 characters (got %d).%s%s" "${pw_length}" >&2
# shellcheck disable=SC2162
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
exit "${ERR_PASS_LENGH}"
fi
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
if [[ "${plaintext_pw}" == *\"* ]]; then
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
printf "%s❌ Error: --root-password-file password MUST NOT contain double quotes (\").%s%s" >&2
# shellcheck disable=SC2162
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
exit "${ERR_PASS_PLICY}"
fi
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
declare salt
set +o pipefail
while :; do
salt=$(tr -dc 'A-Za-z0-9' </dev/random | head -c 16)
[[ ${#salt} -eq 16 ]] && break
done
set -o pipefail
declare hash_temp
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
hash_temp=$(mkpasswd --method=sha-512 --salt="${salt}" --rounds=8388608 "${plaintext_pw}")
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
declare -g VAR_HASHED_PWD="${hash_temp}"
unset hash_temp plaintext_pw
sync sync
if shred -vfzu -n 5 "${pw_file}" > /dev/null 2>&1; then if shred -vfzu -n 5 "${var_nuke_pwd_file}" > /dev/null 2>&1; then
printf "%s✅ Password file '%s': shred -vfzu -n 5 >> done. %s%s" "${pw_file}" > /dev/null 2>&1 do_log "info" "false" "✅ Password file '${var_nuke_pwd_file}': shred -vfzu -n 5 >> done."
else else
printf "%s❌ Password file '%s': shred -vfzu -n 5 >> NOT successful. %s%s" "${pw_file}" > /dev/null 2>&1 do_log "warn" "false" "❌ Password file '${var_nuke_pwd_file}': shred -vfzu -n 5 >> NOT successful."
fi fi
sync sync
do_log "info" "false" "Nuke Hash generated."
return 0
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -43,7 +43,8 @@ declare -girx ERR_CHRT_COMMAND=227 # Failure occurred while executing chroo
declare -girx ERR_GRUB_EFI_FORCE=226 # Invalid combination of Partition Table and grub_force_efi. declare -girx ERR_GRUB_EFI_FORCE=226 # Invalid combination of Partition Table and grub_force_efi.
declare -girx ERR_GRUB_BACKGROUND=225 # Failure occurred on setting up the GRUB-background. declare -girx ERR_GRUB_BACKGROUND=225 # Failure occurred on setting up the GRUB-background.
declare -girx ERR_PATH_NOT_VALID=224 # Specific path is not existing. declare -girx ERR_PATH_NOT_VALID=224 # Specific path is not existing.
declare -girx ERR_READ_NUKE_FILE=223 # Error reading Luks Nuke password file.
declare -girx ERR_READ_GRUB_FILE=222 # Error reading Grub password file.
### Definition of error trap vars ### Definition of error trap vars
declare -gx ERRCODE="" # = $? = $1 = ERRCODE declare -gx ERRCODE="" # = $? = $1 = ERRCODE
@@ -51,20 +52,4 @@ declare -gx ERRSCRT="" # = ${BASH_SOURCE[0]} = $2 = ERRSCRT
declare -gx ERRLINE="" # = ${LINENO} = $3 = ERRLINE declare -gx ERRLINE="" # = ${LINENO} = $3 = ERRLINE
declare -gx ERRFUNC="" # = ${FUNCNAME[0]:-main} = $4 = ERRFUNC declare -gx ERRFUNC="" # = ${FUNCNAME[0]:-main} = $4 = ERRFUNC
declare -gx ERRCMMD="" # = ${$BASH_COMMAND} = $5 = ERRCMMD declare -gx ERRCMMD="" # = ${$BASH_COMMAND} = $5 = ERRCMMD
declare -gir ERR_SPLASH_PNG=200 # --change-splash MUST be 'club' or 'hexagon'
declare -gir ERR_CONTROL_CT=201 # --control MUST be an integer between '1' and '65535'
declare -gir ERR_RENICE_PRI=202 # --renice-priority MUST an integer between '-19' and '19'
declare -gir ERR_REIONICE_P=203 # --reionice-priority no values provided.
declare -gir ERR_REIO_P_VAL=204 # --reionice-priority PRIORITY MUST be an integer between '0' and '7'
declare -gir ERR_REIO_C_VAL=205 # --reionice-priority CLASS MUST be an integer between '1' and '3'
declare -gir ERR_MISS_PWD_P=206 # --root-password-file missing password file path argument
declare -gir ERR_MISS_PWD_F=207 # --root-password-file password file does not exist
declare -gir ERR_OWNS_PWD_F=208 # --root-password-file failed to set owner root:root on the PWD file
declare -gir ERR_RGHT_PWD_F=209 # --root-password-file failed to set permissions 0400 on the PWD file
declare -gir ERR_PASS_LENGH=210 # --root-password-file password MUST be between 20 and 64 characters
declare -gir ERR_PASS_PLICY=211 # --root-password-file password MUST NOT contain double quotes
declare -gir ERR__SSH__PORT=212 # --ssh-port MUST be an integer between '1' and '65535'
declare -gir ERR_NOTABSPATH=252 # Not an absolute path
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh