#!/bin/bash # SPDX-Version: 3.0 # SPDX-CreationInfo: 2025-11-06; 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 guard_sourcing || return "${ERR_GUARD_SRCE}" ####################################### # Integrates CISS dropbear, SOPS version, SOPS Age Key, and CISS and PhysNet primordial SSH identity files. # Globals: # BASH_SOURCE # VAR_AGE # VAR_AGE_KEY # VAR_DROPBEAR_VERSION # VAR_HANDLER_BUILD_DIR # VAR_SOPS_VERSION # VAR_SSHFP # VAR_TMP_SECRET # VAR_WORKDIR # Arguments: # None # Returns: # 0: on success # ERR_DROPBEAR_V: on failure # ERR__SOPS__VER: on failure ####################################### init_primordial() { printf "\e[95m🧪 %s starting ... \e[0m\n" "${BASH_SOURCE[0]}" ### Prepare CISS dropbear integration ---------------------------------------------------------------------------------------- declare var_dropbear_version="${VAR_DROPBEAR_VERSION}" declare var_dropbear_tar="${VAR_WORKDIR}/upgrades/dropbear/dropbear-${var_dropbear_version}.tar.bz2" # shellcheck disable=SC2153,SC2154 declare var_sops_version="${VAR_SOPS_VERSION#v}" if [[ ! "${var_dropbear_version}" =~ ^[0-9]{4}\.[0-9]+$ ]]; then printf "\e[91m❌ ERROR: Invalid Dropbear version: [%s] \e[0m\n" "${var_dropbear_version}" >&2 return "${ERR_DROPBEAR_V}" fi if [[ ! -r "${var_dropbear_tar}" ]]; then printf "\e[91m❌ ERROR: Dropbear tarball not found: [%s] \e[0m\n" "${var_dropbear_tar}" >&2 return "${ERR_DROPBEAR_V}" fi if [[ ! "${var_sops_version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then printf "\e[91m❌ ERROR: Invalid SOPS version: [%s] \e[0m\n" "${var_sops_version}" >&2 # shellcheck disable=SC2154 return "${ERR__SOPS__VER}" fi install -d -m 0755 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/etc/initramfs-tools/files" install -d -m 0755 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/build" install -d -m 0755 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/dropbear" printf 'DROPBEAR_VERSION="%s"\n' "${var_dropbear_version}" \ >| "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/dropbear.env" chmod 0444 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/dropbear.env" printf 'CISS_SOPS_VERSION="%s"\n' "${var_sops_version}" \ >| "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/sops.env" chmod 0444 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/sops.env" install -m 0444 "${var_dropbear_tar}" \ "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/dropbear/dropbear-${var_dropbear_version}.tar.bz2" install -m 0444 "${VAR_WORKDIR}/upgrades/dropbear/localoptions.h" \ "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/dropbear/localoptions.h" install -m 0444 "${VAR_WORKDIR}/config/includes.chroot/usr/share/initramfs-tools/scripts/init-premount/dropbear" \ "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/dropbear.file" ### Check for SOPS AGE key integration --------------------------------------------------------------------------------------- if [[ "${VAR_AGE,,}" == "true" ]]; then install -d -m 0700 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.config/sops/age" install -m 0400 "${VAR_TMP_SECRET}/${VAR_AGE_KEY}" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.config/sops/age/keys.txt" shred -fzu -n 5 -- "${VAR_TMP_SECRET}/${VAR_AGE_KEY}" 2>/dev/null || rm -f "${VAR_TMP_SECRET}/${VAR_AGE_KEY}" fi ### Check for SSH CISS and PhysNet primordial-workflow(tm) integration ------------------------------------------------------- if [[ "${VAR_SSHFP,,}" == "true" ]]; then install -d -m 0700 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh" install -m 0600 "${VAR_TMP_SECRET}/id"* "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/" normalize_ssh_keys_in_dir "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh" shred -fzu -n 5 -- "${VAR_TMP_SECRET}/id"* 2>/dev/null || rm -f "${VAR_TMP_SECRET}/id"* install -d -m 0700 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/ssh" install -m 0600 "${VAR_TMP_SECRET}/ssh_host_"* "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/ssh/" normalize_ssh_keys_in_dir "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/ssh/" shred -fzu -n 5 -- "${VAR_TMP_SECRET}/ssh_host_"* 2>/dev/null || rm -f "${VAR_TMP_SECRET}/ssh_host_"* fi printf "\e[92m✅ %s successfully applied. \e[0m\n" "${BASH_SOURCE[0]}" return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f init_primordial ####################################### # Normalize SSH key files: strip CRLF. # Globals: # None # Arguments: # 1: ssh_host_key or id file # Returns: # 0: on success # ERR_SANITIZING: on failure ####################################### normalize_ssh_key_file() { declare var_key_file="" var_tmp_file="" declare -i var_is_pub=0 var_key_file="$1" [[ -f "${var_key_file}" ]] || return 0 # shellcheck disable=SC2249 case "${var_key_file}" in *.pub) var_is_pub=1 ;; esac ### If there is any CR (carriage return), strip it. if grep -q $'\r' "${var_key_file}"; then ### Use a temporary file to avoid in-place corruption- var_tmp_file="${var_key_file}.noCR.$$" ### Remove only '\r', keep everything else as-is. if ! tr -d '\r' < "${var_key_file}" >| "${var_tmp_file}"; then printf "\e[91m❌ Failed to normalize CRLF: [%s] \e[0m\n" "${var_key_file}" rm -f "${var_tmp_file}" return "${ERR_SANITIZING}" fi mv "${var_tmp_file}" "${var_key_file}" if [[ "${var_is_pub}" -eq 1 ]]; then chmod 0644 "${var_key_file}" else chmod 0600 "${var_key_file}" fi ### Validate with ssh-keygen if available. if command -v ssh-keygen >/dev/null 2>&1; then ### Always: fingerprint check (works for private and public keys). if ! ssh-keygen -lf "${var_key_file}" >/dev/null; then printf "\e[91m❌ Failed check ssh-keygen -lf: [%s] \e[0m\n" "${var_key_file}" return "${ERR_SANITIZING}" fi ### Only for private keys: derive the public key to ensure libcrypto can parse the private key. if [[ "${var_is_pub}" -eq 0 ]]; then if ! ssh-keygen -yf "${var_key_file}" >/dev/null; then printf "\e[91m❌ Failed check ssh-keygen -yf: [%s] \e[0m\n" "${var_key_file}" return "${ERR_SANITIZING}" fi fi fi sha256sum "${var_key_file}" >| "${var_key_file}.sha256sum.txt" chmod 0440 "${var_key_file}.sha256sum.txt" fi return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f normalize_ssh_key_file ####################################### # Normalize SSH key files in dir. # Globals: # None # Arguments: # 1: directory # Returns: # 0: on success # ERR_SANITIZING: on failure ####################################### normalize_ssh_keys_in_dir() { declare var_key_dir="" var_key_file="" declare -i old_nullglob=0 old_dotglob=0 old_failglob=0 var_key_dir="$1" ### Enable nullglob/dotglob, disable failglob for safe globbing. shopt -q nullglob && old_nullglob=1 shopt -q dotglob && old_dotglob=1 shopt -q failglob && old_failglob=1 shopt -s nullglob dotglob shopt -u failglob if [[ ! -d "${var_key_dir}" ]]; then if (( old_nullglob )); then shopt -s nullglob; else shopt -u nullglob; fi if (( old_dotglob )); then shopt -s dotglob; else shopt -u dotglob; fi if (( old_failglob )); then shopt -s failglob; else shopt -u failglob; fi return 0 fi ### Cover both root identity keys and host keys. for var_key_file in "${var_key_dir}"/id_* "${var_key_dir}"/ssh_host_*; do [[ -e "${var_key_file}" ]] || continue if ! normalize_ssh_key_file "${var_key_file}"; then if (( old_nullglob )); then shopt -s nullglob; else shopt -u nullglob; fi if (( old_dotglob )); then shopt -s dotglob; else shopt -u dotglob; fi if (( old_failglob )); then shopt -s failglob; else shopt -u failglob; fi return "${ERR_SANITIZING}" fi done if (( old_nullglob )); then shopt -s nullglob; else shopt -u nullglob; fi if (( old_dotglob )); then shopt -s dotglob; else shopt -u dotglob; fi if (( old_failglob )); then shopt -s failglob; else shopt -u failglob; fi return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f normalize_ssh_keys_in_dir # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh