diff --git a/initrd/bin/kexec-seal-key b/initrd/bin/kexec-seal-key index fe36808c..c8a1891a 100755 --- a/initrd/bin/kexec-seal-key +++ b/initrd/bin/kexec-seal-key @@ -72,20 +72,21 @@ dd \ # Count the number of slots used on each device for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do - DEBUG "Checking number of slots used on $dev" + DEBUG "Checking number of slots used on $dev LUKS header" #check if the device is a LUKS device with luks[1,2] slots_used=$(cryptsetup luksDump $dev | grep -c 'luks[0-9]*' || die "Unable to get number of slots used on $dev") - DEBUG "Number of slots used on $dev: $slots_used" + DEBUG "Number of slots used on $dev LUKS header: $slots_used" # If slot1 is the only one used, warn and die with proper messages if [ $slots_used -eq 1 ]; then # Check if slot 1 is the only one existing if cryptsetup luksDump $dev | grep -q "Slot 1: ENABLED"; then - warn "Slot 1 is the only one existing on $dev. Heads cannot use it to store TPM sealed LUKS Disk Unlock Key" - die "Slot 1 should not be the only slot existing on $dev. Fix your custom setup" + warn "Slot 1 is the only one existing on $dev LUKS header. Heads cannot use it to store TPM sealed LUKS Disk Unlock Key" + warn "Slot 1 should not be the only slot existing on $dev LUKS header. Slot 0 should be used to store Disk Recovery Key/passphrase" + die "You can safely fix this before continuing through Heads recovery shell: cryptsetup luksAddKey $dev" fi else - DEBUG "Slot 1 is not the only existing slot on $dev" - DEBUG "$dev Slot 1 will be used to store LUKS Disk Unlock Key that TPM will seal/unseal with TPM Disk Unlock Key passphrase" + DEBUG "Slot 1 is not the only existing slot on $dev LUKS header." + DEBUG "$dev LUKS header's slot 1 will store LUKS Disk Unlock Key that TPM will seal/unseal with TPM Disk Unlock Key passphrase" fi done diff --git a/initrd/etc/ash_functions b/initrd/etc/ash_functions index d877382f..5c140531 100644 --- a/initrd/etc/ash_functions +++ b/initrd/etc/ash_functions @@ -96,20 +96,24 @@ confirm_gpg_card() { #Prompt user for provisioned GPG Admin PIN that will be passed along to mount-usb and to import gpg subkeys echo - read -s -p "Please enter GPG Admin PIN needed to use the GPG backup thumb drive: " gpg_admin_pin + #TODO: change all passphrase prompts in codebase to include -r to prevent backslash escapes + read -r -s -p "Please enter GPG Admin PIN needed to use the GPG backup thumb drive: " gpg_admin_pin + echo #prompt user to select the proper encrypted partition, which should the first one on next prompt - echo -e "Please select encrypted LUKS container partition (not the public one)\n" + warn "Please select encrypted LUKS on GPG key material backup thumb drive (not public labeled one)" mount-usb --pass "$gpg_admin_pin" || die "Unable to mount USB with GPG Admin PIN" - warn "Testing detach-sign operation and verifiying against fused public key in ROM" + echo "++++ Testing detach-sign operation and verifiying against fused public key in ROM" gpg --pinentry-mode=loopback --passphrase-file <(echo -n "${gpg_admin_pin}") --import /media/subkeys.sec >/dev/null 2>&1 || die "Unable to import GPG private subkeys" #Do a detach signature to ensure gpg material is usable and cache passphrase to sign /boot from caller functions dd if=/dev/urandom of="$CR_NONCE" bs=20 count=1 >/dev/null 2>&1 || - die "Unable to create $CR_NONCE to be signed with GPG private signing subkey" + die "Unable to create $CR_NONCE to be detach-signed with GPG private signing subkey" gpg --pinentry-mode=loopback --passphrase-file <(echo -n "${gpg_admin_pin}") --detach-sign "$CR_NONCE" >/dev/null 2>&1 || - die "Unable to sign $CR_NONCE with GPG private signing subkey using GPG Admin PIN" + die "Unable to detach-sign $CR_NONCE with GPG private signing subkey using GPG Admin PIN" #verify detached signature against public key in rom - gpg --verify "$CR_SIG" "$CR_NONCE" || die "Unable to verify $CR_SIG detached signature against public key in ROM" + gpg --verify "$CR_SIG" "$CR_NONCE" > /dev/null 2>&1 && \ + echo "++++ Imported private subkeys match public key fused in rom and can be used under Heads" || \ + die "Unable to verify $CR_SIG detached signature against public key in ROM" #Wipe any previous CR_NONCE and CR_SIG shred -n 10 -z -u "$CR_NONCE" "$CR_SIG" >/dev/null 2>&1 || true #TODO: maybe just an export instead of setting /etc/user.config otherwise could be flashed in weird corner case situation @@ -177,8 +181,8 @@ gpg_auth() { if gpg --digest-algo SHA256 \ --detach-sign \ -o "$CR_SIG" \ - "$CR_NONCE" \ - && gpgv "$CR_SIG" "$CR_NONCE" \ + "$CR_NONCE" > /dev/null 2>&1 \ + && gpg --verify "$CR_SIG" "$CR_NONCE" > /dev/null 2>&1 \ ; then shred -n 10 -z -u "$CR_NONCE" "$CR_SIG" 2>/dev/null || true DEBUG "Under /etc/ash_functions:gpg_auth: success" diff --git a/initrd/etc/functions b/initrd/etc/functions index 23c8fc2b..f9a45dea 100755 --- a/initrd/etc/functions +++ b/initrd/etc/functions @@ -96,16 +96,15 @@ reseal_tpm_disk_decryption_key() { fi if [ -s /boot/kexec_key_devices.txt ] || [ -s /boot/kexec_key_lvm.txt ]; then - warn "A TPM Disk Unlock Key previously sealed is now invalid since firmware measurements could not unseal TOTP" - echo "Renewing LUKS Disk Unlock Key to be unsealed by TPM Disk Unlock Key passphrase" + warn "TPM sealed Disk Unlock Key secret needs to be resealed alongside TOTP/HOTP secret" + echo "Resealing TPM LUKS Disk Unlock Key to be unsealed by TPM Disk Unlock Key passphrase" while ! kexec-seal-key /boot; do warn "Recovery Disk Encryption key passphrase invalid. Try again!" done warn "LUKS header hash changed under /boot/kexec_luks_hdr_hash.txt" echo "Updating checksums and signing all files under /boot/kexec.sig" while ! update_checksums; do - warn "Checksums were not signed. Bad GPG PIN provided?" - warn "Please update checksums and provide a valid GPG PIN" + warn "Checksums were not signed. Preceding errors should explain possible causes" done warn "Rebooting in 3 seconds to enable booting default boot option" sleep 3 @@ -257,7 +256,7 @@ increment_tpm_counter() { TRACE "Under /etc/functions:increment_tpm_counter" tpmr counter_increment -ix "$1" -pwdc '' | tee /tmp/counter-$1 || - die "Counter increment failed" + die "TPM counter increment failed for rollback prevention. Please reflash firmware and choose TPM Reset reset option" } check_config() { @@ -318,40 +317,6 @@ replace_config() { rm -f ${CONFIG_FILE}.tmp } -# Set a config variable in a specific file to a given value - replace it if it -# exists, or add it. If added, the variable will be exported. -set_config() { - CONFIG_FILE="$1" - CONFIG_OPTION="$2" - NEW_SETTING="$3" - - if grep -q "$CONFIG_OPTION" "$CONFIG_FILE"; then - replace_config "$CONFIG_FILE" "$CONFIG_OPTION" "$NEW_SETTING" - else - echo "export $CONFIG_OPTION=\"$NEW_SETTING\"" >>"$CONFIG_FILE" - fi -} - -# Set a value in config.user, re-combine configs, and update configs in the -# environment. -set_user_config() { - CONFIG_OPTION="$1" - NEW_SETTING="$2" - - set_config /etc/config.user "$CONFIG_OPTION" "$NEW_SETTING" - combine_configs - . /tmp/config -} - -# Load a config value to a variable, defaulting to empty. Does not fail if the -# config is not set (since it would expand to empty by default). -load_config_value() { - local config_name="$1" - if grep -q "$config_name=" /tmp/config; then - grep "$config_name=" /tmp/config | tail -n1 | cut -f2 -d '=' | tr -d '"' - fi -} - # 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.