Signed-off-by: Thierry Laurion <insurgo@riseup.net>
This commit is contained in:
Thierry Laurion 2023-10-18 13:15:48 -04:00
parent e1d972be37
commit b1e5c638cd
No known key found for this signature in database
GPG Key ID: E7B4A71658E36A93
6 changed files with 917 additions and 480 deletions

View File

@ -6,10 +6,13 @@ export CONFIG_COREBOOT=y
export CONFIG_COREBOOT_VERSION=4.19
export CONFIG_LINUX_VERSION=5.10.5
#Enable only one RESTRICTED/BASIC boot modes below to test them manually (we cannot inject config under QEMU (no internal flashing)
#Enable only one RESTRICTED/BASIC boot modes below to test them manually (we cannot inject config under QEMU (no internal flashing))
#export CONFIG_RESTRICTED_BOOT=y
#export CONFIG_BASIC=y
#Enable HAVE_GPG_KEY_BACKUP to test GPG key backup drive (we cannot inject config under QEMU (no internal flashing))
export CONFIG_HAVE_GPG_KEY_BACKUP=y
#Enable DEBUG output
export CONFIG_DEBUG_OUTPUT=y
export CONFIG_ENABLE_FUNCTION_TRACING_OUTPUT=y

View File

@ -7,6 +7,9 @@ set -e -o pipefail
TRACE "Under /bin/media-scan"
#Booting from external media should be authenticated if supported
gpg_auth
# Unmount any previous boot device
if grep -q /boot /proc/mounts ; then
umount /boot \

View File

@ -35,11 +35,12 @@ MAX_HOTP_GPG_PIN_LENGTH=25
# What are the Security components affected by custom passwords
CUSTOM_PASS_AFFECTED_COMPONENTS=""
RSA_KEY_LENGTH=3072
# Default RSA key length
#TODO change it back to 3076. Canokey cannot be tested easily and Nitrokey prov1 I have doesn't key-attr to 3076
RSA_KEY_LENGTH=2048
GPG_ALGO="rsa"
GPG_USER_NAME="OEM Key"
GPG_KEY_NAME=`date +%Y%m%d%H%M%S`
GPG_KEY_NAME=$(date +%Y%m%d%H%M%S)
GPG_USER_MAIL="oem-${GPG_KEY_NAME}@example.com"
GPG_USER_COMMENT="OEM-generated key"
SKIP_BOOT="n"
@ -56,8 +57,7 @@ die() {
exit 1
}
whiptail_error()
{
whiptail_error() {
local msg=$1
if [ "$msg" = "" ]; then
die "whiptail error: An error msg is required"
@ -65,15 +65,299 @@ whiptail_error()
whiptail $BG_COLOR_ERROR --msgbox "${msg}\n\n" $HEIGHT $WIDTH $BG_COLOR_ERROR --title "Error"
}
whiptail_error_die()
{
whiptail_error_die() {
whiptail_error "$@"
die
}
gpg_key_reset()
#Generate a gpg master key: passwordless, no expiration date, RSA 4096 bits
#This key will be used to sign 3 subkeys: encryption, authentication and signing
#The master key will be stored on the disk, and the subkeys on the smartcard
generate_inmemory_RSA_master_and_subkeys() {
TRACE "Under oem-factory-reset:generate_inmemory_RSA_master_and_subkeys"
echo "Generating GPG key material in memory:"
echo "Generating GPG RSA ${RSA_KEY_LENGTH} bits master key..."
# Generate GPG master key
{
echo "Key-Type: RSA"
echo "Key-Length: ${RSA_KEY_LENGTH}"
echo "Key-Usage: sign"
echo "Name-Real: ${GPG_USER_NAME}"
echo "Name-Comment: ${GPG_USER_COMMENT}"
echo "Name-Email: ${GPG_USER_MAIL}"
echo "Expire-Date: 0"
echo "Passphrase: ${ADMIN_PIN}"
echo "%commit"
} | gpg --batch --gen-key \
>/tmp/gpg_card_edit_output 2>&1
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
{
echo addkey
echo 4 # RSA (sign only)
echo ${RSA_KEY_LENGTH}
echo 0 # no expiration
echo ${ADMIN_PIN}
echo y # confirm
echo save
} | 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
{
echo addkey
echo 6 # RSA (encrypt only)
echo ${RSA_KEY_LENGTH}
echo 0 # no expiration
echo ${ADMIN_PIN}
echo y # confirm
echo save
} | 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
echo addkey
echo 8 # RSA (own capabilite)
echo S # disable signing capability
echo E # disable encryption capability
echo A # enable authentication capability
echo Q # quit
echo ${RSA_KEY_LENGTH}
echo 0 # no expiration
echo ${ADMIN_PIN}
echo y # confirm
echo save
} | 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
{
echo trust
echo 5 # ultimate
echo y # confirm
echo save
} | 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
}
#Function to move current gpg keyring subkeys to card (keytocard)
# This is aimed to be used after having generated master key and subkeys in memory and having backuped them to a LUKS container
# 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
# Delete the master key from the keyring once key to card is done (already backuped on LUKS private partition)
keytocard_subkeys_to_smartcard() {
TRACE "Under oem-factory-reset:keytocard_subkeys_to_smartcard"
#make sure usb ready and usb dongle ready to communicate with
enable_usb
enable_usb_storage
gpg --card-status >/dev/null 2>&1 || die "Error getting GPG card status"
DEBUG "Factory resetting the smartcard..."
gpg_key_factory_reset
DEBUG "Moving subkeys to smartcard..."
#keytocard all subkeys
{
echo "key 1" #Select Signature key
echo "keytocard"
echo "1" # Signature key
echo "$ADMIN_PIN" #Smartcard admin pin
echo "$ADMIN_PIN" #Subkey PIN
echo "0" #No expiration date
echo "key 1"
echo "key 2"
echo "keytocard"
echo "2" # Encryption key
echo "$ADMIN_PIN"
echo "$ADMIN_PIN"
echo "key 2"
echo "key 3"
echo "keytocard"
echo "3" # Authentication key
echo "$ADMIN_PIN"
echo "$ADMIN_PIN"
echo "key 3"
echo "save"
} | 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 moving subkeys to smartcard failed!\n\n$ERROR"
fi
DEBUG "Moving subkeys to smartcard done."
}
#Whiptail prompt to disconnect any external USB storage device
prompt_disconnect_external_USB_storage_device() {
TRACE "Under oem-factory-reset:disconnect_external_USB_storage_device"
#Whiptail $BG_COLOR_WARNING warning about removing any external USB storage device currently connected
whiptail $BG_COLOR_WARNING --title 'WARNING: Please disconnect any external USB storage device' \
--msgbox "An external USB storage device will be WIPED next.\n\nPlease disconnect all external USB storage devices." 0 80 ||
die "Error displaying warning about removing any external USB storage device currently connected"
}
#Whiptail prompt to insert to be wiped thumb drive
prompt_insert_to_be_wiped_thumb_drive() {
TRACE "Under oem-factory-reset:prompt_insert_to_be_wiped_thumb_drive"
#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' \
--msgbox "The thumb drive will be WIPED next.\n\nPlease have connected only the thumb drive to be wiped." 0 80 ||
die "Error displaying warning about having only desired to be wiped thumb drive inserted"
}
#list blkid devices (removing partition numbers)
list_blkid_devices() {
TRACE "Under oem-factory-reset:list_blkid_devices"
blkid | cut -d: -f1 | sed 's/[0-9]$//'
}
#export master key and subkeys to thumbdrive's private LUKS contained partition
export_master_key_subkeys_and_revocation_key_to_private_LUKS_container() {
TRACE "Under oem-factory-reset:export_master_key_subkeys_and_revocation_key_to_private_LUKS_container"
#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)
pass="$2"
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..."
gpg --export-secret-key --armor --pinentry-mode loopback --passphrase-file <(echo -n "${pass}") "${GPG_USER_MAIL}" >"$mountpoint"/privkey.sec ||
die "Error exporting master key to private LUKS container's partition"
gpg --export-secret-subkeys --armor --pinentry-mode loopback --passphrase-file <(echo -n "${pass}") "${GPG_USER_MAIL}" >"$mountpoint"/subkeys.sec ||
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"
}
#Export public key to thumb drive's public partition
export_public_key_to_thumbdrive_public_partition() {
TRACE "Under oem-factory-reset:export_public_key_to_thumbdrive_public_partition"
#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"
}
#Wipe a thumb drive and export master key and subkeys to it
wipe_thumb_drive_and_copy_gpg_key_material() {
TRACE "Under oem-factory-reset:wipe_thumb_drive_and_copy_gpg_key_material"
prompt_disconnect_external_USB_storage_device
actual_devices=$(list_blkid_devices)
#enable usb storage
enable_usb
enable_usb_storage
prompt_insert_to_be_wiped_thumb_drive
new_devices=$(list_blkid_devices)
thumb_drive=$(echo "$new_devices" | grep -v "$actual_devices" | uniq)
if [ -z "$thumb_drive" ]; then
whiptail_error_die "No new thumb drive detected! Aborting."
fi
select_luks_container_size_percent
#Wipe thumb drive with a LUKS container of size $(cat /tmp/luks_container_size_percent)
prepare_thumb_drive --device "$thumb_drive" --percentage "$(cat /tmp/luks_container_size_percent)" --pass "$ADMIN_PIN"
#Export master key and subkeys to thumb drive first partition
export_master_key_subkeys_and_revocation_key_to_private_LUKS_container --mode rw --device "$thumb_drive"1 --mountpoint /media --pass "$ADMIN_PIN"
#Export public key to thumb drive's public partition
export_public_key_to_thumbdrive_public_partition --mode rw --device "$thumb_drive"2 --mountpoint /media
}
gpg_key_factory_reset() {
TRACE "Under oem-factory-reset:gpg_key_factory_reset"
#enable usb storage
enable_usb
# Factory reset GPG card
DEBUG "GPG factory reset..."
{
echo admin
echo factory-reset
@ -82,7 +366,7 @@ gpg_key_reset()
} | 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`
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key factory reset failed!\n\n$ERROR"
fi
# If Nitrokey Storage is inserted, reset AES keys as well
@ -91,6 +375,7 @@ gpg_key_reset()
fi
# 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
DEBUG "GPG toggling forcesig on since off..."
{
echo admin
echo forcesig
@ -98,7 +383,7 @@ gpg_key_reset()
} | 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`
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key forcesig toggle on failed!\n\n$ERROR"
fi
fi
@ -119,11 +404,12 @@ gpg_key_reset()
} | gpg --command-fd=0 --status-fd=1 --pinentry-mode=loopback --card-edit --expert \
>/tmp/gpg_card_edit_output 2>&1
if [ $? -ne 0 ]; then
ERROR=`cat /tmp/gpg_card_edit_output`
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "Setting key to NIST-P256 in USB security dongle failed."
fi
# fallback to RSA key generation by default
else
DEBUG "GPG setting RSA key length to ${RSA_KEY_LENGTH} bits..."
# Set RSA key length
{
echo admin
@ -140,11 +426,16 @@ gpg_key_reset()
} | 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`
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "Setting key attributed to RSA ${RSA_KEY_LENGTH} bits in USB security dongle failed."
fi
fi
}
generate_OEM_gpg_keys() {
# Generate OEM GPG keys
TRACE "Under oem-factory-reset:generate_OEM_gpg_keys"
DEBUG "Generating GPG keys to RSA ${RSA_KEY_LENGTH} bits in smartcard..."
{
echo admin
echo generate
@ -159,13 +450,14 @@ gpg_key_reset()
} | 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`
ERROR=$(cat /tmp/gpg_card_edit_output)
whiptail_error_die "GPG Key automatic keygen failed!\n\n$ERROR"
fi
}
gpg_key_change_pin()
{
gpg_key_change_pin() {
TRACE "Under oem-factory-reset:gpg_key_change_pin"
DEBUG "Changing GPG key PINs..."
# 1 = user PIN, 3 = admin PIN
PIN_TYPE=$1
PIN_ORIG=$2
@ -183,13 +475,13 @@ gpg_key_change_pin()
} | 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 | fold -s`
ERROR=$(cat /tmp/gpg_card_edit_output | fold -s)
whiptail_error_die "GPG Key PIN change failed!\n\n$ERROR"
fi
}
generate_checksums()
{
generate_checksums() {
TRACE "Under oem-factory-reset:generate_checksums"
# ensure /boot mounted
if ! grep -q /boot /proc/mounts; then
mount -o rw /boot || whiptail_error_die "Unable to mount /boot"
@ -211,18 +503,18 @@ generate_checksums()
tpmr counter_create \
-pwdo "$TPM_PASS" \
-pwdc '' \
-la -3135106223 \
| tee /tmp/counter \
|| whiptail_error_die "Unable to create TPM counter"
TPM_COUNTER=`cut -d: -f1 < /tmp/counter`
-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"
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"
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
@ -238,15 +530,15 @@ generate_checksums()
(
set -e -o pipefail
cd /boot
find ./ -type f ! -path './kexec*' -print0 \
| xargs -0 sha256sum > /boot/kexec_hashes.txt 2>/dev/null
find ./ -type f ! -path './kexec*' -print0 |
xargs -0 sha256sum >/boot/kexec_hashes.txt 2>/dev/null
print_tree >/boot/kexec_tree.txt
)
[ $? -eq 0 ] || whiptail_error_die "Error generating kexec hashes"
param_files=`find /boot/kexec*.txt`
[ -z "$param_files" ] \
&& whiptail_error_die "No kexec parameter files to sign"
param_files=$(find /boot/kexec*.txt)
[ -z "$param_files" ] &&
whiptail_error_die "No kexec parameter files to sign"
# sign kexec boot files
if sha256sum $param_files 2>/dev/null | gpg \
@ -277,8 +569,8 @@ generate_checksums()
fi
}
set_default_boot_option()
{
set_default_boot_option() {
TRACE "Under oem-factory-reset:set_default_boot_option"
option_file="/tmp/kexec_options.txt"
tmp_menu_file="/tmp/kexec/kexec_menu.txt"
hash_file="/boot/kexec_default_hashes.txt"
@ -286,25 +578,25 @@ set_default_boot_option()
mkdir -p /tmp/kexec/
rm $option_file 2>/dev/null
# parse boot options from grub.cfg
for i in `find /boot -name "grub.cfg"`; do
for i in $(find /boot -name "grub.cfg"); do
kexec-parse-boot "/boot" "$i" >>$option_file
done
# 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
for i in `find /boot -name "grub.cfg"`; do
for i in $(find /boot -name "grub.cfg"); do
kexec-parse-bls "/boot" "$i" "/boot/loader/entries" >>$option_file
done
fi
[ ! -s $option_file ] \
&& whiptail_error_die "Failed to parse any boot options"
[ ! -s $option_file ] &&
whiptail_error_die "Failed to parse any boot options"
# sort boot options
sort -r $option_file | uniq >$tmp_menu_file
## save first option as default
entry=`head -n 1 $tmp_menu_file | tail -1`
entry=$(head -n 1 $tmp_menu_file | tail -1)
# clear existing default configs
rm "/boot/kexec_default.*.txt" 2>/dev/null
@ -316,31 +608,31 @@ set_default_boot_option()
echo "$entry" >/boot/kexec_default.$index.txt
# validate boot option
( 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"
(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"
}
report_integrity_measurements()
{
report_integrity_measurements() {
TRACE "Under oem-factory-reset:report_integrity_measurements"
#check for GPG key in keyring
GPG_KEY_COUNT=`gpg -k 2>/dev/null | wc -l`
if [ $GPG_KEY_COUNT -ne 0 ]; then
GPG_KEY_COUNT=$(gpg -k 2>/dev/null | wc -l)
if [ "$GPG_KEY_COUNT" -ne 0 ]; then
# Check and report TOTP
# update the TOTP code every thirty seconds
date=`date "+%Y-%m-%d %H:%M:%S %Z"`
seconds=`date "+%s"`
half=`expr \( $seconds % 60 \) / 30`
date=$(date "+%Y-%m-%d %H:%M:%S %Z")
seconds=$(date "+%s")
half=$(expr \( "$seconds" % 60 \) / 30)
if [ "$CONFIG_TPM" != "y" ]; then
TOTP="NO TPM"
elif [ "$half" != "$last_half" ]; then
last_half=$half;
TOTP=`unseal-totp` > /dev/null 2>&1
last_half=$half
TOTP=$(unseal-totp) >/dev/null 2>&1
fi
# Check and report on HOTP status
if [ -x /bin/hotp_verification ]; then
HOTP=`unseal-hotp` > /dev/null 2>&1
HOTP=$(unseal-hotp) >/dev/null 2>&1
enable_usb
if ! hotp_verification info >/dev/null 2>&1; then
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
@ -378,8 +670,7 @@ report_integrity_measurements()
fi
}
usb_security_token_capabilities_check()
{
usb_security_token_capabilities_check() {
TRACE "Under /bin/oem-factory-reset:usb_security_token_capabilities_check"
enable_usb
@ -389,10 +680,11 @@ usb_security_token_capabilities_check()
DEBUG "Setting GPG_ALGO to (board-)configured: $CONFIG_GPG_ALGO"
fi
# ... overwrite with usb-token capability
if lsusb | grep -q "20a0:42b2"; then
GPG_ALGO="p256"
DEBUG "Nitrokey 3 detected: Setting GPG_ALGO to: $GPG_ALGO"
fi
#TODO: revert. Testing test firmware for Nitrokey 3 which is supposed to support RSA 3076 now
#if lsusb | grep -q "20a0:42b2"; then
# GPG_ALGO="p256"
# DEBUG "Nitrokey 3 detected: Setting GPG_ALGO to: $GPG_ALGO"
#fi
}
## main script start
@ -442,6 +734,11 @@ if [ "$CONFIG_OEMRESET_OFFER_DEFAULTS" = y ]; then
fi
if [ "$use_defaults" == "n" -o "$use_defaults" == "N" ]; then
#Give general guidance to user on how to answer prompts
echo "The following questionnaire will help you to configure the security components of your system."
echo "You will be prompted for each option to answer a single letter at prompts (Y/n/m)."
echo "If you don't know what to answer, just press Enter to use default value which is shown between [] brackets as the uppercase letter."
# Re-ownership of encrypted disk key, content and passphrase
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 provisioned passphrase would not permit to access content.\n Note that without re-encrypting disk, a backuped header could be restored to access encrypted content with old passphrase) [y/N]: "
read -n 1 prompt_output
@ -462,6 +759,21 @@ if [ "$use_defaults" == "n" -o "$use_defaults" == "N" ]; then
echo -e "\n"
fi
#Prompt to ask if user wants to generate GPG key material in memory or on smartcard
echo -e -n "Would you like to generate GPG key material in (m)emory or (S)olely on the security element of the USB security dongle? [m/S]: "
read -n 1 prompt_output
echo
if [ "$prompt_output" == "m" \
-o "$prompt_output" == "M" ] \
; then
GPG_GEN_KEY_IN_MEMORY=1
#TODO: present steps clearer for user
echo "Master key and subkeys will be generated in memory, backuped to dedicated LUKS container and then subkeys imported to factory resetted smartcard."
else
GPG_GEN_KEY_IN_MEMORY=0
fi
# TODO: add LUKS container passphrase = ADMIN_PIN in security components provisioned
# 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
CUSTOM_PASS_AFFECTED_COMPONENTS="LUKS Disk Recovery Key passphrase"
@ -534,7 +846,8 @@ GPG User PIN"
while [[ ${#luks_new_Disk_Recovery_Key_passphrase} -lt 8 ]]; do
{
read -r luks_new_Disk_Recovery_Key_passphrase
};done
}
done
#We test that current Disk Recovery Key passphrase is known prior of going further
test_luks_current_disk_recovery_key_passphrase
echo -e "\n"
@ -559,7 +872,8 @@ GPG User PIN"
{
echo -e "\nEnter your email@address.org:"
read -r GPG_USER_MAIL
};done
}
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
@ -567,7 +881,8 @@ GPG User PIN"
{
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
}
done
fi
fi
@ -578,6 +893,7 @@ if [ "$ADMIN_PIN" == "" ]; then ADMIN_PIN=$ADMIN_PIN_DEF; fi
## sanity check the USB, GPG key, and boot device before proceeding further
if [ "$GPG_GEN_KEY_IN_MEMORY" == "0" ]; then
# 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
@ -605,10 +921,12 @@ else
# needed for USB Security dongle below and is ensured via mount-usb in case of GPG_EXPORT=1
enable_usb
fi
fi
# ensure USB Security Dongle connected
# ensure USB Security Dongle connected if GPG_GEN_KEY_IN_MEMORY=0
if [ "$GPG_GEN_KEY_IN_MEMORY" == "0" ]; then
echo -e "\nChecking for USB Security Dongle...\n"
# USB kernel modules already loaded via mount-usb
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
@ -616,6 +934,7 @@ if ! gpg --card-status >/dev/null 2>&1 ; then
whiptail_error_die "Unable to detect USB Security Dongle:\n\n${ERROR}"
fi
fi
fi
assert_signable
@ -663,15 +982,30 @@ rm /.gnupg/*.gpg 2>/dev/null
rm /.gnupg/*.kbx 2>/dev/null
gpg --list-keys >/dev/null 2>&1
#Generate key in memory and copy to smartcard
if [ "$GPG_GEN_KEY_IN_MEMORY" == "1" ]; then
# Generate GPG master key
generate_inmemory_RSA_master_and_subkeys
#TODO seperate wiping and thumb drive functions with proper validation
wipe_thumb_drive_and_copy_gpg_key_material
#TODO seperate setting config
set_user_config CONFIG_HAVE_GPG_KEY_BACKUP Y
gpg_key_factory_reset
keytocard_subkeys_to_smartcard
else
#Generate GPG key and subkeys on smartcard
## reset the GPG Key
echo -e "\nResetting GPG Key...\n(this will take around 3 minutes...)\n"
gpg_key_reset
gpg_key_factory_reset
generate_OEM_gpg_keys
fi
# parse name of generated key
GPG_GEN_KEY=`grep -A1 pub /tmp/gpg_card_edit_output | tail -n1 | sed -nr 's/^([ ])*//p'`
GPG_GEN_KEY=$(grep -A1 pub /tmp/gpg_card_edit_output | tail -n1 | sed -nr 's/^([ ])*//p')
PUBKEY="/tmp/${GPG_GEN_KEY}.asc"
#Applying custom GPG PINs
#Applying custom GPG PINs if keys were not generated in memory
if [ "$GPG_GEN_KEY_IN_MEMORY" == "0" ]; then
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"
@ -680,7 +1014,7 @@ if [ "$USER_PIN" != "" -o "$ADMIN_PIN" != "" ]; then
fi
# export pubkey to file
if ! gpg --export --armor $GPG_GEN_KEY > "${PUBKEY}" 2>/tmp/error ; then
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
@ -695,6 +1029,7 @@ if [ $GPG_EXPORT -ne 0 ]; then
fi
mount -o remount,ro /media 2>/dev/null
fi
fi
## flash generated key to ROM
echo -e "\nReading current firmware...\n(this will take a minute or two)\n"
@ -710,9 +1045,9 @@ if ! cat "$PUBKEY" | gpg --import >/dev/null 2>/tmp/error ; then
whiptail_error_die "Error importing GPG key:\n\n$ERROR"
fi
# update /.gnupg/trustdb.gpg to ultimately trust all user provided public keys
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
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
ERROR=$(tail -n 1 /tmp/error | fold -s)
whiptail_error_die "Error importing GPG ownertrust:\n\n$ERROR"
fi
@ -721,8 +1056,8 @@ if ! gpg --update-trust >/dev/null 2>/tmp/error ; then
whiptail_error_die "Error updating GPG ownertrust:\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
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

View File

@ -53,6 +53,51 @@ preserve_rom() {
done
}
gpg_auth() {
TRACE "Under /etc/ash_functions:gpg_auth"
if [ "$CONFIG_HAVE_GPG_KEY_BACKUP" = "y" ]; then
# If we have a GPG key backup, we can use it to authenticate even if the card is lost
echo >&2 "!!!!! Please authenticate with OpenPGP card/backup media to prove you are the owner of this machine !!!!!"
# Wipe any existing nonce and signature
shred -n 10 -z -u "$CR_NONCE" "$CR_SIG" 2>/dev/null || true
confirm_gpg_card
# Perform a signing-based challenge-response,
# to authencate that the card plugged in holding
# the key to sign the list of boot files.
CR_NONCE="/tmp/secret/cr_nonce"
CR_SIG="$CR_NONCE.sig"
# Generate a random nonce
dd \
if=/dev/urandom \
of="$CR_NONCE" \
count=1 \
bs=20 \
2>/dev/null \
|| die "Unable to generate 20 random bytes"
# Sign the nonce
for tries in 1 2 3; do
if gpg --digest-algo SHA256 \
--detach-sign \
-o "$CR_SIG" \
"$CR_NONCE" \
&& gpgv "$CR_SIG" "$CR_NONCE" \
; then
shred -n 10 -z -u "$CR_NONCE" "$CR_SIG" 2>/dev/null || true
return 0
else
shred -n 10 -z -u "$CR_SIG" 2>/dev/null || true
continue
fi
done
return 1
fi
}
recovery() {
TRACE "Under /etc/ash_functions:recovery"
echo >&2 "!!!!! $*"
@ -83,6 +128,9 @@ recovery() {
echo >&2 "!!!!! Starting recovery shell"
sleep 1
#Going to recovery shell should be authenticated if supported
gpg_auth
if [ -x /bin/setsid ]; then
/bin/setsid -c /bin/sh
else

View File

@ -191,19 +191,73 @@ list_usb_storage() {
confirm_gpg_card() {
TRACE "Under /etc/functions:confirm_gpg_card"
#Skip prompts if we are currently using a known GPG key material Thumb drive backup and keys are unlocked pinentry
#TODO: probably export CONFIG_GPG_KEY_BACKUP_IN_USE but not under /etc/user.config?
#Toggle to come in next PR, but currently we don't have a way to toggle it back to n if config.user flashed back in rom
if [[ "$CONFIG_HAVE_GPG_KEY_BACKUP" == "y" && "$CONFIG_GPG_KEY_BACKUP_IN_USE" == "y" ]]; then
return
fi
if [ "$CONFIG_HAVE_GPG_KEY_BACKUP" == "y" ]; then
message="Please confirm that your GPG card is inserted(Y/n) or your GPG key material (b)backup thumbdrive is inserted [Y/n/b]: "
else
# Generic message if no known key material backup
message+="Please confirm that your GPG card is inserted [Y/n]: "
fi
read \
-n 1 \
-p "Please confirm that your GPG card is inserted [Y/n]: " \
-p "$message" \
card_confirm
echo
if [ "$card_confirm" != "y" \
-a "$card_confirm" != "Y" \
-a "$card_confirm" != "b" \
-a -n "$card_confirm" ] \
; then
die "gpg card not confirmed"
fi
# If user has known GPG key material Thumb drive backup and asked to use it
if [[ "$CONFIG_HAVE_GPG_KEY_BACKUP" == "y" && "$card_confirm" == "b" ]]; then
#Only mount and import GPG key material thumb drive backup once
if [ ! "$CONFIG_GPG_KEY_BACKUP_IN_USE" == "y" ]; then
CR_NONCE="/tmp/secret/cr_nonce"
CR_SIG="$CR_NONCE.sig"
#Wipe any previous CR_NONCE and CR_SIG
shred -n 10 -z -u "$CR_NONCE" "$CR_SIG" >/dev/null 2>&1 || true
#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
#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"
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..."
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 dummy file to sign"
gpg --pinentry-mode=loopback --passphrase-file <(echo -n "${gpg_admin_pin}") --detach-sign "$CR_NONCE" >/dev/null 2>&1 ||
die "Unable to sign dummy file with GPG private signing subkey"
#verify detached signature against public key in rom
gpg --verify "$CR_SIG" "$CR_NONCE" || die "Unable to verify dummy file with GPG public key in ROM: public key mismatch"
#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
set_user_config CONFIG_GPG_KEY_BACKUP_IN_USE y
umount /media || die "Unable to unmount USB"
return
fi
#Else if user has known GPG key material Thumb drive backup and already asked to use it
if [[ "$CONFIG_HAVE_GPG_KEY_BACKUP" == "y" && "$CONFIG_GPG_KEY_BACKUP_IN_USE" == "y" ]]; then
return
fi
fi
# setup the USB so we can reach the GPG card
enable_usb

View File

@ -6,25 +6,20 @@
. /tmp/config
#List all LUKS devices on the system
list_luks_devices()
{
list_luks_devices() {
#generate a list of devices to choose from that contain a LUKS header
lvm vgscan || true
blkid | cut -d ':' -f 1 | while read device
do cryptsetup isLuks $device
if [ $? -eq 0 ]; then
echo "$device"
fi
blkid | cut -d ':' -f 1 | while read device; do
cryptsetup isLuks $device
if [ $(echo $?) == 0 ]; then echo $device; fi
done | sort
}
#Whiptail prompt asking user to select ratio of device to use for LUKS container between: 10, 25, 50, 75
select_luks_container_size_percent()
{
#Whiptail prompt asking user to select ratio of device to use for LUKS container between: 25, 50, 75
select_luks_container_size_percent() {
TRACE "Under /etc/luks-functions:select_luks_container_size_percent()"
if [ -x /bin/whiptail ]; then
#whiptail prompt asking user to select ratio of device to use for LUKS container between: 10, 25, 50, 75
#whiptail prompt asking user to select ratio of device to use for LUKS container between: 25, 50, 75
#whiptail returns the percentage of the device to use for LUKS container
whiptail --title "Select LUKS container size percentage of device" --menu \
"Select LUKS container size percentage of device:" 0 80 10 \
@ -84,12 +79,12 @@ prepare_thumb_drive()
PERCENTAGE=$2
shift 2
;;
--passphrase)
--pass)
PASSPHRASE=$2
shift 2
;;
*)
echo "usage: prepare_thumb_drive [--device device] [--percentage percentage] [--passphrase passphrase]"
echo "usage: prepare_thumb_drive [--device device] [--percentage percentage] [--pass passphrase]"
;;
esac
done
@ -201,8 +196,7 @@ prepare_thumb_drive()
fi
fi
echo -e "Preparing $DEVICE with $PERCENTAGE_MB MB for private LUKS container and rest of disk with exfat\
\n for public partition (This may take a while)..." | fold -s
echo -e "Preparing $DEVICE with $PERCENTAGE_MB MB for private LUKS container and rest of disk with exfat for public partition (This may take a while)..." | fold -s
DEBUG "Creating empty DOS partition table on device through fdisk to start clean"
echo -e "o\nw\n" | fdisk $DEVICE >/dev/null 2>&1 || die "Error creating partition table"
DEBUG "partition device with two partitions: first one being the percent applied and rest for second partition through fdisk"