From 56b602974bb36d87360b2c77de62b4ed13a57fde Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 25 Oct 2023 17:01:01 -0400 Subject: [PATCH] WiP: NK3 with p256 ECC algo supported for in-memory keygen and key-to-card op. With this commit, one can provision NK3 with thumb drive backup which enables authenticated recovery shell and USB boot. Signed-off-by: Thierry Laurion --- .../qemu-coreboot-fbwhiptail-tpm1-hotp.md | 1 + .../qemu-coreboot-whiptail-tpm1.config | 2 +- initrd/bin/oem-factory-reset | 143 +++++++++++++----- 3 files changed, 110 insertions(+), 36 deletions(-) diff --git a/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md b/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md index 7e9dffbf..4dbec899 100644 --- a/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md +++ b/boards/qemu-coreboot-fbwhiptail-tpm1-hotp/qemu-coreboot-fbwhiptail-tpm1-hotp.md @@ -45,6 +45,7 @@ Bootstrapping a working system * `sudo mount /dev/loop0p2 /media/fd_heads_gpg` to mount the second partition (public) or if only one partition, /dev/loop0p1 * Look in `/media/fd_heads_gpg` and copy the most recent public key * `sudo umount /media/fd_heads_gpg` + * `sudo losetup --detach /dev/loop0` 6. Inject the GPG key into the Heads image and run again * `make BOARD=qemu-coreboot-fbwhiptail-tpm1-hotp PUBKEY_ASC= inject_gpg` * `make BOARD=qemu-coreboot-fbwhiptail-tpm1-hotp USB_TOKEN=LibremKey PUBKEY_ASC= run` diff --git a/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config b/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config index 0b05dfaa..5353782e 100644 --- a/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config +++ b/boards/qemu-coreboot-whiptail-tpm1/qemu-coreboot-whiptail-tpm1.config @@ -12,7 +12,7 @@ export CONFIG_LINUX_VERSION=5.10.5 #Enable HAVE_GPG_KEY_BACKUP to test GPG key backup drive (we cannot inject config under QEMU (no internal flashing)) #TODO: comment following line prior of pushing final version -export CONFIG_HAVE_GPG_KEY_BACKUP=y +#export CONFIG_HAVE_GPG_KEY_BACKUP=y #Enable DEBUG output export CONFIG_DEBUG_OUTPUT=y diff --git a/initrd/bin/oem-factory-reset b/initrd/bin/oem-factory-reset index 1f44cc46..3579c32f 100755 --- a/initrd/bin/oem-factory-reset +++ b/initrd/bin/oem-factory-reset @@ -35,6 +35,8 @@ MAX_HOTP_GPG_PIN_LENGTH=25 # What are the Security components affected by custom passwords CUSTOM_PASS_AFFECTED_COMPONENTS="" +# Default GPG Algorithm is RSA +GPG_ALGO="RSA" # 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 @@ -70,7 +72,7 @@ whiptail_error_die() { die } -#Generate a gpg master key: passwordless, no expiration date, RSA 4096 bits +#Generate a gpg master key: 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() { @@ -169,6 +171,63 @@ generate_inmemory_RSA_master_and_subkeys() { fi } +#Generate a gpg master key: no expiration date, p256 key (ECC) +#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_p256_master_and_subkeys() { + DEBUG "Generating GPG key material in memory:" + gpg --expert --batch --pinentry-mode=loopback --passphrase ${ADMIN_PIN} --quick-generate-key "${GPG_USER_NAME} (${GPG_USER_COMMENT}) <${GPG_USER_MAIL}>" nistp256 cert 0 + + DEBUG "Getting master key fingerprint..." + MASTER_KEY_FP=$(gpg --list-secret-keys --with-colons | grep fpr | cut -d: -f10) + + DEBUG "MASTER_KEY_FP=${MASTER_KEY_FP}" + + DEBUG "Adding GPG nistp256 signing subkey to master key..." + { + echo addkey + echo 11 # ECC own set capability + echo Q # sign already present + echo 3 # P-256 + echo 0 # no expiration + echo save # save the key + } | gpg --command-fd=0 --passphrase ${ADMIN_PIN} --pinentry-mode=loopback --expert --edit-key ${MASTER_KEY_FP} >/tmp/gpg_card_edit_output 2>&1 + 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 + + DEBUG "Adding GPG nistp256 encryption subkey to master key..." + { + echo addkey + echo 12# ECC encrypt only + echo E # encrypt already present + echo 3 # P-256 + echo 0 # no expiration + echo save # save the key + } | gpg --command-fd=0 --passphrase ${ADMIN_PIN} --pinentry-mode=loopback --expert --edit-key ${MASTER_KEY_FP} >/tmp/gpg_card_edit_output 2>&1 + 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 + + DEBUG "Adding GPG nistp256 authentication subkey to master key..." + { + echo addkey + 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 save # save the key + } | gpg --command-fd=0 --passphrase ${ADMIN_PIN} --pinentry-mode=loopback --expert --edit-key ${MASTER_KEY_FP} >/tmp/gpg_card_edit_output 2>&1 + 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 +} + #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 @@ -435,23 +494,27 @@ gpg_key_factory_reset() { 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 - echo n - echo ${ADMIN_PIN_DEF} - echo ${USER_PIN_DEF} - echo 0 - echo ${GPG_USER_NAME} - echo ${GPG_USER_MAIL} - echo ${GPG_USER_COMMENT} - echo ${USER_PIN_DEF} - } | 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" + + #TODO: finish refactoring to adapt to GPG_ALGO != RSA + if [ "$GPG_ALGO" = "RSA" ]; then + DEBUG "Generating GPG keys to RSA ${RSA_KEY_LENGTH} bits in smartcard..." + { + echo admin + echo generate + echo n + echo ${ADMIN_PIN_DEF} + echo ${USER_PIN_DEF} + echo 0 + echo ${GPG_USER_NAME} + echo ${GPG_USER_MAIL} + echo ${GPG_USER_COMMENT} + echo ${USER_PIN_DEF} + } | 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" + fi fi } @@ -680,11 +743,10 @@ usb_security_token_capabilities_check() { DEBUG "Setting GPG_ALGO to (board-)configured: $CONFIG_GPG_ALGO" fi # ... overwrite with usb-token capability - #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 + if lsusb | grep -q "20a0:42b2"; then + GPG_ALGO="p256" + DEBUG "Nitrokey 3 detected: Setting GPG_ALGO to: $GPG_ALGO" + fi } ## main script start @@ -722,7 +784,8 @@ $TPM_STR fi # We show current integrity measurements status and time -report_integrity_measurements +#TODO: Reactivate this prior of PR review +#report_integrity_measurements # Determine gpg algorithm to be used, based on available usb-token usb_security_token_capabilities_check @@ -947,7 +1010,6 @@ assert_signable # clear local keyring rm /.gnupg/* | true - # detect and set /boot device echo -e "\nDetecting and setting boot device...\n" if ! detect_boot_device; then @@ -962,7 +1024,6 @@ if [[ "$SKIP_BOOT" == "n" ]]; then combine_configs fi - if [ -n "$luks_new_Disk_Recovery_Key_desired" -a -n "$luks_new_Disk_Recovery_Key_passphrase_desired" ]; then #Reencryption of disk, disk recovery key and Disk Recovery Key passphrase change is requested luks_reencrypt @@ -992,14 +1053,27 @@ 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 + # TODO: Refactoring in progress for RSA and p256 support. Now just GPG_ALGO RSA + if [ "$GPG_ALGO" == "RSA" ]; 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 #TODO: do we currently double reset? I think so + keytocard_subkeys_to_smartcard + elif [ "$GPG_ALGO" == "p256" ]; then + generate_inmemory_p256_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 #TODO: do we currently double reset? I think so + keytocard_subkeys_to_smartcard + else + die "Unsupported GPG_ALGO: $GPG_ALGO" + fi else #Generate GPG key and subkeys on smartcard ## reset the GPG Key @@ -1022,7 +1096,6 @@ if ! gpg --export --armor "$GPG_GEN_KEY" >"${PUBKEY}" 2>/tmp/error; then whiptail_error_die "GPG Key gpg export to file failed!\n\n$ERROR" fi - #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