2023-02-08 21:01:48 +00:00
#!/bin/bash
2019-08-15 18:36:05 +00:00
# Automated setup of TPM, GPG keys, and disk
set -o pipefail
2023-03-28 19:51:45 +00:00
## External files sourced
2023-02-18 17:58:43 +00:00
. /etc/functions
2023-03-28 19:51:45 +00:00
. /etc/luks-functions
. /tmp/config
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2019-08-15 18:36:05 +00:00
# use TERM to exit on error
trap "exit 1" TERM
export TOP_PID=$$
## Static local variables
CLEAR="--clear"
CONTINUE="--yes-button Continue"
CANCEL="--no-button Cancel"
2022-11-09 16:51:27 +00:00
HEIGHT="0"
WIDTH="80"
2019-08-15 18:36:05 +00:00
USER_PIN_DEF=123456
ADMIN_PIN_DEF=12345678
TPM_PASS_DEF=12345678
2022-03-10 14:55:08 +00:00
USER_PIN=""
ADMIN_PIN=""
TPM_PASS=""
2023-11-07 18:20:31 +00:00
GPG_GEN_KEY_IN_MEMORY="n"
GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD="n"
2022-03-10 14:55:08 +00:00
2022-06-02 17:52:51 +00:00
#Circumvent Librem Key/Nitrokey HOTP firmware bug https://github.com/osresearch/heads/issues/1167
MAX_HOTP_GPG_PIN_LENGTH=25
2022-03-10 14:55:08 +00:00
# What are the Security components affected by custom passwords
CUSTOM_PASS_AFFECTED_COMPONENTS=""
2023-10-25 21:01:01 +00:00
# Default GPG Algorithm is RSA
GPG_ALGO="RSA"
2023-10-18 17:15:48 +00:00
# Default RSA key length
2023-10-31 15:42:57 +00:00
RSA_KEY_LENGTH=3072
2020-11-24 11:48:41 +00:00
2020-01-02 16:29:11 +00:00
GPG_USER_NAME="OEM Key"
2023-10-18 17:15:48 +00:00
GPG_KEY_NAME=$(date +%Y%m%d%H%M%S)
2020-01-02 16:29:11 +00:00
GPG_USER_MAIL="oem-${GPG_KEY_NAME}@example.com"
GPG_USER_COMMENT="OEM-generated key"
2020-10-23 23:38:30 +00:00
SKIP_BOOT="n"
2020-07-07 08:32:22 +00:00
2019-08-15 18:36:05 +00:00
## functions
die() {
2023-10-18 17:15:48 +00:00
local msg=$1
if [ -n "$msg" ]; then
echo -e "\n$msg"
fi
kill -s TERM $TOP_PID
exit 1
2019-08-15 18:36:05 +00:00
}
2023-10-18 17:15:48 +00:00
whiptail_error() {
2019-08-15 18:36:05 +00:00
local msg=$1
if [ "$msg" = "" ]; then
die "whiptail error: An error msg is required"
fi
2021-11-23 20:37:09 +00:00
whiptail $BG_COLOR_ERROR --msgbox "${msg}\n\n" $HEIGHT $WIDTH $BG_COLOR_ERROR --title "Error"
2019-08-15 18:36:05 +00:00
}
2023-10-18 17:15:48 +00:00
whiptail_error_die() {
2019-08-15 18:36:05 +00:00
whiptail_error "$@"
die
}
2023-11-03 20:38:41 +00:00
mount_boot() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-11-03 20:38:41 +00:00
# Mount local disk if it is not already mounted.
# Added so that 'o' can be typed early at boot to enter directly into OEM Factory Reset
if ! grep -q /boot /proc/mounts; then
# try to mount if CONFIG_BOOT_DEV exists
if [ -e "$CONFIG_BOOT_DEV" ]; then
mount -o ro $CONFIG_BOOT_DEV /boot || die "Failed to mount $CONFIG_BOOT_DEV. Please change boot device under Configuration > Boot Device"
fi
fi
}
2023-10-25 21:01:01 +00:00
#Generate a gpg master key: no expiration date, RSA 4096 bits
2023-10-18 17:15:48 +00:00
#This key will be used to sign 3 subkeys: encryption, authentication and signing
2023-10-26 20:50:10 +00:00
#The master key and subkeys will be copied to backup, and the subkeys moved from memory keyring to the smartcard
2023-10-18 17:15:48 +00:00
generate_inmemory_RSA_master_and_subkeys() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
echo "Generating GPG key material in memory:"
echo "Generating GPG RSA ${RSA_KEY_LENGTH} bits master key..."
# Generate GPG master key
{
2023-10-30 15:37:31 +00:00
echo "Key-Type: RSA" # RSA key
echo "Key-Length: ${RSA_KEY_LENGTH}" # RSA key length
echo "Key-Usage: sign" # RSA key usage
echo "Name-Real: ${GPG_USER_NAME}" # User name
echo "Name-Comment: ${GPG_USER_COMMENT}" # User comment
echo "Name-Email: ${GPG_USER_MAIL}" # User email
echo "Expire-Date: 0" # No expiration date
echo "Passphrase: ${ADMIN_PIN}" # Admin PIN
echo "%commit" # Commit changes
2023-10-26 20:50:10 +00:00
} | gpg --command-fd=0 --status-fd=1 --batch --gen-key >/tmp/gpg_card_edit_output 2>&1
2023-10-18 17:15:48 +00:00
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key generation failed!\n\n$ERROR"
fi
echo "Generating GPG RSA ${RSA_KEY_LENGTH} bits signing subkey..."
# Add signing subkey
{
2023-10-30 15:37:31 +00:00
echo addkey # add key in --edit-key mode
echo 4 # RSA (sign only)
echo ${RSA_KEY_LENGTH} # Signing key size set to RSA_KEY_LENGTH
echo 0 # No expiration date
echo ${ADMIN_PIN} # Local keyring admin pin
echo y # confirm
echo save # save changes and commit to keyring
2023-10-18 17:15:48 +00:00
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --edit-key "${GPG_USER_MAIL}" \
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key signing subkey generation failed!\n\n$ERROR"
fi
echo "Generating GPG RSA ${RSA_KEY_LENGTH} bits encryption subkey..."
#Add encryption subkey
{
2023-10-30 15:37:31 +00:00
echo addkey # add key in --edit-key mode
echo 6 # RSA (encrypt only)
echo ${RSA_KEY_LENGTH} # Encryption key size set to RSA_KEY_LENGTH
echo 0 # No expiration date
echo ${ADMIN_PIN} # Local keyring admin pin
echo y # confirm
echo save # save changes and commit to keyring
2023-10-18 17:15:48 +00:00
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --edit-key "${GPG_USER_MAIL}" \
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key encryption subkey generation failed!\n\n$ERROR"
fi
echo "Generating GPG RSA ${RSA_KEY_LENGTH} bits authentication subkey..."
#Add authentication subkey
{
#Authentication subkey needs gpg in expert mode to select RSA custom mode (8)
# in order to disable encryption and signing capabilities of subkey
# and then enable authentication capability
2023-10-30 15:37:31 +00:00
echo addkey # add key in --edit-key mode
echo 8 # RSA (set your own capabilities)
echo S # disable sign capability
echo E # disable encryption capability
echo A # enable authentication capability
echo Q # Quit
echo ${RSA_KEY_LENGTH} # Authentication key size set to RSA_KEY_LENGTH
echo 0 # No expiration date
echo ${ADMIN_PIN} # Local keyring admin pin
echo y # confirm
echo save # save changes and commit to keyring
2023-10-18 17:15:48 +00:00
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --expert --edit-key "${GPG_USER_MAIL}" \
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key authentication subkey generation failed!\n\n$ERROR"
fi
DEBUG "Setting public key to ultimate trust..."
#Set the public key to the ultimate trust
{
2023-10-30 15:37:31 +00:00
echo trust # trust key in --edit-key mode
echo 5 # ultimate trust
echo y # confirm
echo save # save changes and commit to keyring
2023-10-18 17:15:48 +00:00
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --edit-key "${GPG_USER_MAIL}" \
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key setting public key to ultimate trust failed!\n\n$ERROR"
fi
}
2023-10-25 21:01:01 +00:00
#Generate a gpg master key: no expiration date, p256 key (ECC)
#This key will be used to sign 3 subkeys: encryption, authentication and signing
2023-10-26 20:50:10 +00:00
#The master key and subkeys will be copied to backup, and the subkeys moved from memory keyring to the smartcard
2023-10-25 21:01:01 +00:00
generate_inmemory_p256_master_and_subkeys() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-25 21:01:01 +00:00
2023-10-26 20:50:10 +00:00
echo "Generating GPG p256 bits master key..."
{
2023-10-30 15:37:31 +00:00
echo "Key-Type: ECDSA" # ECDSA key
echo "Key-Curve: nistp256" # ECDSA key curve
echo "Key-Usage: cert" # ECDSA key usage
echo "Name-Real: ${GPG_USER_NAME}" # User name
echo "Name-Comment: ${GPG_USER_COMMENT}" # User comment
echo "Name-Email: ${GPG_USER_MAIL}" # User email
echo "Passphrase: ${ADMIN_PIN}" # Local keyring admin pin
echo "Expire-Date: 0" # No expiration date
echo "%commit" # Commit changes
} | gpg --expert --batch --command-fd=0 --status-fd=1 --pinentry-mode=loopback --generate-key \
2023-10-26 20:50:10 +00:00
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG p256 Key generation failed!\n\n$ERROR"
fi
2023-10-25 21:01:01 +00:00
2023-10-26 20:50:10 +00:00
#Keep Master key fingerprint for add key calls
MASTER_KEY_FP=$(gpg --list-secret-keys --with-colons | grep fpr | cut -d: -f10)
2023-10-25 21:01:01 +00:00
2023-10-26 20:50:10 +00:00
echo "Generating GPG nistp256 signing subkey..."
2023-10-25 21:01:01 +00:00
{
2023-10-30 15:37:31 +00:00
echo addkey # add key in --edit-key mode
echo 11 # ECC own set capability
echo Q # sign already present, do not modify
echo 3 # P-256
echo 0 # no expiration
echo ${ADMIN_PIN} # Local keyring admin pin
echo save # save changes and commit to keyring
} | gpg --expert --command-fd=0 --status-fd=1 --pinentry-mode=loopback --edit-key ${MASTER_KEY_FP} >/tmp/gpg_card_edit_output 2>&1
2023-10-25 21:01:01 +00:00
if [ $? -ne 0 ]; then
ERROR_MSG=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "Failed to add ECC nistp256 signing key to master key\n\n${ERROR_MSG}"
fi
2023-10-26 20:50:10 +00:00
echo "Generating GPG nistp256 encryption subkey..."
2023-10-25 21:01:01 +00:00
{
echo addkey
2023-10-30 15:37:31 +00:00
echo 12 # ECC own set capability
echo Q # Quit
echo 3 # P-256
echo 0 # no expiration
echo ${ADMIN_PIN} # Local keyring admin pin
echo save # save changes and commit to keyring
} | gpg --expert --command-fd=0 --status-fd=1 --pinentry-mode=loopback --edit-key ${MASTER_KEY_FP} >/tmp/gpg_card_edit_output 2>&1
2023-10-25 21:01:01 +00:00
if [ $? -ne 0 ]; then
ERROR_MSG=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "Failed to add ECC nistp256 encryption key to master key\n\n${ERROR_MSG}"
fi
2023-10-26 20:50:10 +00:00
echo "Generating GPG nistp256 authentication subkey..."
2023-10-25 21:01:01 +00:00
{
2023-10-30 15:37:31 +00:00
echo addkey # add key in --edit-key mode
echo 11 # ECC own set capability
echo S # deactivate sign
echo A # activate auth
echo Q # Quit
echo 3 # P-256
echo 0 # no expiration
echo ${ADMIN_PIN} # Local keyring admin pin
echo save # save changes and commit to keyring
} | gpg --expert --command-fd=0 --status-fd=1 --pinentry-mode=loopback --edit-key ${MASTER_KEY_FP} >/tmp/gpg_card_edit_output 2>&1
2023-10-25 21:01:01 +00:00
if [ $? -ne 0 ]; then
ERROR_MSG=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "Failed to add ECC nistp256 authentication key to master key\n\n${ERROR_MSG}"
fi
2023-10-30 15:37:31 +00:00
2023-10-31 20:32:12 +00:00
}
2023-10-25 21:01:01 +00:00
2023-10-18 17:15:48 +00:00
#Function to move current gpg keyring subkeys to card (keytocard)
2023-10-31 15:45:06 +00:00
# This is aimed to be used after having generated master key and subkeys in memory and having backed up them to a LUKS container
2023-10-18 17:15:48 +00:00
# This function will keytocard the subkeys from the master key in the keyring
# The master key will be kept in the keyring
# The master key was already used to sign the subkeys, so it is not needed anymore
2023-10-31 15:45:06 +00:00
# Delete the master key from the keyring once key to card is done (already backed up on LUKS private partition)
2023-10-18 17:15:48 +00:00
keytocard_subkeys_to_smartcard() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
2023-10-30 15:37:31 +00:00
#make sure usb ready and USB Security Dongle ready to communicate with
2023-10-18 17:15:48 +00:00
enable_usb
enable_usb_storage
gpg --card-status >/dev/null 2>&1 || die "Error getting GPG card status"
gpg_key_factory_reset
2023-10-26 20:50:10 +00:00
echo "Moving subkeys to smartcard..."
2023-10-18 17:15:48 +00:00
{
2023-10-30 15:37:31 +00:00
echo "key 1" #Toggle on Signature key in --edit-key mode on local keyring
echo "keytocard" #Move Signature key to smartcard
echo "1" #Select Signature key keyslot on smartcard
echo "${ADMIN_PIN}" #Local keyring Subkey PIN
echo "${ADMIN_PIN_DEF}" #Smartcard Admin PIN
echo "0" #No expiration date
echo "key 1" #Toggle off Signature key
echo "key 2" #Toggle on Encryption key
echo "keytocard" #Move Encryption key to smartcard
echo "2" #Select Encryption key keyslot on smartcard
echo "${ADMIN_PIN}" #Local keyring Subkey PIN
echo "${ADMIN_PIN_DEF}" #Smartcard Admin PIN
echo "key 2" #Toggle off Encryption key
echo "key 3" #Toggle on Authentication key
echo "keytocard" #Move Authentication key to smartcard
echo "3" #Select Authentication key keyslot on smartcard
echo "${ADMIN_PIN}" #Local keyring Subkey PIN
echo "${ADMIN_PIN_DEF}" #Smartcard Admin PIN
echo "key 3" #Toggle off Authentication key
echo "save" #Save changes and commit to keyring
} | gpg --expert --command-fd=0 --status-fd=1 --pinentry-mode=loopback --edit-key "${GPG_USER_MAIL}" \
2023-10-18 17:15:48 +00:00
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key moving subkeys to smartcard failed!\n\n$ERROR"
fi
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
}
#Whiptail prompt to insert to be wiped thumb drive
prompt_insert_to_be_wiped_thumb_drive() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
#Whiptail warning about having only desired to be wiped thumb drive inserted
whiptail $BG_COLOR_WARNING --title 'WARNING: Please insert the thumb drive to be wiped' \
2023-11-13 18:54:37 +00:00
--msgbox "The thumb drive will be WIPED next.\n\nPlease connect only the thumb drive to be wiped and disconnect others." 0 80 ||
2023-10-18 17:15:48 +00:00
die "Error displaying warning about having only desired to be wiped thumb drive inserted"
}
#export master key and subkeys to thumbdrive's private LUKS contained partition
export_master_key_subkeys_and_revocation_key_to_private_LUKS_container() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
#Sanity check on passed arguments
while [ $# -gt 0 ]; do
case "$1" in
--mode)
mode="$2"
shift
shift
;;
--device)
device="$2"
shift
shift
;;
--mountpoint)
mountpoint="$2"
shift
shift
;;
--pass)
2023-10-26 20:50:10 +00:00
pass="${2}"
2023-10-18 17:15:48 +00:00
shift
shift
;;
*)
die "Error: unknown argument: $1"
;;
esac
done
mount-usb --mode "$mode" --device "$device" --mountpoint "$mountpoint" --pass "$pass" || die "Error mounting thumb drive's private partition"
#Export master key and subkeys to thumb drive
DEBUG "Exporting master key and subkeys to private LUKS container's partition..."
2023-10-26 20:50:10 +00:00
2023-10-30 16:56:27 +00:00
gpg --export-secret-key --armor --pinentry-mode loopback --passphrase="${pass}" "${GPG_USER_MAIL}" >"$mountpoint"/privkey.sec ||
2023-10-18 17:15:48 +00:00
die "Error exporting master key to private LUKS container's partition"
2023-10-30 15:37:31 +00:00
gpg --export-secret-subkeys --armor --pinentry-mode loopback --passphrase="${pass}" "${GPG_USER_MAIL}" >"$mountpoint"/subkeys.sec ||
2023-10-18 17:15:48 +00:00
die "Error exporting subkeys to private LUKS container's partition"
#copy whole keyring to thumb drive, including revocation key and trust database
cp -af ~/.gnupg "$mountpoint"/.gnupg || die "Error copying whole keyring to private LUKS container's partition"
#Unmount private LUKS container's mount point
umount "$mountpoint" || die "Error unmounting private LUKS container's mount point"
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
}
#Export public key to thumb drive's public partition
export_public_key_to_thumbdrive_public_partition() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
#Sanity check on passed arguments
while [ $# -gt 0 ]; do
case "$1" in
--mode)
mode="$2"
shift
shift
;;
--device)
device="$2"
shift
shift
;;
--mountpoint)
mountpoint="$2"
shift
shift
;;
*)
die "Error: unknown argument: $1"
;;
esac
done
#pass non-empty arguments to --pass, --mountpoint, --device, --mode
mount-usb --device "$device" --mode "$mode" --mountpoint "$mountpoint" || die "Error mounting thumb drive's public partition"
gpg --export --armor "${GPG_USER_MAIL}" >"$mountpoint"/pubkey.asc || die "Error exporting public key to thumb drive's public partition"
umount "$mountpoint" || die "Error unmounting thumb drive's public partition"
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
}
2023-11-13 18:54:37 +00:00
# Select thumb drive and LUKS container size for GPG key export
# Sets variables containing selections:
# - thumb_drive
# - thumb_drive_luks_percent
select_thumb_drive_for_key_material() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-11-13 18:54:37 +00:00
2023-10-18 17:15:48 +00:00
#enable usb storage
enable_usb
enable_usb_storage
2023-11-09 22:01:35 +00:00
2023-11-13 19:52:09 +00:00
prompt_insert_to_be_wiped_thumb_drive
2023-11-09 22:01:35 +00:00
#loop until user chooses a disk
thumb_drive=""
while [ -z "$thumb_drive" ]; do
#list usb storage devices
list_usb_storage disks >/tmp/usb_disk_list
2023-11-13 18:54:37 +00:00
# Abort if:
# - no disks found (prevent file_selector's nonsense prompt)
# - file_selector fails for any reason
# - user aborts (file_selector succeeds but FILE is empty)
if [ $(cat /tmp/usb_disk_list | wc -l) -gt 0 ] &&
file_selector --show-size "/tmp/usb_disk_list" "Select USB device to partition" &&
[ -n "$FILE" ]; then
# Obtain size of thumb drive to be wiped with fdisk
disk_size_bytes="$(blockdev --getsize64 "$FILE")"
if [ "$disk_size_bytes" -lt "$((128*1024*1024))" ]; then
warn "Thumb drive size is less than 128MB!"
warn "LUKS container needs to be at least 8MB!"
warn "If the next operation fails, try with a bigger thumb drive"
fi
2023-11-13 19:37:19 +00:00
select_luks_container_size_percent
thumb_drive_luks_percent="$(cat /tmp/luks_container_size_percent)"
if ! confirm_thumb_drive_format "$FILE" "$thumb_drive_luks_percent"; then
2023-11-13 18:54:37 +00:00
warn "Thumb drive wipe aborted by user!"
continue
2023-11-09 22:01:35 +00:00
fi
2023-11-13 18:54:37 +00:00
#User chose and confirmed a thumb drive and its size to be wiped
thumb_drive=$FILE
2023-11-09 22:01:35 +00:00
else
#No USB storage device detected
warn "No USB storage device detected! Aborting OEM Factory Reset / Re-Ownership"
sleep 3
die "No USB storage device detected! User decided to not wipe any thumb drive"
fi
done
2023-11-13 18:54:37 +00:00
thumb_drive_luks_percent="$(cat /tmp/luks_container_size_percent)"
}
#Wipe a thumb drive and export master key and subkeys to it
# $1 - thumb drive block device
# $2 - LUKS container percentage [1-99]
wipe_thumb_drive_and_copy_gpg_key_material() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-11-13 18:54:37 +00:00
local thumb_drive thumb_drive_luks_percent
thumb_drive="$1"
thumb_drive_luks_percent="$2"
2023-10-18 17:15:48 +00:00
#Wipe thumb drive with a LUKS container of size $(cat /tmp/luks_container_size_percent)
2023-11-13 19:37:19 +00:00
prepare_thumb_drive "$thumb_drive" "$thumb_drive_luks_percent" "${ADMIN_PIN}"
2023-10-18 17:15:48 +00:00
#Export master key and subkeys to thumb drive first partition
2023-10-26 20:50:10 +00:00
export_master_key_subkeys_and_revocation_key_to_private_LUKS_container --mode rw --device "$thumb_drive"1 --mountpoint /media --pass "${ADMIN_PIN}"
2023-10-18 17:15:48 +00:00
#Export public key to thumb drive's public partition
export_public_key_to_thumbdrive_public_partition --mode rw --device "$thumb_drive"2 --mountpoint /media
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
}
gpg_key_factory_reset() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
#enable usb storage
enable_usb
2019-08-15 18:36:05 +00:00
# Factory reset GPG card
2023-11-02 16:08:52 +00:00
echo "GPG factory reset of USB Security Dongle's smartcard..."
2019-08-15 18:36:05 +00:00
{
2023-10-30 15:37:31 +00:00
echo admin # admin menu
echo factory-reset # factory reset smartcard
echo y # confirm
echo yes # confirm
2019-08-15 18:36:05 +00:00
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --card-edit \
2023-10-18 17:15:48 +00:00
>/tmp/gpg_card_edit_output 2>&1
2019-08-15 18:36:05 +00:00
if [ $? -ne 0 ]; then
2023-10-18 17:15:48 +00:00
ERROR=$(cat /tmp/gpg_card_edit_output)
2019-08-15 18:36:05 +00:00
whiptail_error_die "GPG Key factory reset failed!\n\n$ERROR"
fi
2020-08-05 09:49:06 +00:00
# If Nitrokey Storage is inserted, reset AES keys as well
2023-10-18 17:15:48 +00:00
if lsusb | grep -q "20a0:4109" && [ -x /bin/hotp_verification ]; then
2020-08-05 09:49:06 +00:00
/bin/hotp_verification regenerate ${ADMIN_PIN_DEF}
2023-11-08 11:10:47 +00:00
killall -9 scdaemon
2020-06-30 16:29:42 +00:00
fi
2023-02-02 02:12:45 +00:00
# Toggle forced sig (good security practice, forcing PIN request for each signature request)
if gpg --card-status | grep "Signature PIN" | grep -q "not forced"; then
2023-10-18 17:15:48 +00:00
DEBUG "GPG toggling forcesig on since off..."
2023-02-02 02:12:45 +00:00
{
2023-10-30 15:37:31 +00:00
echo admin # admin menu
echo forcesig # toggle forcesig
echo ${ADMIN_PIN_DEF} # local keyring PIN
2023-02-02 02:12:45 +00:00
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --card-edit \
2023-10-18 17:15:48 +00:00
>/tmp/gpg_card_edit_output 2>&1
2023-02-02 02:12:45 +00:00
if [ $? -ne 0 ]; then
2023-10-18 17:15:48 +00:00
ERROR=$(cat /tmp/gpg_card_edit_output)
2023-02-02 02:12:45 +00:00
whiptail_error_die "GPG Key forcesig toggle on failed!\n\n$ERROR"
fi
fi
2023-09-05 10:28:52 +00:00
# use p256 for key generation if requested
2023-10-18 17:15:48 +00:00
if [ "$GPG_ALGO" = "p256" ]; then
{
2023-10-30 15:37:31 +00:00
echo admin # admin menu
echo key-attr # key attributes
echo 2 # ECC
echo 3 # P-256
echo ${ADMIN_PIN_DEF} # local keyring PIN
echo 2 # ECC
echo 3 # P-256
echo ${ADMIN_PIN_DEF} # local keyring PIN
echo 2 # ECC
echo 3 # P-256
echo ${ADMIN_PIN_DEF} # local keyring PIN
} | gpg --expert --command-fd=0 --status-fd=1 --pinentry-mode=loopback --card-edit \
2023-10-18 17:15:48 +00:00
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
2023-10-30 15:37:31 +00:00
whiptail_error_die "Setting key to NIST-P256 in USB Security Dongle failed."
2023-10-18 17:15:48 +00:00
fi
2023-09-05 10:28:52 +00:00
# fallback to RSA key generation by default
2023-10-30 16:56:27 +00:00
elif [ "$GPG_ALGO" = "RSA" ]; then
2023-10-18 17:15:48 +00:00
DEBUG "GPG setting RSA key length to ${RSA_KEY_LENGTH} bits..."
# Set RSA key length
{
echo admin
echo key-attr
echo 1 # RSA
echo ${RSA_KEY_LENGTH} #Signing key size set to RSA_KEY_LENGTH
2023-10-30 15:37:31 +00:00
echo ${ADMIN_PIN_DEF} #Local keyring PIN
2023-10-18 17:15:48 +00:00
echo 1 # RSA
echo ${RSA_KEY_LENGTH} #Encryption key size set to RSA_KEY_LENGTH
2023-10-30 15:37:31 +00:00
echo ${ADMIN_PIN_DEF} #Local keyring PIN
2023-10-18 17:15:48 +00:00
echo 1 # RSA
echo ${RSA_KEY_LENGTH} #Authentication key size set to RSA_KEY_LENGTH
2023-10-30 15:37:31 +00:00
echo ${ADMIN_PIN_DEF} #Local keyring PIN
2023-10-18 17:15:48 +00:00
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --card-edit \
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
2023-10-30 15:37:31 +00:00
whiptail_error_die "Setting key attributed to RSA ${RSA_KEY_LENGTH} bits in USB Security Dongle failed."
2023-10-18 17:15:48 +00:00
fi
2023-10-26 20:50:10 +00:00
else
#Unknown GPG_ALGO
whiptail_error_die "Unknown GPG_ALGO: $GPG_ALGO"
2020-11-24 11:48:41 +00:00
fi
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-18 17:15:48 +00:00
}
generate_OEM_gpg_keys() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-25 21:01:01 +00:00
2023-10-26 20:50:10 +00:00
#This function simply generates subkeys in smartcard following smarcard config from gpg_key_factory_reset
2023-11-02 16:08:52 +00:00
echo "Generating GPG keys in USB Security Dongle's smartcard..."
2023-10-26 20:50:10 +00:00
{
2023-10-30 15:37:31 +00:00
echo admin # admin menu
echo generate # generate keys
echo n # Do not export keys
echo ${ADMIN_PIN_DEF} # Default admin PIN since we just factory reset
echo ${USER_PIN_DEF} # Default user PIN since we just factory reset
echo 0 # No key expiration
echo ${GPG_USER_NAME} # User name
echo ${GPG_USER_MAIL} # User email
echo ${GPG_USER_COMMENT} # User comment
echo ${USER_PIN_DEF} # Default user PIN since we just factory reset
2023-10-26 20:50:10 +00:00
} | gpg --command-fd=0 --status-fd=2 --pinentry-mode=loopback --card-edit \
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key automatic keygen failed!\n\n$ERROR"
2019-08-15 18:36:05 +00:00
fi
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2019-08-15 18:36:05 +00:00
}
2020-03-26 14:05:51 +00:00
2023-10-18 17:15:48 +00:00
gpg_key_change_pin() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-27 15:18:20 +00:00
DEBUG "Changing GPG key PIN"
2019-11-07 19:01:49 +00:00
# 1 = user PIN, 3 = admin PIN
PIN_TYPE=$1
2023-10-27 15:18:20 +00:00
PIN_ORIG=${2}
PIN_NEW=${3}
2019-11-07 19:01:49 +00:00
# Change PIN
{
2023-10-30 15:37:31 +00:00
echo admin # admin menu
echo passwd # change PIN
echo ${PIN_TYPE} # 1 = user PIN, 3 = admin PIN
echo ${PIN_ORIG} # old PIN
echo ${PIN_NEW} # new PIN
echo ${PIN_NEW} # confirm new PIN
echo q # quit
2019-11-07 19:01:49 +00:00
echo q
} | gpg --command-fd=0 --status-fd=2 --pinentry-mode=loopback --card-edit \
2023-10-18 17:15:48 +00:00
>/tmp/gpg_card_edit_output 2>&1
2019-11-07 19:01:49 +00:00
if [ $? -ne 0 ]; then
2023-10-18 17:15:48 +00:00
ERROR=$(cat /tmp/gpg_card_edit_output | fold -s)
2019-11-07 19:01:49 +00:00
whiptail_error_die "GPG Key PIN change failed!\n\n$ERROR"
fi
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2019-11-07 19:01:49 +00:00
}
2019-08-15 18:36:05 +00:00
2023-10-18 17:15:48 +00:00
generate_checksums() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-27 15:18:20 +00:00
2019-08-15 18:36:05 +00:00
# ensure /boot mounted
2023-10-18 17:15:48 +00:00
if ! grep -q /boot /proc/mounts; then
2019-08-15 18:36:05 +00:00
mount -o rw /boot || whiptail_error_die "Unable to mount /boot"
else
mount -o remount,rw /boot || whiptail_error_die "Unable to mount /boot"
fi
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following conditions:\n 1-Every boot if no Disk Unlock Key was added to the TPM\n 2-If the TPM fails (hardware failure)\n 3-If the firmware has been tampered with/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
#Check if previous LUKS TPM Disk Unlock Key was set
2022-04-13 18:24:59 +00:00
if [ -e /boot/kexec_key_devices.txt ]; then
TPM_DISK_ENCRYPTION_KEY_SET=1
fi
2019-08-15 18:36:05 +00:00
# clear any existing checksums/signatures
rm /boot/kexec* 2>/dev/null
# create Heads TPM counter
2023-10-18 17:15:48 +00:00
if [ "$CONFIG_TPM" = "y" ]; then
if [ "$CONFIG_IGNORE_ROLLBACK" != "y" ]; then
tpmr counter_create \
-pwdc '' \
-la -3135106223 |
tee /tmp/counter ||
whiptail_error_die "Unable to create TPM counter"
TPM_COUNTER=$(cut -d: -f1 </tmp/counter)
# increment TPM counter
increment_tpm_counter $TPM_COUNTER >/dev/null 2>&1 ||
whiptail_error_die "Unable to increment tpm counter"
# create rollback file
sha256sum /tmp/counter-$TPM_COUNTER >/boot/kexec_rollback.txt 2>/dev/null ||
whiptail_error_die "Unable to create rollback file"
else
## needs to exist for initial call to unseal-hotp
echo "0" >/boot/kexec_hotp_counter
fi
2022-08-25 18:43:31 +00:00
fi
2019-08-15 18:36:05 +00:00
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following conditions:\n 1-Every boot if no Disk Unlock Key was added to the TPM\n 2-If the TPM fails (hardware failure)\n 3-If the firmware has been tampered with/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
# set default boot option only if no LUKS TPM Disk Unlock Key previously set
2022-04-13 18:24:59 +00:00
if [ -z "$TPM_DISK_ENCRYPTION_KEY_SET" ]; then
set_default_boot_option
fi
2019-08-15 18:36:05 +00:00
2023-10-31 20:32:12 +00:00
DEBUG "Generating hashes"
2022-12-31 17:41:24 +00:00
(
set -e -o pipefail
cd /boot
2023-10-18 17:15:48 +00:00
find ./ -type f ! -path './kexec*' -print0 |
xargs -0 sha256sum >/boot/kexec_hashes.txt 2>/dev/null
print_tree >/boot/kexec_tree.txt
2022-12-31 17:41:24 +00:00
)
[ $? -eq 0 ] || whiptail_error_die "Error generating kexec hashes"
2019-08-15 18:36:05 +00:00
2023-10-18 17:15:48 +00:00
param_files=$(find /boot/kexec*.txt)
[ -z "$param_files" ] &&
whiptail_error_die "No kexec parameter files to sign"
2019-08-15 18:36:05 +00:00
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "y" -a "$GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD" = "n" ]; then
#The local keyring used to generate in memory subkeys is still valid since no key has been moved to smartcard
#Local keyring passwd is ADMIN_PIN. We need to set USER_PIN to ADMIN_PIN to be able to sign next in this boot session
2023-10-31 20:32:12 +00:00
DEBUG "Setting GPG User PIN to GPG Admin PIN so local keyring can be used to detach-sign kexec files next"
USER_PIN=$ADMIN_PIN
fi
2023-11-07 18:20:31 +00:00
DEBUG "Detach-signing boot files under kexec.sig: ${param_files}"
2019-08-15 18:36:05 +00:00
if sha256sum $param_files 2>/dev/null | gpg \
2023-10-18 17:15:48 +00:00
--pinentry-mode loopback \
2023-10-26 20:50:10 +00:00
--passphrase "${USER_PIN}" \
2023-10-18 17:15:48 +00:00
--digest-algo SHA256 \
--detach-sign \
-a \
>/boot/kexec.sig 2>/tmp/error; then
2019-08-15 18:36:05 +00:00
# successful - update the validated params
2023-10-18 17:15:48 +00:00
if ! check_config /boot >/dev/null 2>/tmp/error; then
2019-08-15 18:36:05 +00:00
cat /tmp/error
ret=1
else
ret=0
fi
else
cat /tmp/error
ret=1
fi
# done writing to /boot, switch back to RO
mount -o ro,remount /boot
2023-10-18 17:15:48 +00:00
if [ $ret = 1 ]; then
2020-07-10 22:29:43 +00:00
ERROR=$(tail -n 1 /tmp/error | fold -s)
2019-08-15 18:36:05 +00:00
whiptail_error_die "Error signing kexec boot files:\n\n$ERROR"
fi
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2019-08-15 18:36:05 +00:00
}
2023-10-18 17:15:48 +00:00
set_default_boot_option() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-27 15:18:20 +00:00
2019-08-15 18:36:05 +00:00
option_file="/tmp/kexec_options.txt"
tmp_menu_file="/tmp/kexec/kexec_menu.txt"
hash_file="/boot/kexec_default_hashes.txt"
mkdir -p /tmp/kexec/
rm $option_file 2>/dev/null
# parse boot options from grub.cfg
2023-10-18 17:15:48 +00:00
for i in $(find /boot -name "grub.cfg"); do
kexec-parse-boot "/boot" "$i" >>$option_file
2019-08-15 18:36:05 +00:00
done
2020-07-29 03:24:32 +00:00
# FC29/30+ may use BLS format grub config files
# https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault
# only parse these if $option_file is still empty
if [ ! -s $option_file ] && [ -d "/boot/loader/entries" ]; then
2023-10-18 17:15:48 +00:00
for i in $(find /boot -name "grub.cfg"); do
kexec-parse-bls "/boot" "$i" "/boot/loader/entries" >>$option_file
done
2020-07-29 03:24:32 +00:00
fi
2023-10-18 17:15:48 +00:00
[ ! -s $option_file ] &&
whiptail_error_die "Failed to parse any boot options"
2019-08-15 18:36:05 +00:00
# sort boot options
2023-10-18 17:15:48 +00:00
sort -r $option_file | uniq >$tmp_menu_file
2019-08-15 18:36:05 +00:00
## save first option as default
2023-10-18 17:15:48 +00:00
entry=$(head -n 1 $tmp_menu_file | tail -1)
2019-08-15 18:36:05 +00:00
# clear existing default configs
rm "/boot/kexec_default.*.txt" 2>/dev/null
2020-07-29 05:18:57 +00:00
# get correct index for entry
index=$(grep -n "$entry" $option_file | cut -f1 -d ':')
2019-08-15 18:36:05 +00:00
# write new config
2023-10-18 17:15:48 +00:00
echo "$entry" >/boot/kexec_default.$index.txt
2019-08-15 18:36:05 +00:00
# validate boot option
2023-10-18 17:15:48 +00:00
(cd /boot && /bin/kexec-boot -b "/boot" -e "$entry" -f |
xargs sha256sum >$hash_file 2>/dev/null) ||
whiptail_error_die "Failed to create hashes of boot files"
2023-10-27 15:18:20 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2019-08-15 18:36:05 +00:00
}
2023-10-18 17:15:48 +00:00
report_integrity_measurements() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-10-27 15:18:20 +00:00
2022-03-23 20:00:08 +00:00
#check for GPG key in keyring
2023-10-18 17:15:48 +00:00
GPG_KEY_COUNT=$(gpg -k 2>/dev/null | wc -l)
if [ "$GPG_KEY_COUNT" -ne 0 ]; then
2022-03-23 20:00:08 +00:00
# Check and report TOTP
# update the TOTP code every thirty seconds
2023-10-18 17:15:48 +00:00
date=$(date "+%Y-%m-%d %H:%M:%S %Z")
seconds=$(date "+%s")
half=$(expr \( "$seconds" % 60 \) / 30)
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM" != "y" ]; then
2022-03-23 20:00:08 +00:00
TOTP="NO TPM"
elif [ "$half" != "$last_half" ]; then
2023-10-18 17:15:48 +00:00
last_half=$half
TOTP=$(unseal-totp) >/dev/null 2>&1
2022-03-23 20:00:08 +00:00
fi
# Check and report on HOTP status
if [ -x /bin/hotp_verification ]; then
2023-10-18 17:15:48 +00:00
HOTP=$(unseal-hotp) >/dev/null 2>&1
2022-03-23 20:00:08 +00:00
enable_usb
2023-10-18 17:15:48 +00:00
if ! hotp_verification info >/dev/null 2>&1; then
2023-10-30 15:37:31 +00:00
whiptail $CONFIG_WARNING_BG_COLOR --title 'WARNING: Please insert your HOTP enabled USB Security Dongle' --msgbox "Your HOTP enabled USB Security Dongle was not detected.\n\nPlease remove it and insert it again." 0 80
2022-03-23 20:00:08 +00:00
fi
# Don't output HOTP codes to screen, so as to make replay attacks harder
hotp_verification check $HOTP
case "$?" in
2023-10-18 17:15:48 +00:00
0)
HOTP="Success"
;;
4)
HOTP="Invalid code"
MAIN_MENU_BG_COLOR=$CONFIG_ERROR_BG_COLOR
;;
*)
2023-10-30 15:37:31 +00:00
HOTP="Error checking code, Insert USB Security Dongle and retry"
2023-10-18 17:15:48 +00:00
MAIN_MENU_BG_COLOR=$CONFIG_WARNING_BG_COLOR
;;
esac
else
HOTP='N/A'
2022-03-23 20:00:08 +00:00
fi
# Check for detached signed digest and report on /boot integrity status
check_config /boot force
TMP_HASH_FILE="/tmp/kexec/kexec_hashes.txt"
2023-10-18 17:15:48 +00:00
if (cd /boot && sha256sum -c "$TMP_HASH_FILE" >/tmp/hash_output); then
2022-03-23 20:00:08 +00:00
HASH="OK"
2023-10-18 17:15:48 +00:00
else
HASH="ALTERED"
2022-03-23 20:00:08 +00:00
fi
2023-10-18 17:15:48 +00:00
#Show results
whiptail $MAIN_MENU_BG_COLOR --title "Measured Integrity Report" --msgbox "$date\nTOTP: $TOTP | HOTP: $HOTP\n/BOOT INTEGRITY: $HASH\n\nPress OK to continue or Ctrl+Alt+Delete to reboot" 0 80
2022-03-23 20:00:08 +00:00
fi
2023-10-30 15:37:31 +00:00
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2022-03-23 20:00:08 +00:00
}
2023-10-18 17:15:48 +00:00
usb_security_token_capabilities_check() {
2024-02-01 19:30:31 +00:00
TRACE_FUNC
2023-09-05 10:28:52 +00:00
enable_usb
# ... first set board config preference
if [ -n "$CONFIG_GPG_ALGO" ]; then
GPG_ALGO=$CONFIG_GPG_ALGO
DEBUG "Setting GPG_ALGO to (board-)configured: $CONFIG_GPG_ALGO"
fi
# ... overwrite with usb-token capability
2023-10-30 17:19:27 +00:00
if lsusb | grep -q "20a0:42b2"; then
2023-10-31 20:32:12 +00:00
GPG_ALGO="p256"
DEBUG "Nitrokey 3 detected: Setting GPG_ALGO to: $GPG_ALGO"
2023-10-30 17:19:27 +00:00
fi
2023-09-05 10:28:52 +00:00
}
2022-03-23 20:00:08 +00:00
2019-08-15 18:36:05 +00:00
## main script start
# check for args
if [ "$1" != "" ]; then
title_text=$1
else
2022-03-10 14:55:08 +00:00
title_text="OEM Factory Reset / Re-Ownership"
2019-08-15 18:36:05 +00:00
fi
if [ "$2" != "" ]; then
bg_color=$2
else
bg_color=""
fi
# show warning prompt
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM" = "y" ]; then
2022-03-10 14:55:08 +00:00
TPM_STR=" * ERASE the TPM and own it with a password\n"
2020-04-23 23:36:03 +00:00
else
TPM_STR=""
fi
2019-08-15 18:36:05 +00:00
if ! whiptail --yesno "
2022-03-10 14:55:08 +00:00
This operation will automatically:\n
2020-04-23 23:36:03 +00:00
$TPM_STR
* ERASE any keys or passwords on the GPG smart card,\n
2022-03-10 14:55:08 +00:00
reset it to a factory state, generate new keys\n
2022-04-29 20:58:34 +00:00
and optionally set custom PIN(s)\n
2020-04-23 23:36:03 +00:00
* Add the new GPG key to the firmware and reflash it\n
* Sign all of the files in /boot with the new GPG key\n\n
It requires that you already have an OS installed on a\n
2022-03-10 14:55:08 +00:00
dedicated /boot partition. Do you wish to continue?" \
2023-10-18 17:15:48 +00:00
$HEIGHT $WIDTH $CONTINUE $CANCEL $CLEAR $bg_color --title "$title_text"; then
2019-08-15 18:36:05 +00:00
exit 1
fi
2023-11-03 20:38:41 +00:00
#Make sure /boot is mounted if board config defines default
mount_boot
2022-03-23 20:00:08 +00:00
# We show current integrity measurements status and time
2023-10-30 18:01:37 +00:00
report_integrity_measurements
2022-03-23 20:00:08 +00:00
2023-11-03 18:34:40 +00:00
# Clear the screen
clear
2023-11-06 15:34:28 +00:00
#Prompt user for use of default configuration options
echo -e -n "Would you like to use default configuration options?\nIf N, you will be prompted for each option [Y/n]: "
read -n 1 use_defaults
2022-04-29 21:01:21 +00:00
if [ "$use_defaults" == "n" -o "$use_defaults" == "N" ]; then
2023-10-18 17:15:48 +00:00
#Give general guidance to user on how to answer prompts
2023-11-03 18:34:40 +00:00
echo
echo "****************************************************"
echo "**** Factory Reset / Re-Ownership Questionnaire ****"
echo "****************************************************"
echo "The following questionnaire will help you configure the security components of your system."
echo "Each prompt requires a single letter answer: eg. (Y/n)."
2023-10-30 17:57:02 +00:00
echo -e "If you don't know what to answer, pressing Enter will select the default answer for that prompt: eg. Y, above.\n"
2023-10-18 17:15:48 +00:00
# Re-ownership of encrypted disk key, content and passphrase
2023-11-03 18:34:40 +00:00
echo -e -n "\n\nWould you like to change the current LUKS Disk Recovery Key passphrase?\n (Highly recommended if you didn't install the Operating System yourself, so that past configured passphrase would not permit to access content.\n Note that without re-encrypting disk, a backed up header could be restored to access encrypted content with old passphrase) [y/N]: "
2023-10-18 17:15:48 +00:00
read -n 1 prompt_output
echo
if [ "$prompt_output" == "y" \
-o "$prompt_output" == "Y" ]; then
luks_new_Disk_Recovery_Key_passphrase_desired=1
echo -e "\n"
fi
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following conditions:\n 1-Every boot if no Disk Unlock Key was added to the TPM\n 2-If the TPM fails (hardware failure)\n 3-If the firmware has been tampered with/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
echo -e -n "Would you like to re-encrypt LUKS encrypted container and generate new LUKS Disk Recovery Key?\n (Highly recommended if you didn't install the operating system yourself: this would prevent any LUKS backed up header to be restored to access encrypted data) [y/N]: "
2023-10-18 17:15:48 +00:00
read -n 1 prompt_output
echo
if [ "$prompt_output" == "y" \
-o "$prompt_output" == "Y" ]; then
test_luks_current_disk_recovery_key_passphrase
luks_new_Disk_Recovery_Key_desired=1
echo -e "\n"
fi
#Prompt to ask if user wants to generate GPG key material in memory or on smartcard
2023-11-02 16:49:13 +00:00
echo -e -n "Would you like to format an encrypted USB Thumb drive to store GPG key material?\n (Required to enable GPG authentication) [y/N]: "
2023-10-18 17:15:48 +00:00
read -n 1 prompt_output
echo
2023-10-31 20:32:12 +00:00
if [ "$prompt_output" == "y" \
-o "$prompt_output" == "Y" ] \
2023-10-18 17:15:48 +00:00
; then
2023-11-07 18:20:31 +00:00
GPG_GEN_KEY_IN_MEMORY="y"
2023-11-01 18:10:42 +00:00
echo " ++++ Master key and subkeys will be generated in memory, backed up to dedicated LUKS container +++"
2023-11-02 16:08:52 +00:00
echo -e -n "Would you like in-memory generated subkeys to be copied to USB Security Dongle's smartcard?\n (Highly recommended so the smartcard is used on daily basis and backup is kept safe, but not required) [Y/n]: "
2023-10-31 20:32:12 +00:00
read -n 1 prompt_output
echo
if [ "$prompt_output" == "n" \
-o "$prompt_output" == "N" ]; then
2023-11-03 18:34:40 +00:00
warn "Subkeys will NOT be copied to USB Security Dongle's smartcard"
2023-11-01 18:10:42 +00:00
warn "Your GPG key material backup thumb drive should be cloned to a second thumb drive for redundancy for production environements"
2023-11-07 18:20:31 +00:00
GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD="n"
2023-10-31 20:32:12 +00:00
else
2023-11-02 16:08:52 +00:00
echo "++++ Subkeys will be copied to USB Security Dongle's smartcard ++++"
2023-11-01 18:10:42 +00:00
warn "Please keep your GPG key material backup thumb drive safe"
2023-11-07 18:20:31 +00:00
GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD="y"
2023-10-31 20:32:12 +00:00
fi
2023-10-18 17:15:48 +00:00
else
2023-11-06 21:05:08 +00:00
echo "GPG key material will be generated on USB Security Dongle's smartcard without backup"
2023-11-07 18:20:31 +00:00
GPG_GEN_KEY_IN_MEMORY="n"
GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD="n"
2023-10-18 17:15:48 +00:00
fi
2023-11-01 18:10:42 +00:00
# Dynamic messages to be given to user in terms of security components that will be applied
# based on previous answers
2023-10-30 17:57:02 +00:00
CUSTOM_PASS_AFFECTED_COMPONENTS="\n"
2023-10-18 17:15:48 +00:00
# Adapt message to be given to user in terms of security components that will be applied.
if [ -n "$luks_new_Disk_Recovery_Key_passphrase_desired" -o -n "$luks_new_Disk_Recovery_Key_passphrase" ]; then
2023-10-30 16:31:31 +00:00
CUSTOM_PASS_AFFECTED_COMPONENTS+="LUKS Disk Recovery Key passphrase\n"
2023-10-18 17:15:48 +00:00
fi
if [ "$CONFIG_TPM" = "y" ]; then
2023-10-30 16:31:31 +00:00
CUSTOM_PASS_AFFECTED_COMPONENTS+="TPM Owner Password\n"
2023-10-18 17:15:48 +00:00
fi
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "y" ]; then
2023-11-06 21:02:19 +00:00
CUSTOM_PASS_AFFECTED_COMPONENTS+="GPG Key material backup passphrase (Same as GPG Admin PIN)\n"
2023-10-30 16:31:31 +00:00
fi
CUSTOM_PASS_AFFECTED_COMPONENTS+="GPG Admin PIN\n"
2023-11-07 18:20:31 +00:00
# Only show GPG User PIN as affected component if GPG_GEN_KEY_IN_MEMORY not requested or GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD is
if [ "$GPG_GEN_KEY_IN_MEMORY" = "n" -o "$GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD" = "y" ]; then
2023-11-01 18:10:42 +00:00
CUSTOM_PASS_AFFECTED_COMPONENTS+="GPG User PIN\n"
fi
2023-10-18 17:15:48 +00:00
# Inform user of security components affected for the following prompts
2023-11-03 18:34:40 +00:00
echo
echo -e "The following Security Components will be configured with defaults or further chosen PINs/passwords:
2022-04-29 21:01:21 +00:00
$CUSTOM_PASS_AFFECTED_COMPONENTS\n"
2023-10-18 17:15:48 +00:00
# Prompt to change default passwords
2023-11-03 18:34:40 +00:00
echo -e -n "Would you like to set a single custom password to all previously stated security components? [y/N]: "
2023-10-18 17:15:48 +00:00
read -n 1 prompt_output
echo
if [ "$prompt_output" == "y" \
-o "$prompt_output" == "Y" ]; then
echo -e "\nThe chosen custom password must be between 8 and $MAX_HOTP_GPG_PIN_LENGTH characters in length.\n"
echo
while [[ ${#CUSTOM_SINGLE_PASS} -lt 8 ]] || [[ ${#CUSTOM_SINGLE_PASS} -gt $MAX_HOTP_GPG_PIN_LENGTH ]]; do
echo -e -n "Enter the custom password: "
read CUSTOM_SINGLE_PASS
done
echo
2023-10-26 20:50:10 +00:00
TPM_PASS=${CUSTOM_SINGLE_PASS}
USER_PIN=${CUSTOM_SINGLE_PASS}
ADMIN_PIN=${CUSTOM_SINGLE_PASS}
2023-10-18 17:15:48 +00:00
2023-11-01 18:10:42 +00:00
# Only set if user said desired
2023-10-18 17:15:48 +00:00
if [ -n "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then
2023-10-26 20:50:10 +00:00
luks_new_Disk_Recovery_Key_passphrase=${CUSTOM_SINGLE_PASS}
2023-10-18 17:15:48 +00:00
fi
else
2023-11-03 18:34:40 +00:00
echo -e -n "Would you like to set distinct PINs/passwords to configure previously stated security components? [y/N]: "
2023-10-18 17:15:48 +00:00
read -n 1 prompt_output
echo
if [ "$prompt_output" == "y" \
-o "$prompt_output" == "Y" ]; then
echo -e "\nThey must be each at least 8 characters in length.\n"
echo
if [ "$CONFIG_TPM" = "y" ]; then
while [[ ${#TPM_PASS} -lt 8 ]]; do
2023-10-23 17:13:39 +00:00
echo -e -n "Enter desired TPM Owner Password: "
2023-10-18 17:15:48 +00:00
read TPM_PASS
done
fi
while [[ ${#ADMIN_PIN} -lt 8 ]] || [[ ${#ADMIN_PIN} -gt $MAX_HOTP_GPG_PIN_LENGTH ]]; do
echo -e -n "\nThis PIN should be between 8 to $MAX_HOTP_GPG_PIN_LENGTH characters in length.\n"
echo -e -n "Enter desired GPG Admin PIN: "
read ADMIN_PIN
done
2023-11-07 18:20:31 +00:00
#USER PIN not required in case of GPG_GEN_KEY_IN_MEMORY not requested of if GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD is
2023-11-03 20:38:41 +00:00
# That is, if keys were NOT generated in memory (on smartcard only) or
2023-11-01 18:10:42 +00:00
# if keys were generated in memory but are to be moved from local keyring to smartcard
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "n" -o "$GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD" = "y" ]; then
2023-11-01 18:10:42 +00:00
while [[ ${#USER_PIN} -lt 8 ]] || [[ ${#USER_PIN} -gt $MAX_HOTP_GPG_PIN_LENGTH ]]; do
echo -e -n "\nThis PIN should be between 8 to $MAX_HOTP_GPG_PIN_LENGTH characters in length.\n"
echo -e -n "Enter desired GPG User PIN: "
read USER_PIN
done
fi
2023-10-18 17:15:48 +00:00
echo
fi
fi
if [ -n "$luks_new_Disk_Recovery_Key_passphrase_desired" -a -z "$luks_new_Disk_Recovery_Key_passphrase" ]; then
# We catch here if changing LUKS Disk Recovery Key passphrase was desired
# but yet undone. This is if not being covered by the single password
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following conditions:\n 1-Every boot if no Disk Unlock Key was added to the TPM\n 2-If the TPM fails (hardware failure)\n 3-If the firmware has been tampered with/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
echo -e "\nEnter desired replacement for current LUKS Disk Recovery Key passphrase (At least 8 characters long):"
2023-10-18 17:15:48 +00:00
while [[ ${#luks_new_Disk_Recovery_Key_passphrase} -lt 8 ]]; do
{
read -r luks_new_Disk_Recovery_Key_passphrase
}
done
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following conditions:\n 1-Every boot if no Disk Unlock Key was added to the TPM\n 2-If the TPM fails (hardware failure)\n 3-If the firmware has been tampered with/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
#We test that current LUKS Disk Recovery Key passphrase is known prior of going further
2023-10-18 17:15:48 +00:00
test_luks_current_disk_recovery_key_passphrase
echo -e "\n"
fi
# Prompt to change default GnuPG key information
echo -e -n "Would you like to set custom user information for the GnuPG key? [y/N]: "
read -n 1 prompt_output
echo
if [ "$prompt_output" == "y" \
-o "$prompt_output" == "Y" ]; then
echo -e "\n\n"
echo -e "We will generate a GnuPG (PGP) keypair identifiable with the following text form:"
echo -e "Real Name (Comment) email@address.org"
echo -e "\nEnter your Real Name (Optional):"
read -r GPG_USER_NAME
echo -e "\nEnter your email@adress.org:"
read -r GPG_USER_MAIL
while ! $(expr "$GPG_USER_MAIL" : '.*@' >/dev/null); do
{
echo -e "\nEnter your email@address.org:"
read -r GPG_USER_MAIL
}
done
echo -e "\nEnter Comment (Optional, to distinguish this key from others with same previous attributes. Must be smaller then 60 characters):"
read -r GPG_USER_COMMENT
while [[ ${#GPG_USER_COMMENT} -gt 60 ]]; do
{
echo -e "\nEnter Comment (Optional, to distinguish this key from others with same previous attributes. Must be smaller then 60 characters):"
read -r GPG_USER_COMMENT
}
done
fi
2023-11-13 18:54:37 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "y" ]; then
select_thumb_drive_for_key_material
fi
2023-10-18 17:15:48 +00:00
fi
2022-04-29 21:01:21 +00:00
# If nothing is stored in custom variables, we set them to their defaults
2023-10-26 20:50:10 +00:00
if [ "$TPM_PASS" == "" ]; then TPM_PASS=${TPM_PASS_DEF}; fi
if [ "$USER_PIN" == "" ]; then USER_PIN=${USER_PIN_DEF}; fi
if [ "$ADMIN_PIN" == "" ]; then ADMIN_PIN=${ADMIN_PIN_DEF}; fi
2020-01-02 16:29:11 +00:00
2020-07-07 08:32:22 +00:00
## sanity check the USB, GPG key, and boot device before proceeding further
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "n" ]; then
2023-10-18 17:15:48 +00:00
# Prompt to insert USB drive if desired
echo -e -n "\nWould you like to export your public key to an USB drive? [y/N]: "
read -n 1 prompt_output
echo
if [ "$prompt_output" == "y" \
-o "$prompt_output" == "Y" ] \
; then
GPG_EXPORT=1
# mount USB over /media only if not already mounted
if ! grep -q /media /proc/mounts; then
# mount USB in rw
if ! mount-usb --mode rw 2>/tmp/error; then
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Unable to mount USB on /media:\n\n${ERROR}"
fi
else
#/media already mounted, make sure it is in r+w mode
if ! mount -o remount,rw /media 2>/tmp/error; then
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Unable to remount in read+write USB on /media:\n\n${ERROR}"
fi
fi
2022-03-10 14:55:08 +00:00
else
2023-10-18 17:15:48 +00:00
GPG_EXPORT=0
2023-10-30 15:37:31 +00:00
# needed for USB Security Dongle below and is ensured via mount-usb in case of GPG_EXPORT=1
2023-10-18 17:15:48 +00:00
enable_usb
2020-07-07 08:32:22 +00:00
fi
fi
2019-08-15 18:36:05 +00:00
2023-11-07 18:20:31 +00:00
# ensure USB Security Dongle connected if GPG_GEN_KEY_IN_MEMORY=n or if GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD=y
if [ "$GPG_GEN_KEY_IN_MEMORY" = "n" -o "$GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD" = "y" ]; then
2023-10-18 17:15:48 +00:00
echo -e "\nChecking for USB Security Dongle...\n"
enable_usb
if ! gpg --card-status >/dev/null 2>&1; then
whiptail_error "Can't access USB Security Dongle; \nPlease remove and reinsert, then press Enter."
if ! gpg --card-status >/dev/null 2>/tmp/error; then
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Unable to detect USB Security Dongle:\n\n${ERROR}"
fi
2019-08-15 18:36:05 +00:00
fi
2023-11-07 18:20:31 +00:00
#Now that USB Security Dongle is detected, we can check its capabilities and limitations
usb_security_token_capabilities_check
2019-08-15 18:36:05 +00:00
fi
2023-01-12 16:31:31 +00:00
assert_signable
2022-03-23 19:55:42 +00:00
# Action time...
2023-10-26 20:50:10 +00:00
# clear gpg-agent cache so that next gpg calls doesn't have past keyring in memory
killall gpg-agent >/dev/null 2>&1 || true
2023-10-30 15:37:31 +00:00
# clear local keyring
rm -rf /.gnupg/* >/dev/null 2>&1 || true
2023-10-19 19:42:27 +00:00
2019-08-15 18:36:05 +00:00
# detect and set /boot device
echo -e "\nDetecting and setting boot device...\n"
2023-10-18 17:15:48 +00:00
if ! detect_boot_device; then
SKIP_BOOT="y"
2019-08-15 18:36:05 +00:00
else
2023-10-18 17:15:48 +00:00
echo -e "Boot device set to $CONFIG_BOOT_DEV\n"
2019-08-15 18:36:05 +00:00
fi
# update configs
2020-10-23 23:38:30 +00:00
if [[ "$SKIP_BOOT" == "n" ]]; then
2023-10-18 17:15:48 +00:00
replace_config /etc/config.user "CONFIG_BOOT_DEV" "$CONFIG_BOOT_DEV"
combine_configs
2020-10-23 23:38:30 +00:00
fi
2019-08-15 18:36:05 +00:00
2022-05-03 20:14:51 +00:00
if [ -n "$luks_new_Disk_Recovery_Key_desired" -a -n "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then
Uniformize vocabulary: LUKS TPM Disk Unlock Key & LUKS Disk Recovery Key
When playing with long fbwhiptail/whiptail messages, this commit played around the long string using fold.
'''
echo -e "This will replace the encrypted container content and its LUKS Disk Recovery Key.\n\nThe passphrase associated with this key will be asked from the user under the following conditions:\n 1-Every boot if no Disk Unlock Key was added to the TPM\n 2-If the TPM fails (hardware failure)\n 3-If the firmware has been tampered with/modified by the user\n\nThis process requires you to type the current LUKS Disk Recovery Key passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set up, by setting a default boot LUKS key slot (1) if present.\n\nAt the next prompt, you may be asked to select which file corresponds to the LUKS device container.\n\nHit Enter to continue." | fold -w 70 -s
'''
Which gave the exact output of what will be inside of the fbwhiptail prompt, fixed to 70 chars width:
'''
This will replace the encrypted container content and its LUKS Disk
Recovery Key.
The passphrase associated with this key will be asked from the user
under the following conditions:
1-Every boot if no Disk Unlock Key was added to the TPM
2-If the TPM fails (hardware failure)
3-If the firmware has been tampered with/modified by the user
This process requires you to type the current LUKS Disk Recovery Key
passphrase and will delete the LUKS TPM Disk Unlock Key slot, if set
up, by setting a default boot LUKS key slot (1) if present.
At the next prompt, you may be asked to select which file corresponds
to the LUKS device container.
Hit Enter to continue.
'''
Therefore, for long prompts in the future, one can just deal with "\n 1-" alignments to be respected in prompts and have fold deal with cutting the length of strings properly.
Signed-off-by: Thierry Laurion <insurgo@riseup.net>
2024-01-19 17:32:04 +00:00
#Reencryption of disk, LUKS Disk Recovery Key and LUKS Disk Recovery Key passphrase change is requested
2023-10-18 17:15:48 +00:00
luks_change_passphrase
2023-12-01 22:04:34 +00:00
luks_reencrypt
2022-05-03 20:14:51 +00:00
elif [ -n "$luks_new_Disk_Recovery_Key_desired" -a -z "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then
2023-10-18 17:15:48 +00:00
#Reencryption of disk was requested but not passphrase change
luks_reencrypt
2022-05-03 20:14:51 +00:00
elif [ -z "$luks_new_Disk_Recovery_Key_desired" -a -n "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then
2023-10-18 17:15:48 +00:00
#Passphrase change is requested without disk reencryption
luks_change_passphrase
2022-03-23 19:55:42 +00:00
fi
2022-03-10 14:55:08 +00:00
## reset TPM and set password
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM" = "y" ]; then
2023-10-18 17:15:48 +00:00
echo -e "\nResetting TPM...\n"
tpmr reset "$TPM_PASS" >/dev/null 2>/tmp/error
2022-08-25 18:43:31 +00:00
fi
if [ $? -ne 0 ]; then
2023-10-18 17:15:48 +00:00
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Error resetting TPM:\n\n${ERROR}"
2019-08-15 18:36:05 +00:00
fi
# clear local keyring
rm /.gnupg/*.gpg 2>/dev/null
rm /.gnupg/*.kbx 2>/dev/null
2023-10-30 15:37:31 +00:00
# initialize gpg wth empty keyring
2019-08-15 18:36:05 +00:00
gpg --list-keys >/dev/null 2>&1
2023-10-26 20:50:10 +00:00
#Generate keys in memory and copy to smartcard
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "y" ]; then
2023-10-25 21:01:01 +00:00
if [ "$GPG_ALGO" == "RSA" ]; then
# Generate GPG master key
generate_inmemory_RSA_master_and_subkeys
elif [ "$GPG_ALGO" == "p256" ]; then
generate_inmemory_p256_master_and_subkeys
else
die "Unsupported GPG_ALGO: $GPG_ALGO"
fi
2023-11-13 18:54:37 +00:00
wipe_thumb_drive_and_copy_gpg_key_material "$thumb_drive" "$thumb_drive_luks_percent"
2023-10-31 20:32:12 +00:00
set_user_config "CONFIG_HAVE_GPG_KEY_BACKUP" "y"
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD" = "y" ]; then
2023-10-31 20:32:12 +00:00
keytocard_subkeys_to_smartcard
fi
2023-10-18 17:15:48 +00:00
else
2023-10-26 20:50:10 +00:00
#Generate GPG key and subkeys on smartcard only
2023-10-30 17:19:27 +00:00
echo -e "\nResetting USB Security Dongle's GPG smartcard...\n(this will take around 3 minutes...)\n"
2023-10-18 17:15:48 +00:00
gpg_key_factory_reset
generate_OEM_gpg_keys
fi
2019-08-15 18:36:05 +00:00
2023-10-19 19:42:27 +00:00
# Obtain GPG key ID
GPG_GEN_KEY=$(gpg --list-keys --with-colons | grep "^fpr" | cut -d: -f10 | head -n1)
#Where to export the public key
2020-02-19 20:15:27 +00:00
PUBKEY="/tmp/${GPG_GEN_KEY}.asc"
2023-10-19 19:42:27 +00:00
# export pubkey to file
if ! gpg --export --armor "$GPG_GEN_KEY" >"${PUBKEY}" 2>/tmp/error; then
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "GPG Key gpg export to file failed!\n\n$ERROR"
fi
2023-10-26 20:50:10 +00:00
#Applying custom GPG PINs to the smartcard if they were provided
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "n" -o "$GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD" = "y" ]; then
2023-11-01 18:10:42 +00:00
#Only apply smartcard PIN change if smartcard only or if keytocard op is expected next
2023-10-31 20:32:12 +00:00
if [ "${USER_PIN}" != "" -o "${ADMIN_PIN}" != "" ]; then
echo -e "\nChanging default GPG Admin PIN\n"
gpg_key_change_pin "3" "${ADMIN_PIN_DEF}" "${ADMIN_PIN}"
echo -e "\nChanging default GPG User PIN\n"
gpg_key_change_pin "1" "${USER_PIN_DEF}" "${USER_PIN}"
fi
2023-10-26 20:50:10 +00:00
fi
2020-07-07 09:16:18 +00:00
2023-10-26 20:50:10 +00:00
## export pubkey to USB
2023-10-27 15:18:20 +00:00
if [ "$GPG_EXPORT" != "0" ]; then
2023-10-26 20:50:10 +00:00
echo -e "\nExporting generated key to USB...\n"
# copy to USB
if ! cp "${PUBKEY}" "/media/${GPG_GEN_KEY}.asc" 2>/tmp/error; then
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Key export error: unable to copy ${GPG_GEN_KEY}.asc to /media:\n\n$ERROR"
2020-07-07 08:32:22 +00:00
fi
2023-10-26 20:50:10 +00:00
mount -o remount,ro /media 2>/dev/null
fi
2019-08-15 18:36:05 +00:00
# ensure key imported locally
2023-10-18 17:15:48 +00:00
if ! cat "$PUBKEY" | gpg --import >/dev/null 2>/tmp/error; then
2020-07-10 22:29:43 +00:00
ERROR=$(tail -n 1 /tmp/error | fold -s)
2019-08-15 18:36:05 +00:00
whiptail_error_die "Error importing GPG key:\n\n$ERROR"
fi
# update /.gnupg/trustdb.gpg to ultimately trust all user provided public keys
2023-10-18 17:15:48 +00:00
if ! gpg --list-keys --fingerprint --with-colons 2>/dev/null |
sed -E -n -e 's/^fpr:::::::::([0-9A-F]+):$/\1:6:/p' |
gpg --import-ownertrust >/dev/null 2>/tmp/error; then
2020-07-10 22:29:43 +00:00
ERROR=$(tail -n 1 /tmp/error | fold -s)
2019-08-15 18:36:05 +00:00
whiptail_error_die "Error importing GPG ownertrust:\n\n$ERROR"
fi
2023-10-18 17:15:48 +00:00
if ! gpg --update-trust >/dev/null 2>/tmp/error; then
2020-07-10 22:29:43 +00:00
ERROR=$(tail -n 1 /tmp/error | fold -s)
2019-08-15 18:36:05 +00:00
whiptail_error_die "Error updating GPG ownertrust:\n\n$ERROR"
fi
2023-10-19 19:42:27 +00:00
2023-10-27 15:18:20 +00:00
# Do not attempt to flash the key to ROM if we are running in QEMU based on CONFIG_BOARD_NAME matching glob pattern containing qemu-*
# We check for qemu-* instead of ^qemu- because CONFIG_BOARD_NAME could be renamed to UNTESTED-qemu-* in a probable future
if [[ "$CONFIG_BOARD_NAME" == qemu-* ]]; then
2023-10-30 15:43:44 +00:00
warn "Skipping flash of GPG key to ROM because we are running in QEMU without internal flashing support."
2023-11-01 18:10:42 +00:00
warn "Please review boards/qemu*/qemu*.md documentation to extract public key from raw disk and inject at build time"
2023-11-03 18:34:40 +00:00
warn "Also review boards/qemu*/qemu*.config to tweak CONFIG_* options you might need to turn on/off manually at build time"
2023-10-27 15:18:20 +00:00
else
#We are not running in QEMU, so flash the key to ROM
## flash generated key to ROM
echo -e "\nReading current firmware...\n(this will take a minute or two)\n"
/bin/flash.sh -r /tmp/oem-setup.rom >/dev/null 2>/tmp/error
if [ ! -s /tmp/oem-setup.rom ]; then
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Error reading current firmware:\n\n$ERROR"
fi
# clear any existing heads/gpg files from current firmware
for i in $(cbfs.sh -o /tmp/oem-setup.rom -l | grep -e "heads/"); do
cbfs.sh -o /tmp/oem-setup.rom -d "$i"
done
# add heads/gpg files to current firmware
if [ -e /.gnupg/pubring.kbx ]; then
cbfs.sh -o /tmp/oem-setup.rom -a "heads/initrd/.gnupg/pubring.kbx" -f /.gnupg/pubring.kbx
if [ -e /.gnupg/pubring.gpg ]; then
rm /.gnupg/pubring.gpg
fi
elif [ -e /.gnupg/pubring.gpg ]; then
cbfs.sh -o /tmp/oem-setup.rom -a "heads/initrd/.gnupg/pubring.gpg" -f /.gnupg/pubring.gpg
fi
if [ -e /.gnupg/trustdb.gpg ]; then
cbfs.sh -o /tmp/oem-setup.rom -a "heads/initrd/.gnupg/trustdb.gpg" -f /.gnupg/trustdb.gpg
fi
# persist user config changes (boot device)
if [ -e /etc/config.user ]; then
cbfs.sh -o /tmp/oem-setup.rom -a "heads/initrd/etc/config.user" -f /etc/config.user
fi
# flash updated firmware image
echo -e "\nAdding generated key to current firmware and re-flashing...\n"
if ! /bin/flash.sh /tmp/oem-setup.rom 2>/tmp/error; then
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Error flashing updated firmware image:\n\n$ERROR"
fi
2019-08-15 18:36:05 +00:00
fi
## sign files in /boot and generate checksums
2020-10-23 23:38:30 +00:00
if [[ "$SKIP_BOOT" == "n" ]]; then
2023-10-18 17:15:48 +00:00
echo -e "\nSigning boot files and generating checksums...\n"
generate_checksums
2020-10-23 23:38:30 +00:00
fi
2019-08-15 18:36:05 +00:00
2023-10-30 16:31:31 +00:00
# passphrases set to be empty first
passphrases="\n"
2023-11-03 18:34:40 +00:00
# Prepare whiptail output of configured secrets
2023-10-30 16:31:31 +00:00
if [ -n "$luks_new_Disk_Recovery_Key_passphrase" -o -n "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then
passphrases+="LUKS Disk Recovery Key passphrase: ${luks_new_Disk_Recovery_Key_passphrase}\n"
2022-03-23 19:55:42 +00:00
fi
tpm2-tools: Change sense of CONFIG_TPM to mean any TPM, not just TPM1.
Most logic throughout Heads doesn't need to know TPM1 versus TPM2 (and
shouldn't, the differences should be localized). Some checks were
incorrect and are fixed by this change. Most checks are now unchanged
relative to master.
There are not that many places outside of tpmr that need to
differentiate TPM1 and TPM2. Some of those are duplicate code that
should be consolidated (seal-hotpkey, unseal-totp, unseal-hotp), and
some more are probably good candidates for abstracting in tpmr so the
business logic doesn't have to know TPM1 vs. TPM2.
Previously, CONFIG_TPM could be variously 'y', 'n', or empty. Now it
is always 'y' or 'n', and 'y' means "any TPM". Board configs are
unchanged, setting CONFIG_TPM2_TOOLS=y implies CONFIG_TPM=y so this
doesn't have to be duplicated and can't be mistakenly mismatched.
There were a few checks for CONFIG_TPM = n that only coincidentally
worked for TPM2 because CONFIG_TPM was empty (not 'n'). This test is
now OK, but the checks were also cleaned up to '!= "y"' for robustness.
Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
2023-02-22 21:30:07 +00:00
if [ "$CONFIG_TPM" = "y" ]; then
2023-10-30 16:31:31 +00:00
passphrases+="TPM Owner Password: ${TPM_PASS}\n"
fi
2023-11-01 18:10:42 +00:00
#GPG PINs output
2023-10-30 16:31:31 +00:00
passphrases+="GPG Admin PIN: ${ADMIN_PIN}\n"
2023-11-07 18:20:31 +00:00
#USER PIN was configured if GPG_GEN_KEY_IN_MEMORY is not active or if GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD is active
if [ "$GPG_GEN_KEY_IN_MEMORY" = "n" -o "$GPG_GEN_KEY_IN_MEMORY_COPY_TO_SMARTCARD" = "y" ]; then
2023-11-01 18:10:42 +00:00
passphrases+="GPG User PIN: ${USER_PIN}\n"
fi
2023-10-30 16:31:31 +00:00
#If user decided to generate keys in memory, we add the thumb drive passphrase
2023-11-07 18:20:31 +00:00
if [ "$GPG_GEN_KEY_IN_MEMORY" = "y" ]; then
2023-10-30 16:31:31 +00:00
passphrases+="GPG key material backup passphrase: ${ADMIN_PIN}\n"
2022-03-23 19:55:42 +00:00
fi
2023-11-03 18:34:40 +00:00
## Show to user current configured secrets prior of rebooting
2022-03-10 14:55:08 +00:00
whiptail --msgbox "
2023-12-06 13:53:15 +00:00
$(echo -e "$passphrases" | fold -w $((WIDTH-5)))" \
2023-12-03 17:43:49 +00:00
$HEIGHT $WIDTH --title "Configured secrets"
2022-03-10 14:55:08 +00:00
2019-08-15 18:36:05 +00:00
## all done -- reboot
whiptail --msgbox "
2022-03-10 14:55:08 +00:00
OEM Factory Reset / Re-Ownership has completed successfully\n\n
2019-08-15 18:36:05 +00:00
After rebooting, you will need to generate new TOTP/HOTP secrets\n
when prompted in order to complete the setup process.\n\n
2019-11-26 17:10:39 +00:00
Press Enter to reboot.\n" \
2022-03-10 14:55:08 +00:00
$HEIGHT $WIDTH --title "OEM Factory Reset / Re-Ownership Complete"
2019-08-15 18:36:05 +00:00
2022-03-23 19:55:42 +00:00
# Clean LUKS secrets
luks_secrets_cleanup
unset luks_passphrase_changed
2023-10-24 15:19:49 +00:00
unset tpm_owner_password_changed
2022-03-23 19:55:42 +00:00
2019-08-15 18:36:05 +00:00
reboot