#!/bin/sh
# bashsupport disable=BP5007
# shellcheck disable=SC2249
# shellcheck shell=sh

# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-11-12; WEIDNER, Marc S.; <msw@coresecret.dev>
# 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.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: GPL-3.0-or-later
# 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

### Modified Version of the original file:
### https://salsa.debian.org/live-team/live-boot 'components/0030-ciss-verify-checksums'
### In case of successful verification of the offered checksum, proceed with booting; otherwise panic.

#######################################
# Modified checksum-integrity and authenticity-verification-script for continuing the boot process.
# Globals:
#   LIVE_BOOT_CMDLINE
#   _TTY
# Arguments:
#   1: _MOUNTPOINT
# Returns:
#   0 : Successful verification
#######################################
Verify_checksums() {
  printf "\e[95m[INFO] CDLB modified: [/usr/lib/live/boot/0030-ciss-verify-checksums] ... \n\e[0m"

  ### Will be replaced at build time:
  export CDLB_EXP_FPR="@EXP_FPR@"
  export CDLB_EXP_CA_FPR="@EXP_CA_FPR@"

  ### Declare variables --------------------------------------------------------------------------------------------------------
  _MOUNTPOINT="${1}"

  _PARAMETER=""

  _TTY="/dev/tty8"

  LIVE_VERIFY_CHECKSUMS_DIGESTS="${LIVE_VERIFY_CHECKSUMS_DIGESTS:-sha512 sha384 sha256}"

  LIVE_VERIFY_CHECKSUMS_SIGNATURES="false"

  _KEYFILE=""

  _MP=""

  ### Parse commandline arguments ----------------------------------------------------------------------------------------------
  for _PARAMETER in ${LIVE_BOOT_CMDLINE}; do

    case "${_PARAMETER}" in

      live-boot.verify-checksums=* | verify-checksums=*)

        LIVE_VERIFY_CHECKSUMS="true"
        LIVE_VERIFY_CHECKSUMS_DIGESTS="${_PARAMETER#*verify-checksums=}"
        ;;

      live-boot.verify-checksums | verify-checksums)

        LIVE_VERIFY_CHECKSUMS="true"
        ;;

      live-boot.verify-checksums-signatures | verify-checksums-signatures)

        LIVE_VERIFY_CHECKSUMS_SIGNATURES="true"
        ;;

    esac

  done

  ### Check if the function should be skipped ----------------------------------------------------------------------------------
  case "${LIVE_VERIFY_CHECKSUMS}" in

    true)
      :
      ;;

    *)
      return 0
      ;;

  esac

  ### Check GPG pubkey file correct path ---------------------------------------------------------------------------------------
  for _MP in /lib/live/mount/medium /run/live/medium /cdrom /; do

    if [ -e "${_MP}/${CDLB_EXP_FPR}.gpg" ]; then

      _KEYFILE="${_MP}/${CDLB_EXP_FPR}.gpg"

      if [ -e "${_MP}/${CDLB_EXP_FPR}.gpg" ]; then

        _CA_KEYFILE="${_MP}/${CDLB_EXP_CA_FPR}.gpg"

      fi

      break

    fi

  done

  # shellcheck disable=SC2164
  cd "${_MOUNTPOINT}"


  ### CDLB verification of script integrity itself -----------------------------------------------------------------------------
  if [ "${LIVE_VERIFY_CHECKSUMS_SIGNATURES}" = "true" ]; then

    log_begin_msg "Verifying integrity of: [0030-ciss-verify-checksums]"
    printf "\n"

    _CAND=""
    CDLB_SCRIPT_SELF=""  CDLB_CMD="" CDLB_COMPUTED="" CDLB_EXPECTED="" CDLB_HASHFILE="" CDLB_SIG_FILE=""

    CDLB_CMD="/usr/bin/sha512sum"
    CDLB_SHA="sha512"

    for _CAND in /scripts/live-bottom/0030-ciss-verify-checksums /usr/lib/live/boot/0030-ciss-verify-checksums; do

      [ -e "${_CAND}" ] && { CDLB_SCRIPT_SELF="${_CAND}"; break; }

    done

    CDLB_SCRIPT_FILE="${CDLB_SCRIPT_SELF##*/}"
    CDLB_SCRIPT_PATH="${CDLB_SCRIPT_SELF%/*}"
    CDLB_SCRIPT_FULL="${CDLB_SCRIPT_PATH%/}/${CDLB_SCRIPT_FILE}"
    CDLB_HASHFILE="${CDLB_SCRIPT_FILE}.${CDLB_SHA}sum.txt"
    CDLB_SIG_FILE="${CDLB_HASHFILE}.sig"

    _STATUS="$(/usr/bin/gpgv --no-default-keyring --keyring "${_KEYFILE}" --status-fd 1 --verify "${CDLB_SIG_FILE}" "${CDLB_SCRIPT_FULL}" 2>/dev/null)"

    _CDLB_SIG_FILE_FPR="$(printf '%s\n' "${_STATUS}" | awk '/^\[GNUPG:\] VALIDSIG /{print $3; exit}')"

    ### Compare against pinned and expected fingerprint.
    if [ "${_CDLB_SIG_FILE_FPR}" = "${CDLB_EXP_FPR}" ]; then

      printf "\e[92m[INFO] Signer fingerprint match: got [%s] expected: [%s] \n\e[0m" "${_CDLB_SIG_FILE_FPR}" "${CDLB_EXP_FPR}"

    else

      printf "\e[91m[FATAL] Signer fingerprint mismatch: got [%s] expected: [%s] \n\e[0m" "${_CDLB_SIG_FILE_FPR}" "${CDLB_EXP_FPR}"
      sleep 16
      panic        "[FATAL] Signer fingerprint mismatch: got [${_CDLB_SIG_FILE_FPR}] expected: [${CDLB_EXP_FPR}]."

    fi

    ### Script self-integrity and authenticity checks --------------------------------------------------------------------------
    ### Assumption: initramfs itself is not altered.
    printf "\e[95m[INFO] Verifying signature of: [%s] ... \n\e[0m" "${CDLB_SIG_FILE}"

    if ! /usr/bin/gpgv --keyring "${_KEYFILE}" --status-fd 1 "${CDLB_SIG_FILE}" "${CDLB_HASHFILE}"; then

      printf "\e[91m[FATAL] Verifying signature of: [%s] failed. \n\e[0m" "${CDLB_SIG_FILE}"
      sleep 16
      panic        "[FATAL] Verifying signature of: [${CDLB_SIG_FILE}] failed."

    else

      printf "\e[92m[INFO] Verifying signature of: [%s] successful. \n\e[0m" "${CDLB_SIG_FILE}"

    fi

    printf "\e[95m[INFO] Recomputing hash for: [%s] ... \n\e[0m" "${CDLB_SHA}"

    CDLB_COMPUTED=$("${CDLB_CMD}" "${CDLB_SCRIPT_FULL}" | { read -r first _ || exit 1; printf '%s\n' "${first}"; })
    IFS=' ' read -r CDLB_EXPECTED _ < "${CDLB_HASHFILE}"

    if [ "${CDLB_COMPUTED}" != "${CDLB_EXPECTED}" ]; then

      printf "\e[91m[FATAL] Recomputing hash for: [%s] failed. \n\e[0m" "${CDLB_SHA}"
      sleep 16
      panic        "[FATAL] Recomputing hash for: [${CDLB_SHA}] failed."

    fi

    printf "\e[92m[INFO] Recomputing hash for: [%s] successful. \n\e[0m" "${CDLB_SHA}"
    printf "\e[92m[INFO] Verification of authenticity and integrity of [%s] successfully completed. \n\e[0m" "${CDLB_SCRIPT_FULL}"
    log_end_msg
    printf "\n"

  fi

  ### Checksum and checksum signature verification -----------------------------------------------------------------------------
  log_begin_msg "Verifying checksums"
  printf "\n"
  printf "\e[95m[INFO] Verifying checksums ... \n\e[0m"

  # shellcheck disable=SC2001
  for _DIGEST in $(echo "${LIVE_VERIFY_CHECKSUMS_DIGESTS}" | sed -e 's|,| |g'); do

    # shellcheck disable=SC2060
    _CHECKSUMS="$(echo "${_DIGEST}" | tr [a-z] [A-Z])SUMS ${_DIGEST}sum.txt"

    for _CHECKSUM in ${_CHECKSUMS}; do

      if [ -e "${_CHECKSUM}" ]; then

        printf "\e[95m[INFO] Found: [%s] ... \n\e[0m" "${_CHECKSUM}"

        if [ -e "/usr/bin/${_DIGEST}sum" ]; then

          printf "\e[95m[INFO] Found: [%s] ... \n\e[0m" "/usr/bin/${_DIGEST}sum"

          if [ "${LIVE_VERIFY_CHECKSUMS_SIGNATURES}" = "true" ]; then

            printf "\e[95m[INFO] Checking signature of: [%s] ... \n\e[0m" "${_CHECKSUM}"

            _CHECKSUM_SIGNATURE="${_CHECKSUM}.sig"

            if /usr/bin/gpgv --keyring "${_KEYFILE}" --status-fd 1 "${_CHECKSUM_SIGNATURE}" "${_CHECKSUM}"; then

              _RETURN_PGP="${?}"
              printf "\e[92m[INFO] Checking signature of: [%s] successful. \n\e[0m" "${_CHECKSUM}"

            else

              _RETURN_PGP="${?}"
              printf "\e[91m[FATAL] Checking signature of: [%s] failed. \n\e[0m" "${_CHECKSUM}"

            fi

          else

            _RETURN_PGP="na"

          fi

          # shellcheck disable=SC2312
          if grep -v '^#' "${_CHECKSUM}" | /usr/bin/"${_DIGEST}"sum -c > "${_TTY}"; then

            _RETURN_SHA="${?}"
            printf "\e[92m[INFO] Found: [%s] successful verified: [%s] \n\e[0m" "/usr/bin/${_DIGEST}sum" "${_CHECKSUM}"

          else

            _RETURN_SHA="${?}"
            printf "\e[91m[FATAL] Found: [%s] unsuccessful verified: [%s] \n\e[0m" "/usr/bin/${_DIGEST}sum" "${_CHECKSUM}"

          fi

          # Stop after the first verification.
          break 2

        else

          _RETURN_SHA="255"
          printf "\e[93m[WARN] NOT Found [%s]. \n\e[0m" "/usr/bin/${_DIGEST}sum"

        fi

      fi

    done

  done

  log_end_msg
  printf "\n"

  case "${_RETURN_PGP},${_RETURN_SHA}" in

    "0,0")
      printf "\e[92m[INFO] Verification of [GPG signature] and [sha checksum] file successful; continuing booting in 8 seconds. \n\e[0m"
      printf "\e[92m[INFO] CDLB modified: [%s] done. \n\e[0m" "${CDLB_SCRIPT_FULL}"
      sleep 8
      log_success_msg "Verification of [GPG signature] and [sha checksum] file successful; continuing booting in 8 seconds."
      return 0
      ;;

    "na,0")
      printf "\e[92m[INFO] Verification of [sha checksum] file successful; continuing booting in 8 seconds. \n\e[0m"
      printf "\e[92m[INFO] CDLB modified: [%s] done. \n\e[0m" "${CDLB_SCRIPT_FULL}"
      sleep 8
      log_success_msg "Verification of [sha checksum] file successful; continuing booting in 8 seconds."
      return 0
      ;;

    "0,"*)
      printf "\e[91m[FATAL] Verification of [GPG signature] file successful, while verification of [sha checksum] file failed. \n\e[0m"
      printf "\e[91m[FATAL] CDLB modified: [%s] done. \n\e[0m" "${CDLB_SCRIPT_FULL}"
      sleep 8
      panic "Verification of [GPG signature] file successful, while verification of [sha checksum] file failed."
      ;;

    *",0")
      printf "\e[91m[FATAL] Verification of [GPG signature] file failed, while verification of [sha checksum] file successful. \n\e[0m"
      printf "\e[91m[FATAL] CDLB modified: [%s] done. \n\e[0m" "${CDLB_SCRIPT_FULL}"
      sleep 8
      panic "Verification of [GPG signature] file failed, while verification of [sha checksum] file successful."
      ;;

    "na,"*)
      printf "\e[91m[FATAL] Verification of [sha checksum] file failed. \n\e[0m"
      printf "\e[91m[FATAL] CDLB modified: [%s] done. \n\e[0m" "${CDLB_SCRIPT_FULL}"
      sleep 8
      panic "Verification of checksum file failed."
      ;;

  esac
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
