Use 160 bits of ROM hash for TPM-less HOTP secret (up from 80)

HOTP/TOTP secrets don't have to be printable.  Use binary data to
include 160 bits of entropy instead of just 80.

The secret is still limited to 20 bytes.  Most keys now support up to
40 bytes, but tpmtotp is still limited to 20 bytes.

Move the truncation to 20 bytes a bit later, for future improvements to
detect the key's actual limit.

Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
This commit is contained in:
Jonathon Hall 2023-07-05 10:18:06 -04:00
parent 75cb8a070f
commit 0a35ef912f
No known key found for this signature in database
GPG Key ID: 1E9C3CA91AE25114
3 changed files with 38 additions and 4 deletions

View File

@ -38,7 +38,7 @@ if [ "$CONFIG_TPM" = "y" ]; then
tpmr unseal 4d47 0,1,2,3,4,7 312 "$HOTP_SECRET" \
|| fatal_error "Unable to unseal HOTP secret"
else
# without a TPM, use the first 20 characters of the ROM SHA256sum
# without a TPM, generate a secret based on the SHA-256 of the ROM
secret_from_rom_hash > "$HOTP_SECRET" || die "Reading ROM failed"
fi
@ -80,6 +80,9 @@ else
HOTPKEY_BRANDING="HOTP USB Security Dongle"
fi
# Truncate the secret if it is longer than the maximum HOTP secret
truncate_max_bytes 20 "$HOTP_SECRET"
# try using factory default admin PIN
admin_pin="12345678"
hotp_initialize "$admin_pin" $HOTP_SECRET $counter_value "$HOTPKEY_BRANDING" >/dev/null 2>&1

View File

@ -41,10 +41,13 @@ 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
# without a TPM, generate a secret based on the SHA-256 of the ROM
secret_from_rom_hash > "$HOTP_SECRET" || die "Reading ROM failed"
fi
# Truncate the secret if it is longer than the maximum HOTP secret
truncate_max_bytes 20 "$HOTP_SECRET"
if ! hotp $counter_value < "$HOTP_SECRET"; then
shred -n 10 -z -u "$HOTP_SECRET" 2> /dev/null
die 'Unable to compute HOTP hash?'

View File

@ -349,7 +349,9 @@ load_config_value()
fi
}
# Generate secret value using first 20 chars of ROM SHA256 hash
# Generate a secret for TPM-less HOTP by reading the ROM. Output is the
# sha256sum of the ROM (binary, not printable), which can be truncated to the
# supported secret length.
secret_from_rom_hash() {
local ROM_IMAGE="/tmp/coreboot-notpm.rom"
@ -360,7 +362,7 @@ secret_from_rom_hash() {
flash.sh -r "${ROM_IMAGE}" >/dev/null 2>&1 || return 1
fi
sha256sum ${ROM_IMAGE} | cut -f1 -d ' ' | cut -c 1-20 | tr -d '\n'
sha256sum "${ROM_IMAGE}" | cut -f1 -d ' ' | fromhex_plain
}
update_checksums()
@ -589,6 +591,32 @@ calc()
awk "BEGIN { print "$*" }";
}
# truncate a file to a size only if it is longer (busybox truncate lacks '<' and
# always sets the file size)
truncate_max_bytes() {
local bytes="$1"
local file="$2"
if [ "$(stat -c %s "$file")" -gt "$bytes" ]; then
truncate -s "$bytes" "$file"
fi
}
# Busybox xxd -p pads the last line with spaces to 60 columns, which not only
# trips up many scripts, it's very difficult to diagnose by looking at the
# output. Delete line breaks and spaces to really get plain hex output.
tohex_plain() {
xxd -p | tr -d '\n '
}
# Busybox xxd -p -r silently truncates lines longer than 60 hex chars.
# Shorter lines are OK, spaces are OK, and even splitting a byte across lines is
# allowed, so just fold the text to maximum 60 column lines.
# Note that also unlike GNU xxd, non-hex chars in input corrupt the output (GNU
# xxd ignores them).
fromhex_plain() {
fold -w 60 | xxd -p -r
}
print_battery_health()
{
if [ -d /sys/class/power_supply/BAT* ]; then