Skip to content

Commit 6da58d4

Browse files
committed
initrd/gpg: final review fixes for PR #2158
- Add local rc declarations in gpg_card_factory_reset, gpg_card_change_pin, and gpg_keytocard_subkeys to prevent global scope leaks - Add _luks_cleanup helper to close LUKS mappings on all error paths (removed broken EXIT trap that does not fire on function return) - Re-run NK3 Secrets app reset with custom PIN when factory reset is retried from default to custom PIN - Add chmod 600 on /tmp/secret/gpg_pin to match existing cache_gpg_signing_pin convention - Fix recovery-shell.md auth scope: USB/external media boot is also gated by gpg_auth via media-scan.sh Signed-off-by: Thierry Laurion <insurgo@riseup.net>
1 parent 2e873e9 commit 6da58d4

2 files changed

Lines changed: 36 additions & 19 deletions

File tree

doc/recovery-shell.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ with the in-memory backup path, or by running the reprovision flow from the GPG
2727
Management Menu), the recovery shell requires GPG smartcard authentication before
2828
the bash prompt opens.
2929

30-
**Scope:** This ONLY guards recovery shell entry. USB boot, TPM operations,
30+
**Scope:** This guards recovery shell and external media/USB boot entry
31+
(`media-scan.sh` also calls `gpg_auth` before scanning USB). TPM operations,
3132
flash/update, GPG management, and all other GUI menu functions are NOT gated
3233
by this check — they remain accessible from the main menu.
3334

initrd/etc/gpg_functions.sh

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ gpg_reset_nk3_secret_app() {
172172
fi
173173
done
174174
fi
175+
return 0
175176
}
176177

177178
# Factory-reset the OpenPGP smartcard and set key attributes for the given
@@ -185,6 +186,7 @@ gpg_card_factory_reset() {
185186
local algo="$1"
186187
local rsa_key_length="$2"
187188
local card_admin_pin="${3:-12345678}"
189+
local rc
188190

189191
STATUS "Factory resetting $DONGLE_BRAND OpenPGP smartcard"
190192
{
@@ -359,6 +361,7 @@ gpg_card_change_pin() {
359361
local pin_type="$1"
360362
local old_pin="$2"
361363
local new_pin="$3"
364+
local rc
362365
{
363366
echo admin # admin menu
364367
echo passwd # change PIN
@@ -389,6 +392,7 @@ gpg_keytocard_subkeys() {
389392
local key_id="$1"
390393
local subkey_pin="$2"
391394
local card_pin="${3:-12345678}"
395+
local rc
392396

393397
# Ensure USB and smartcard are accessible
394398
enable_usb
@@ -435,6 +439,15 @@ gpg_keytocard_subkeys() {
435439
TRACE_FUNC
436440
}
437441

442+
# Unmount /media and close any LUKS usb_mount mappings.
443+
# Called by reprovision_smartcard_from_backup() on error paths.
444+
_luks_cleanup() {
445+
umount /media 2>/dev/null || true
446+
for d in /dev/mapper/usb_mount_*; do
447+
[ -e "$d" ] && cryptsetup close "$(basename "$d")" 2>/dev/null || true
448+
done
449+
}
450+
438451
# Reprovision an OpenPGP smartcard from a GPG key backup on a LUKS-encrypted
439452
# USB drive. Detects key type (RSA vs ECC) from the imported key, mounts the
440453
# LUKS private partition to import privkey.sec, mounts the public partition to
@@ -448,9 +461,6 @@ reprovision_smartcard_from_backup() {
448461
local mapper_dev parent_disk pub_partition
449462
local algo_code bit_len
450463

451-
# Ensure LUKS mappings are cleaned up on any exit path (error or normal)
452-
trap 'umount /media 2>/dev/null || true; for d in /dev/mapper/usb_mount_*; do [ -e "$d" ] && cryptsetup close "$(basename "$d")" 2>/dev/null || true; done' EXIT
453-
454464
# Detect dongle branding early -- needed for whiptail messages and
455465
# Nitrokey Storage AES key reset in factory_reset_and_configure.
456466
enable_usb
@@ -505,7 +515,7 @@ reprovision_smartcard_from_backup() {
505515

506516
# Verify the private key backup file exists
507517
if [ ! -f /media/privkey.sec ]; then
508-
umount /media 2>/dev/null || true
518+
_luks_cleanup
509519
WARN "privkey.sec not found on backup drive -- not a valid GPG key backup"
510520
whiptail_error --title 'ERROR: No Backup Found' \
511521
--msgbox "No privkey.sec found on this drive.\n\nThis does not appear to be a valid\nGPG key backup drive." 0 80
@@ -517,7 +527,7 @@ reprovision_smartcard_from_backup() {
517527
STATUS "Importing GPG keys from backup"
518528
if ! gpg --pinentry-mode=loopback --passphrase-fd 3 3< <(echo -n "$admin_pin") \
519529
--import-options restore --import /media/privkey.sec >/dev/null 2>/tmp/gpg_import_err; then
520-
umount /media 2>/dev/null || true
530+
_luks_cleanup
521531
ERROR="$(cat /tmp/gpg_import_err)"
522532
WARN "GPG key import from backup failed: $(head -3 /tmp/gpg_import_err 2>/dev/null)"
523533
whiptail_error --title 'ERROR: Key Import Failed' \
@@ -546,7 +556,7 @@ reprovision_smartcard_from_backup() {
546556
DEBUG "Detected ECC P-256 key from backup"
547557
;;
548558
*)
549-
umount /media 2>/dev/null || true
559+
_luks_cleanup
550560
WARN "Unrecognized GPG algorithm code $algo_code from backup key"
551561
whiptail_error --title 'ERROR: Unknown Key Type' \
552562
--msgbox "Could not detect the key type from the backup\n(algorithm $algo_code).\n\nThe backup file may be corrupted." 0 80
@@ -571,7 +581,7 @@ reprovision_smartcard_from_backup() {
571581
else
572582
key_id="$(gpg --list-secret-keys --with-colons 2>/dev/null | grep '^sec:' | cut -d: -f5)"
573583
[ -z "$key_id" ] && {
574-
umount /media 2>/dev/null || true
584+
_luks_cleanup
575585
DIE "Could not determine key ID from imported backup"
576586
}
577587
fi
@@ -596,7 +606,7 @@ reprovision_smartcard_from_backup() {
596606
if ! whiptail_warning --title 'Dongle Compatibility Warning' \
597607
--yesno "The backed-up key is ECC P-256, but your $DONGLE_BRAND\nmay have limited ECC support.\n\nProceeding may fail.\n\nDo you want to continue?" 0 80; then
598608
DEBUG "User aborted: ECC key incompatible with dongle"
599-
umount /media 2>/dev/null || true
609+
_luks_cleanup
600610
return 1
601611
fi
602612
DEBUG "User accepted ECC compatibility risk"
@@ -611,15 +621,15 @@ reprovision_smartcard_from_backup() {
611621
if ! whiptail_warning --title 'Reprovision Smartcard' \
612622
--yesno "This will:\n\n * ERASE all keys on your $DONGLE_BRAND\n * Import GPG key: $identity_summary\n (${key_algo}$([ "$key_algo" = "RSA" ] && echo " ${rsa_key_length}-bit"))\n * Copy subkeys to the smartcard\n\nDo you want to continue?" 0 80; then
613623
DEBUG "User declined reprovision via confirmation dialog"
614-
umount /media 2>/dev/null || true
624+
_luks_cleanup
615625
return 1
616626
fi
617627
DEBUG "User confirmed reprovision; proceeding with factory reset"
618628

619629
# Re-verify the smartcard is still present before wiping it
620630
STATUS "Verifying $DONGLE_BRAND smartcard is still present"
621631
if ! gpg --card-status >/dev/null 2>&1; then
622-
umount /media 2>/dev/null || true
632+
_luks_cleanup
623633
WARN "$DONGLE_BRAND smartcard disappeared after user confirmation"
624634
whiptail_error --title 'ERROR: Smartcard Not Found' \
625635
--msgbox "The $DONGLE_BRAND smartcard is no longer detected.\n\nCheck the connection and try again." 0 80
@@ -653,10 +663,14 @@ reprovision_smartcard_from_backup() {
653663
while [ -z "$card_admin_pin" ]; do
654664
INPUT "Enter the current $DONGLE_BRAND admin PIN:" -r -s card_admin_pin
655665
done
666+
# Re-run NK3 Secrets app reset with the custom PIN
667+
release_scdaemon
668+
gpg_reset_nk3_secret_app "$card_admin_pin" || \
669+
DEBUG "NK3 Secrets app reset with custom PIN also failed (non-fatal)"
656670
fi
657671
done
658672
if [ "$factory_reset_ok" != "y" ]; then
659-
umount /media 2>/dev/null || true
673+
_luks_cleanup
660674
ERROR="$(tail -n 3 /tmp/gpg_card_edit_output 2>/dev/null | fold -s)"
661675
WARN "Smartcard factory reset failed after retry with correct admin PIN"
662676
whiptail_error --title 'ERROR: Factory Reset Failed' \
@@ -670,7 +684,7 @@ reprovision_smartcard_from_backup() {
670684
# Phase 6: move subkeys from the local keyring to the smartcard.
671685
DEBUG "Starting keytocard with key_id=$key_id, admin_pin=${#admin_pin} chars, card_admin_pin=${#card_admin_pin} chars"
672686
if ! gpg_keytocard_subkeys "$key_id" "$admin_pin" "$card_admin_pin"; then
673-
umount /media 2>/dev/null || true
687+
_luks_cleanup
674688
ERROR="$(cat /tmp/gpg_card_edit_output)"
675689
WARN "GPG keytocard operation failed: $(head -3 /tmp/gpg_card_edit_output 2>/dev/null)"
676690
whiptail_error --title 'ERROR: Keytocard Failed' \
@@ -698,7 +712,7 @@ reprovision_smartcard_from_backup() {
698712
ERROR="$(cat /tmp/gpg_card_edit_output | fold -s)"
699713
whiptail_error --title 'ERROR: Admin PIN Change Failed' \
700714
--msgbox "Could not change the Admin PIN.\n\n${ERROR}" 0 80
701-
umount /media 2>/dev/null || true
715+
_luks_cleanup
702716
return 1
703717
fi
704718
STATUS_OK "${pin_label_admin} changed"
@@ -717,16 +731,18 @@ reprovision_smartcard_from_backup() {
717731
ERROR="$(cat /tmp/gpg_card_edit_output | fold -s)"
718732
whiptail_error --title 'ERROR: User PIN Change Failed' \
719733
--msgbox "Could not change the User PIN.\n\n${ERROR}" 0 80
720-
umount /media 2>/dev/null || true
734+
_luks_cleanup
721735
return 1
722736
fi
723737
STATUS_OK "GPG User PIN changed"
724738
# Cache the User PIN for /boot signing after reprovision
725739
printf '%s' "$new_user_pin" >/tmp/secret/gpg_pin
740+
chmod 600 /tmp/secret/gpg_pin 2>/dev/null || true
726741
else
727742
DEBUG "User declined custom PINs; keeping factory defaults"
728743
# Cache default User PIN for /boot signing after reprovision
729744
printf '%s' "123456" >/tmp/secret/gpg_pin
745+
chmod 600 /tmp/secret/gpg_pin 2>/dev/null || true
730746
fi
731747

732748
# Sign /boot so hashes exist on next boot.
@@ -779,7 +795,7 @@ reprovision_smartcard_from_backup() {
779795
# Phase 8: save the LUKS mapper name so we can derive the public
780796
# partition device, then unmount the LUKS partition.
781797
mapper_dev="$(ls /dev/mapper/usb_mount_* 2>/dev/null | head -1)"
782-
umount /media 2>/dev/null || true
798+
_luks_cleanup
783799
if [ -n "$mapper_dev" ]; then
784800
# Extract partition name from mapper (e.g. usb_mount_sdb1 -> sdb1)
785801
# and derive parent disk (e.g. /dev/sdb) + public partition (/dev/sdb2).
@@ -823,7 +839,7 @@ reprovision_smartcard_from_backup() {
823839
else
824840
DEBUG "pubkey.asc import failed; exporting from imported keyring"
825841
gpg --export --armor "$key_id" >/tmp/reprovision_pubkey.asc 2>/dev/null || {
826-
umount /media 2>/dev/null || true
842+
_luks_cleanup
827843
DIE "Failed to export public key for ROM flash"
828844
}
829845
PUBKEY=/tmp/reprovision_pubkey.asc
@@ -832,7 +848,7 @@ reprovision_smartcard_from_backup() {
832848
# Fallback: export from the keyring (public key is already there
833849
# from the privkey.sec import)
834850
gpg --export --armor "$key_id" >/tmp/reprovision_pubkey.asc 2>/dev/null || {
835-
umount /media 2>/dev/null || true
851+
_luks_cleanup
836852
DIE "Failed to export public key for ROM flash"
837853
}
838854
PUBKEY=/tmp/reprovision_pubkey.asc
@@ -882,7 +898,7 @@ reprovision_smartcard_from_backup() {
882898

883899
DEBUG "Running cleanup: unmounting partitions and closing LUKS mappings"
884900
# Cleanup: unmount public partition and close any orphaned LUKS mappings
885-
umount /media 2>/dev/null || true
901+
_luks_cleanup
886902
for dev in /dev/mapper/usb_mount_*; do
887903
[ -e "$dev" ] && cryptsetup close "$(basename "$dev")" 2>/dev/null || true
888904
done

0 commit comments

Comments
 (0)