#!/usr/bin/bash
set -euo pipefail -o errtrace
shopt -s expand_aliases

alias plymouth_message="plymouth message --text"
source anti-evil-maid-lib
trap 'rm -rf "$CACHE_DIR"' EXIT

validatetpm || exit 1

# Listing foo.service in anti-evil-maid-seal.service's Requires= and After=
# would cause it to always be started (even when not booting in AEM mode or
# when sealing is unnecessary) due to the way systemd evaluates conditions.
# Putting the systemctl command in ExecStartPre= is also insufficient: The
# user might want to run this script manually after changing the secret(s).

tpmstartservices

if [ ! -e "$SUFFIX_CACHE" ] && [ $# -ne 1 ]; then
    message "AEM media suffix cache file does not exist"
    message "and you didn't specify a suffix as the"
    message "first positional argument to this script."
    exit 1
fi

# scream loudly if sealing fails for some reason
# (eg. AEM media read-only)
_failure() {
    message "Failed to seal secrets (error @ line $1)!"
    waitforenter
    exit 1
}
trap '_failure $LINENO' ERR


# define sealing and device variables

# shellcheck source=../etc/anti-evil-maid.conf
source /etc/anti-evil-maid.conf
tpmresetdalock || true
Z=$(tpmzsrk)
LABEL_SUFFIX=${1-$(cat "$SUFFIX_CACHE")}
LABEL=$LABEL_PREFIX$LABEL_SUFFIX

case $# in
    0) DEV=/dev/disk/by-uuid/$(getparams aem.uuid) ;;
    1) DEV=/dev/disk/by-label/$LABEL ;;
    *) exit 1 ;;
esac


# ensure that all standard PCRs configured to be used have been extended

bad_pcrs=$(listbadpcrs) || true
if [ -n "$bad_pcrs" ]; then
    message "PCR sanity check failed!"
    message "Bad PCRs:"$'\n'"$bad_pcrs"
    message "See /usr/share/doc/anti-evil-maid/README for details."
    exit 1
fi


# regenerate the freshness token and store its hash in TPM

head -c 20 /dev/random > "$AEM_DIR/$LABEL/secret.fre"
updatefreshness "$AEM_DIR/$LABEL/secret.fre" "$LABEL_SUFFIX"


# seal and save secret(s) to root partition

mkdir -p "$TPM_DIR/$LABEL"
tpmsealprepare "$TPM_DIR/$LABEL"

SEALED=0
for ext in txt key otp fre; do
     input=$AEM_DIR/$LABEL/secret.$ext
    output=$TPM_DIR/$LABEL/secret.$ext.sealed2

    if [ ! -e "$input" ]; then
        message "Absent $input"
    elif tpmsealdata "$Z" "$input" "$output" "$TPM_DIR/$LABEL"; then
        rm -f "${output%2}"
        SEALED=$((SEALED + 1))
        message "Sealed $input using $SEAL"
    else
        message "Failed $input"
    fi
done

if [ "$SEALED" = 0 ]; then
    exit 1
fi


# mount device

waitfor -b "$DEV"

if CUR_MNT=$(devtomnt "$DEV") && [ -n "$CUR_MNT" ]; then
    MNT=$CUR_MNT
else
    CUR_MNT=
    MNT=/mnt/anti-evil-maid/$LABEL
    mkdir -p "$MNT"
    mount "$DEV" "$MNT"
fi


# copy secret(s) to device

synctpms "$LABEL" "$MNT"


# unmount device

if [ -z "$CUR_MNT" ]; then
    umount "$MNT"
    if external "$DEV" && removable "$DEV"; then
        waitfor ! -b "$DEV"
    fi
fi
