Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move policy update to HUP commit hook
When migrating the TPM2 policy used to secure the LUKS passphrase to use different PCRs, we temporarily want to maintain fallback capability in case the newly installed hostapp doesn't pass healthchecks. This allows the system to boot back into the original OS and try again. In order to do so, we leave the passphrase in place with the old PCR authentication policy. The cryptsetup hook in the initramfs will try PCRs 0,2,3,7 and if those don't work we fallback to the original PCRs. Once the new system successfully boots, we'll re-encrypt the passphrase and use the new PCRs to create a policy to secure the key. Change-type: patch Signed-off-by: Joseph Kogut <joseph@balena.io>
- Loading branch information
Showing
5 changed files
with
152 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
129 changes: 129 additions & 0 deletions
129
...ommon/recipes-support/hostapp-update-hooks/files/95-secureboot/2-fwd_commit_update-policy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#!/bin/sh | ||
|
||
# Copyright 2024 Balena Ltd. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
# | ||
# Update the TPM2 sealing policy on commit. | ||
# | ||
# This updates the passphrase to use the newly computed value of PCR7 if any | ||
# measured variables have been changed, such as by appending to dbx during HUP. | ||
# | ||
# Additonally, the hook will migrate from systems that were setup to seal the | ||
# LUKS passphrase using PCRs 0,1,2,3 to using 0,2,3,7. | ||
# | ||
# This is done in a commit hook to preserve fallback capability until the new | ||
# OS is healthy. | ||
# | ||
|
||
set -o errexit | ||
|
||
# shellcheck disable=SC1091 | ||
. /usr/libexec/os-helpers-sb | ||
|
||
EFI_MOUNT_DIR="/mnt/efi" | ||
PASSPHRASE_FILE="$(mktemp -t)" | ||
SESSION_CTX="$(mktemp -t)" | ||
POLICY_PATH="$(find "${EFI_MOUNT_DIR}" -type d -name "policies.*")" | ||
tpm2_startauthsession --policy-session -S "${SESSION_CTX}" | ||
tpm2_policypcr -S "${SESSION_CTX}" -l "sha256:0,2,3,7" | ||
|
||
update_reason="" | ||
POLICIES="$(find "${POLICY_PATH}" -type f | sort | xargs)" | ||
if [ "$(echo "${POLICIES}" | wc -w)" -gt 1 ]; then | ||
tpm2_policyor -S "${SESSION_CTX}" "sha256:$(echo "${POLICIES}" | sed 's/ /,/g')" | ||
update_reason="Combined policy in use" | ||
fi | ||
|
||
if hw_decrypt_passphrase "${EFI_MOUNT_DIR}" "session:${SESSION_CTX}" "${PASSPHRASE_FILE}"; then | ||
echo "Unlocked passphrase using pcr:sha256:0,2,3,7" | ||
elif hw_decrypt_passphrase "${EFI_MOUNT_DIR}" "pcr:sha256:0,1,2,3" "${PASSPHRASE_FILE}"; then | ||
echo "Unlocked passphrase using pcr:sha256:0,1,2,3, migrating to 0,2,3,7" | ||
update_reason="Legacy PCRs in use" | ||
else | ||
echo "Failed to unlock passphrase, abort" | ||
exit 1 | ||
fi | ||
|
||
POLICY="$(mktemp -t)" | ||
PCRS="0,2,3,7" | ||
PCR_VAL_BIN="$(mktemp -t)" | ||
RESULT_DIR="$(mktemp -d)" | ||
EFI_BINARIES=" \ | ||
$(find "${EFI_MOUNT_DIR}" -name bootx64.efi -print -quit) \ | ||
$(find /boot -name bzImage -print -quit) | ||
" | ||
|
||
for pcr in $(echo ${PCRS} | sed 's/,/ /g'); do | ||
case $pcr in | ||
7) | ||
digest="$(compute_pcr7)" | ||
|
||
if firmware_measures_efibins; then | ||
for bin in ${EFI_BINARIES}; do | ||
extend="$(tcgtool -s "$bin" \ | ||
| tcgtool -e "db-${EFI_IMAGE_SECURITY_DATABASE_GUID}" \ | ||
| _sha256 )" | ||
digest="$(printf '%s%s' "$digest" "$extend" \ | ||
| _hexdecode | _sha256 )" | ||
done | ||
fi | ||
|
||
current_digest="$( \ | ||
tpm2_pcrread --quiet "sha256:$pcr" -o /proc/self/fd/1 \ | ||
| _hexencode)" | ||
if [ "$current_digest" != "$digest" ]; then | ||
update_reason="PCR7 computed value changed" | ||
fi | ||
;; | ||
*) | ||
digest="$(tpm2_pcrread --quiet "sha256:$pcr" -o /proc/self/fd/1 | _hexencode)" | ||
;; | ||
esac | ||
|
||
printf "%s" "$digest" | _hexdecode \ | ||
| dd of="${PCR_VAL_BIN}" \ | ||
status=none \ | ||
bs=1 \ | ||
seek="$(du -b "${PCR_VAL_BIN}" | cut -f1)" | ||
done | ||
|
||
if [ -n "${update_reason}" ]; then | ||
echo "${update_reason}, updating policy" | ||
tpm2_createpolicy --policy-pcr \ | ||
-l "sha256:${PCRS}" \ | ||
-f "${PCR_VAL_BIN}" \ | ||
-L "${POLICY}" | ||
hw_encrypt_passphrase "${PASSPHRASE_FILE}" "${POLICY}" "${RESULT_DIR}" | ||
|
||
tpm2_evictcontrol -c "${EFI_MOUNT_DIR}/balena-luks.ctx" | ||
mv "${RESULT_DIR}/persistent.ctx" "${EFI_MOUNT_DIR}/balena-luks.ctx" && sync | ||
mv "${RESULT_DIR}/passphrase.enc" "${EFI_MOUNT_DIR}/balena-luks.enc" && sync | ||
|
||
POLICY_PATH="$(find "${EFI_MOUNT_DIR}" -type d -name "policies.*")" | ||
|
||
rm -rf "${RESULT_DIR}" \ | ||
"${POLICY}" \ | ||
"${PCR_VAL_BIN}" \ | ||
"${PASSPHRASE_FILE}" \ | ||
"${POLICY_PATH}" | ||
|
||
sync | ||
|
||
# reboot to ensure the passphrase can be unlocked again, otherwise HUP | ||
# won't work until the device is manually rebooted | ||
reboot | ||
else | ||
echo "PCR7 computed value is unchanged" | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This is an awk syntax error