mirror of
https://github.com/m8tin/cis.git
synced 2026-11-02 22:17:24 +01:00
154 lines
4.3 KiB
Bash
Executable File
154 lines
4.3 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
AES_STORE_FILE=~/tpm/aes-key-safe
|
|
SECRETS_STORE_FILE=~/tpm/secrets
|
|
SECRETS_PLAIN_PATH=/run/user/$(id -u)/secrets/
|
|
|
|
|
|
|
|
function checkPreconditions() {
|
|
! checkTPM \
|
|
&& echo >&2 \
|
|
&& echo "TPM 2.0 device missing." >&2 \
|
|
&& return 1
|
|
|
|
! checkTools \
|
|
&& echo >&2 \
|
|
&& echo 'TPM tools missing. Setup via: "apt install tpm2-tools"' >&2 \
|
|
&& return 1
|
|
|
|
return 0
|
|
}
|
|
|
|
function checkSafe() {
|
|
printf -- "%s" 'Checking TPM derived safe ... ' >&2 \
|
|
&& [ -f "${AES_STORE_FILE}" ] \
|
|
&& [ -f "${AES_STORE_FILE}.pub" ] \
|
|
&& printf -- "%s\n" '(found)' >&2 \
|
|
&& return 0
|
|
|
|
printf -- "%s\n" '(missing)' >&2
|
|
return 1
|
|
}
|
|
|
|
function checkTools() {
|
|
printf -- "%s" 'Checking TPM tools ... ' >&2 \
|
|
&& tpm2_createprimary --version > /dev/null 2>&1 \
|
|
&& tpm2_create --version > /dev/null 2>&1 \
|
|
&& tpm2_load --version > /dev/null 2>&1 \
|
|
&& tpm2_unseal --version > /dev/null 2>&1 \
|
|
&& printf -- "%s\n" '(installed)' >&2 \
|
|
&& return 0
|
|
|
|
return 1
|
|
}
|
|
|
|
function checkTPM() {
|
|
printf -- "%s" 'Checking TPM device ... ' >&2 \
|
|
&& [ -f /sys/class/tpm/tpm0/tpm_version_major ] \
|
|
&& [ $(cat /sys/class/tpm/tpm0/tpm_version_major) -ge 2 ] 2> /dev/null \
|
|
&& printf -- "%s\n" '(available)' >&2 \
|
|
&& return 0
|
|
|
|
return 1
|
|
}
|
|
|
|
function checkOrCreateSafe() {
|
|
checkSafe \
|
|
&& return 0
|
|
|
|
[ -f "${AES_STORE_FILE}" ] \
|
|
&& echo 'ABORT existing safe file found: "${AES_STORE_FILE}"' >&2 \
|
|
&& return 1
|
|
|
|
[ -f "${AES_STORE_FILE}.pub" ] \
|
|
&& echo 'ABORT existing safe file found: "${AES_STORE_FILE}.pub"' >&2 \
|
|
&& return 1
|
|
|
|
printf -- "%s" 'Creating TPM derived safe ... ' >&2
|
|
mkdir -p "$(dirname "${AES_STORE_FILE}")"
|
|
tpm2_createprimary -C o -Q -c "${TMPDIR%/}/primary.ctx"
|
|
openssl rand 32 | tpm2_create -C "${TMPDIR%/}/primary.ctx" -Q -i - -r "${AES_STORE_FILE}" -u "${AES_STORE_FILE}.pub" \
|
|
&& checkSafe \
|
|
&& return 0
|
|
|
|
echo 'FAILURE: unable to provide a usable safe.' >&2
|
|
return 1
|
|
}
|
|
|
|
function seal() {
|
|
# Ensure all secrets have restricte permissions before tar
|
|
! chmod -R go-rwx "${SECRETS_PLAIN_PATH}" \
|
|
&& return 1
|
|
|
|
tpm2_createprimary -C o -Q -c "${TMPDIR%/}/primary.ctx"
|
|
tpm2_load \
|
|
-C "${TMPDIR%/}/primary.ctx" -Q \
|
|
-r "${AES_STORE_FILE}" \
|
|
-u "${AES_STORE_FILE}.pub" \
|
|
-c "${TMPDIR%/}/safe.ctx"
|
|
openssl enc -aes-256-cbc -salt -pbkdf2 \
|
|
-in <(tar -czvf - "${SECRETS_PLAIN_PATH%/}/"*) \
|
|
-out "${SECRETS_STORE_FILE}.tar.gz.aes" \
|
|
-pass file:<(tpm2_unseal -c "${TMPDIR%/}/safe.ctx")
|
|
}
|
|
|
|
function unseal() {
|
|
! [ -f "${SECRETS_STORE_FILE}.tar.gz.aes" ] \
|
|
&& return 1
|
|
|
|
! mkdir -m 1700 -p "${SECRETS_PLAIN_PATH}" \
|
|
&& return 1
|
|
|
|
tpm2_createprimary -C o -Q -c "${TMPDIR%/}/primary.ctx"
|
|
tpm2_load \
|
|
-C "${TMPDIR%/}/primary.ctx" -Q \
|
|
-r "${AES_STORE_FILE}" \
|
|
-u "${AES_STORE_FILE}.pub" \
|
|
-c "${TMPDIR%/}/safe.ctx"
|
|
openssl enc -d -aes-256-cbc -pbkdf2 \
|
|
-in "${SECRETS_STORE_FILE}.tar.gz.aes" \
|
|
-out - \
|
|
-pass file:<(tpm2_unseal -c "${TMPDIR%/}/safe.ctx") | tar -xzvf - -C /
|
|
}
|
|
|
|
function usage() {
|
|
echo
|
|
echo 'Commands:'
|
|
echo ' --seal : This will save the secrets of this host in a secure way.'
|
|
echo ' A safe is created automatically and will not be overwritten,'
|
|
echo ' you have to delete both safe files to replace an existing safe,'
|
|
echo ' BUT you will loose access to the AES key inside, so BE CAREFUL!'
|
|
echo ' --unseal : This restores the secrets after a reboot.'
|
|
|
|
return 0
|
|
}
|
|
|
|
|
|
|
|
checkPreconditions || exit 1
|
|
|
|
case "${1}" in
|
|
--seal)
|
|
TMPDIR=$(mktemp -d --suffix .tpm.context)
|
|
trap 'rm -rf "${TMPDIR:?"Missing TMPDIR"}"; echo "Sealing finished, TMPDIR removed: ${TMPDIR}"' EXIT
|
|
checkOrCreateSafe \
|
|
&& seal \
|
|
&& exit 0
|
|
;;
|
|
--unseal)
|
|
TMPDIR=$(mktemp -d --suffix .tpm.context)
|
|
trap 'rm -rf "${TMPDIR:?"Missing TMPDIR"}"; echo "Unsealing finished, TMPDIR removed: ${TMPDIR}"' EXIT
|
|
checkSafe \
|
|
&& unseal \
|
|
&& exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown command '${1}'"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
exit 1
|