Use the Librem Key as a TPM work-alike in the absence of a TPM

On machines without a TPM, we'd still like some way for the BIOS to
attest that it has not been modified. With a Librem Key, we can have the
BIOS use its own ROM measurement converted to a SHA256sum and truncated
so it fits within an HOTP secret. Like with a TPM, a malicious BIOS with
access to the correct measurements can send pre-known good measurements
to the Librem Key.

This approach provides one big drawback in that we have to truncate the
SHA256sum to 20 characters so that it fits within the limitations of
HOTP secrets. This means the possibility of collisions is much higher
but again, an attacker could also capture and spoof an existing ROM's
measurements if they have prior access to it, either with this approach
or with a TPM.

Signed-off-by: Kyle Rankin <kyle.rankin@puri.sm>
This commit is contained in:
Kyle Rankin 2019-11-25 12:25:11 -06:00 committed by Jonathon Hall
parent 3b3c49b026
commit d937426306
No known key found for this signature in database
GPG Key ID: 1E9C3CA91AE25114
6 changed files with 63 additions and 5 deletions

View File

@ -12,7 +12,7 @@ TRACE "Under /bin/flash.sh"
case "$CONFIG_FLASHROM_OPTIONS" in
-* )
echo "Board $CONFIG_BOARD detected, continuing..."
[ "$1" != "-s" ] && echo "Board $CONFIG_BOARD detected, continuing..."
;;
* )
die "ERROR: No board has been configured!\n\nEach board requires specific flashrom options and it's unsafe to flash without them.\n\nAborting."
@ -119,6 +119,10 @@ flash_rom() {
if [ "$READ" -eq 1 ]; then
flashrom $CONFIG_FLASHROM_OPTIONS -r "${ROM}" \
|| die "Backup to $ROM failed"
elif [ "$SHA" -eq 1 ]; then
flashrom $CONFIG_FLASHROM_OPTIONS -r "${ROM}" 1&>2 >/dev/null \
|| die "$ROM: Read failed"
sha256sum ${ROM} | cut -f1 -d ' '
else
cp "$ROM" /tmp/${CONFIG_BOARD}.rom
sha256sum /tmp/${CONFIG_BOARD}.rom
@ -150,20 +154,29 @@ flash_rom() {
if [ "$1" == "-c" ]; then
CLEAN=1
READ=0
SHA=0
ROM="$2"
elif [ "$1" == "-r" ]; then
CLEAN=0
READ=1
SHA=0
ROM="$2"
touch $ROM
elif [ "$1" == "-s" ]; then
CLEAN=0
READ=0
SHA=1
ROM="$2"
touch $ROM
else
CLEAN=0
READ=0
SHA=0
ROM="$1"
fi
if [ ! -e "$ROM" ]; then
die "Usage: $0 [-c|-r] <path/to/image.(rom|tgz)>"
die "Usage: $0 [-c|-r|-s] <path/to/image.(rom|tgz)>"
fi
if [ "$READ" -eq 0 ] && [ "${ROM##*.}" = tgz ]; then

View File

@ -152,8 +152,10 @@ generate_totp_hotp()
{
tpm_password="$1" # May be empty, will prompt if needed and empty
TRACE "Under /bin/gui-init:generate_totp_hotp"
echo "Scan the QR code to add the new TOTP secret"
if /bin/seal-totp "$BOARD_NAME" "$tpm_password"; then
if [ "$CONFIG_TPM" != "y" ]; then
echo "Generating new HOTP secret"
/bin/seal-hotpkey
elif echo "Scan the QR code to add the new TOTP secret" && /bin/seal-totp "$BOARD_NAME" "$tpm_password"; then
if [ -x /bin/hotp_verification ]; then
echo "Once you have scanned the QR code, hit Enter to configure your HOTP USB Security Dongle (e.g. Librem Key or Nitrokey)"
read
@ -263,6 +265,31 @@ update_hotp()
else
HOTP='N/A'
fi
if [[ "$CONFIG_TPM" = n && "$HOTP" = "Invalid code" ]]; then
whiptail $BG_COLOR_ERROR --title "ERROR: HOTP Validation Failed!" \
--menu "ERROR: Heads couldn't validate the HOTP code.\n\nIf you just reflashed your BIOS, you should generate a new TOTP/HOTP secret.\n\nIf you have not just reflashed your BIOS, THIS COULD INDICATE TAMPERING!\n\nHow would you like to proceed?" 0 80 4 \
'g' ' Generate new TOTP/HOTP secret' \
'i' ' Ignore error and continue to main menu' \
'x' ' Exit to recovery shell' \
2>/tmp/whiptail || recovery "GUI menu failed"
option=$(cat /tmp/whiptail)
case "$option" in
g )
if (whiptail $BG_COLOR_WARNING --title 'Generate new TOTP/HOTP secret' \
--yesno "This will erase your old secret and replace it with a new one!\n\nDo you want to proceed?" 0 80) then
generate_totp_hotp && BG_COLOR_MAIN_MENU=""
fi
;;
i )
return 1
;;
x )
recovery "User requested recovery shell"
;;
esac
fi
}
clean_boot_check()

View File

@ -30,6 +30,9 @@ if [ "$CONFIG_TPM" = "y" ]; then
DEBUG "Sealing HOTP secret reuses TOTP sealed secret..."
tpmr unseal 4d47 0,1,2,3,4,7 312 "$HOTP_SECRET" \
|| die "Unable to unseal HOTP secret"
else
# without a TPM, use the first 20 characters of the ROM SHA256sum
secret_from_rom_hash > "$HOTP_SECRET"
fi
# Store counter in file instead of TPM for now, as it conflicts with Heads

View File

@ -40,6 +40,9 @@ fi
if [ "$CONFIG_TPM" = "y" ]; then
DEBUG "Unsealing HOTP secret reuses TOTP sealed secret..."
tpmr unseal 4d47 0,1,2,3,4,7 312 "$HOTP_SECRET"
else
# without a TPM, use the first 20 characters of the ROM SHA256sum
secret_from_rom_hash > "$HOTP_SECRET"
fi
if ! hotp $counter_value < "$HOTP_SECRET"; then

View File

@ -284,6 +284,19 @@ replace_config() {
rm -f ${CONFIG_FILE}.tmp
}
# Generate secret value using first 20 chars of ROM SHA256 hash
secret_from_rom_hash() {
local ROM_IMAGE="/tmp/coreboot-notpm.rom"
echo -e "\nTPM not detected; measuring ROM directly\n" 1>&2
# use a previously-copied image if it exists
if [ -f ${ROM_IMAGE} ]; then
sha256sum ${ROM_IMAGE} | cut -f1 -d ' ' | cut -c 1-20 | tr -d '\n'
else
flash.sh -s ${ROM_IMAGE} | cut -c 1-20 | tr -d '\n'
fi
}
update_checksums()
{
TRACE "Under /etc/functions:update_checksums"

View File

@ -59,7 +59,6 @@ TRACE "Under init"
if [ ! -e /dev/tpm0 ]; then
CONFIG_TPM='n'
CONFIG_TPM2_TOOLS='n'
warn 'No TPM found...'
fi
#Specify whiptail background colors cues under FBWhiptail only