Skip to content

Commit

Permalink
Use a USB security key as a TPM work-alike in the absence of a TPM
Browse files Browse the repository at this point in the history
On machines without a TPM, we'd still like some way for the BIOS to
attest that it has not been modified. With a USB security 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 USB security 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: Matt DeVillier <matt.devillier@puri.sm>
  • Loading branch information
MrChromebox committed Sep 16, 2020
1 parent aeec903 commit 21ade9f
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 86 deletions.
17 changes: 15 additions & 2 deletions initrd/bin/flash.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set -e -o pipefail

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."
Expand All @@ -30,6 +30,10 @@ flash_rom() {
else
die "$ROM: Read inconsistent"
fi
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
Expand All @@ -52,20 +56,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>"
die "Usage: $0 [-c|-r|-s] <path_to_image.rom>"
fi

flash_rom $ROM
Expand Down
31 changes: 18 additions & 13 deletions initrd/bin/seal-hotpkey
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,24 @@ else
HOTPKEY_BRANDING="HOTP USB Security Dongle"
fi

tpm nv_readvalue \
-in 4d47 \
-sz 312 \
-of "$HOTP_SEALED" \
|| die "Unable to retrieve sealed file from TPM NV"

tpm unsealfile \
-hk 40000000 \
-if "$HOTP_SEALED" \
-of "$HOTP_SECRET" \
|| die "Unable to unseal HOTP secret"

shred -n 10 -z -u "$HOTP_SEALED" 2> /dev/null
if [ "$CONFIG_TPM" = "y" ]; then
tpm nv_readvalue \
-in 4d47 \
-sz 312 \
-of "$HOTP_SEALED" \
|| die "Unable to retrieve sealed file from TPM NV"

tpm unsealfile \
-hk 40000000 \
-if "$HOTP_SEALED" \
-of "$HOTP_SECRET" \
|| die "Unable to unseal HOTP secret"

shred -n 10 -z -u "$HOTP_SEALED" 2> /dev/null
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
# config TPM counter as TPM 1.2 can only increment one counter between reboots
Expand Down
123 changes: 65 additions & 58 deletions initrd/bin/seal-totp
Original file line number Diff line number Diff line change
Expand Up @@ -17,72 +17,79 @@ fi
TOTP_SECRET="/tmp/secret/totp.key"
TOTP_SEALED="/tmp/secret/totp.sealed"

dd \
if=/dev/urandom \
of="$TOTP_SECRET" \
count=1 \
bs=20 \
2>/dev/null \
|| die "Unable to generate 20 random bytes"

secret="`base32 < $TOTP_SECRET`"

# Use the current values of the PCRs, which will be read
# from the TPM as part of the sealing ("X").
# PCR4 == 0 means that we are still in the boot process and
# not a recovery shell.
# should this read the storage root key?
if ! tpm sealfile2 \
-if "$TOTP_SECRET" \
-of "$TOTP_SEALED" \
-hk 40000000 \
-ix 0 X \
-ix 1 X \
-ix 2 X \
-ix 3 X \
-ix 4 0000000000000000000000000000000000000000 \
-ix 7 X \
; then
if [ "$CONFIG_TPM" = "y" ]; then
dd \
if=/dev/urandom \
of="$TOTP_SECRET" \
count=1 \
bs=20 \
2>/dev/null \
|| die "Unable to generate 20 random bytes"

secret="`base32 < $TOTP_SECRET`"

# Use the current values of the PCRs, which will be read
# from the TPM as part of the sealing ("X").
# PCR4 == 0 means that we are still in the boot process and
# not a recovery shell.
# should this read the storage root key?
if ! tpm sealfile2 \
-if "$TOTP_SECRET" \
-of "$TOTP_SEALED" \
-hk 40000000 \
-ix 0 X \
-ix 1 X \
-ix 2 X \
-ix 3 X \
-ix 4 0000000000000000000000000000000000000000 \
-ix 7 X \
; then
shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null
die "Unable to seal secret"
fi

shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null
die "Unable to seal secret"
fi

shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null

# to create an nvram space we need the TPM owner password
# and the TPM physical presence must be asserted.
#
# The permissions are 0 since there is nothing special
# about the sealed file
tpm physicalpresence -s \
|| warn "Warning: Unable to assert physical presence"

# to create an nvram space we need the TPM owner password
# and the TPM physical presence must be asserted.
#
# The permissions are 0 since there is nothing special
# about the sealed file
tpm physicalpresence -s \
|| warn "Warning: Unable to assert physical presence"

# Try to write it without the password first, and then create
# the NVRAM space using the owner password if it fails for some reason.
if ! tpm nv_writevalue \
-in $TPM_NVRAM_SPACE \
-if "$TOTP_SEALED" \
; then
warn 'NVRAM space does not exist? Owner password is required'
read -s -p "TPM Owner password: " tpm_password
echo

tpm nv_definespace \
-in $TPM_NVRAM_SPACE \
-sz 312 \
-pwdo "$tpm_password" \
-per 0 \
|| die "Unable to define NVRAM space"

tpm nv_writevalue \
# Try to write it without the password first, and then create
# the NVRAM space using the owner password if it fails for some reason.
if ! tpm nv_writevalue \
-in $TPM_NVRAM_SPACE \
-if "$TOTP_SEALED" \
|| die "Unable to write sealed secret to NVRAM"
; then
warn 'NVRAM space does not exist? Owner password is required'
read -s -p "TPM Owner password: " tpm_password
echo

tpm nv_definespace \
-in $TPM_NVRAM_SPACE \
-sz 312 \
-pwdo "$tpm_password" \
-per 0 \
|| die "Unable to define NVRAM space"

tpm nv_writevalue \
-in $TPM_NVRAM_SPACE \
-if "$TOTP_SEALED" \
|| die "Unable to write sealed secret to NVRAM"
fi

shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null
else
# without a TPM, use the first 20 characters of the ROM SHA256sum
secret_from_rom_hash > $TOTP_SECRET
secret="`base32 < $TOTP_SECRET`"
shred -n 10 -z -u "$TOTP_SECRET" 2> /dev/null
fi

shred -n 10 -z -u "$TOTP_SEALED" 2> /dev/null

url="otpauth://totp/$HOST?secret=$secret"
secret=""

Expand Down
31 changes: 18 additions & 13 deletions initrd/bin/unseal-hotp
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,24 @@ fi

#counter_value=$(printf "%d" 0x${counter_value})

tpm nv_readvalue \
-in 4d47 \
-sz 312 \
-of "$HOTP_SEALED" \
|| die "Unable to retrieve sealed file from TPM NV"

tpm unsealfile \
-hk 40000000 \
-if "$HOTP_SEALED" \
-of "$HOTP_SECRET" \
|| die "Unable to unseal HOTP secret"

shred -n 10 -z -u "$HOTP_SEALED" 2> /dev/null
if [ "$CONFIG_TPM" = "y" ]; then
tpm nv_readvalue \
-in 4d47 \
-sz 312 \
-of "$HOTP_SEALED" \
|| die "Unable to retrieve sealed file from TPM NV"

tpm unsealfile \
-hk 40000000 \
-if "$HOTP_SEALED" \
-of "$HOTP_SECRET" \
|| die "Unable to unseal HOTP secret"

shred -n 10 -z -u "$HOTP_SEALED" 2> /dev/null
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
shred -n 10 -z -u "$HOTP_SECRET" 2> /dev/null
Expand Down
13 changes: 13 additions & 0 deletions initrd/etc/functions
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,19 @@ combine_configs() {
cat /etc/config* > /tmp/config
}

# 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()
{
# clear screen
Expand Down

0 comments on commit 21ade9f

Please sign in to comment.