From 6ba14371c7fbab2e40c6d1d6329cd1fafacd070e Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Wed, 1 Feb 2023 14:43:59 +0100 Subject: [PATCH 1/4] man: Use sbsigntools for secure boot key generation example This way, people do not need efitools installed to generate these as sbsigntools has everything needed to produce signed EFI variables. --- man/loader.conf.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/man/loader.conf.xml b/man/loader.conf.xml index 80122177e5..8808461ceb 100644 --- a/man/loader.conf.xml +++ b/man/loader.conf.xml @@ -254,8 +254,8 @@ uuid=$(systemd-id128 new --uuid) for key in PK KEK db; do openssl req -new -x509 -subj "/CN=${key}/" -keyout "${key}.key" -out "${key}.crt" - openssl x509 -outform DER -in "${key}.crt" -out "${key}.cer" - cert-to-efi-sig-list -g "${uuid}" "${key}.crt" "${key}.esl" + openssl x509 -outform DER -in "${key}.crt" -out "${key}.der" + sbsiglist --owner "${uuid}" --type x509 --output "${key}.esl" "${key}.der" done for key in MicWinProPCA2011_2011-10-19.crt MicCorUEFCA2011_2011-06-27.crt MicCorKEKCA2011_2011-06-24.crt; do @@ -266,7 +266,7 @@ done # Optionally add Microsoft Windows Production CA 2011 (needed to boot into Windows). cat MicWinProPCA2011_2011-10-19.esl >> db.esl -# Optionally add Microsoft Corporation UEFI CA 2011 (for firmware drivers / option ROMs +# Optionally add Microsoft Corporation UEFI CA 2011 for firmware drivers / option ROMs # and third-party boot loaders (including shim). This is highly recommended on real # hardware as not including this may soft-brick your device (see next paragraph). cat MicCorUEFCA2011_2011-06-27.esl >> db.esl @@ -276,9 +276,10 @@ cat MicCorUEFCA2011_2011-06-27.esl >> db.esl # key. The revocation database can be updated with fwupdmgr1. cat MicCorKEKCA2011_2011-06-24.esl >> KEK.esl -sign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth -sign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth -sign-efi-sig-list -c KEK.crt -k KEK.key db db.esl db.auth +attr=NON_VOLATILE,RUNTIME_ACCESS,BOOTSERVICE_ACCESS,TIME_BASED_AUTHENTICATED_WRITE_ACCESS +sbvarsign --attr ${attr} --key PK.key --cert PK.crt --output PK.auth PK PK.esl +sbvarsign --attr ${attr} --key PK.key --cert PK.crt --output KEK.auth KEK KEK.esl +sbvarsign --attr ${attr} --key KEK.key --cert KEK.crt --output db.auth db db.esl This feature is considered dangerous because even if all the required files are signed with the From 1e8e7f4463713177332957b7b3d3782ac765b61b Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Wed, 1 Feb 2023 15:23:25 +0100 Subject: [PATCH 2/4] boot: Add if-safe mode for secure boot enrollment --- man/loader.conf.xml | 33 +++++++++++++++++++++++++++------ src/boot/efi/boot.c | 14 ++++++++++---- src/boot/efi/secure-boot.c | 13 +++++++++---- src/boot/efi/secure-boot.h | 3 ++- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/man/loader.conf.xml b/man/loader.conf.xml index 8808461ceb..22f4644d9e 100644 --- a/man/loader.conf.xml +++ b/man/loader.conf.xml @@ -227,12 +227,33 @@ Danger: this feature might soft-brick your device if used improperly. - Takes one of off, manual or force. - Controls the enrollment of Secure Boot keys. If set to off, no action whatsoever - is taken. If set to manual (the default) and the UEFI firmware is in setup-mode - then entries to manually enroll Secure Boot variables are created in the boot menu. If set to - force, in addition, if a directory named /loader/keys/auto/ - exists on the ESP then the keys in that directory are enrolled automatically. + Controls enrollment of secure boot keys found on the ESP if the system is in setup mode: + + + + No action is taken. + + + + + Boot entries for found secure boot keys are created that allow manual + enrollment. + + + + + Same behavior as , but will try to automatically + enroll the key auto if it is considered to be safe. Currently, this is only + the case if the system is running inside a virtual machine. + + + + + Always enroll the auto key if found. Note that a warning + message with a timeout will still be shown if this operation is unknown to be safe. + + + The different sets of variables can be set up under /loader/keys/NAME where diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index bb318c4e7e..03fe022ef6 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -526,6 +526,9 @@ static void print_status(Config *config, char16_t *loaded_image_path) { case ENROLL_MANUAL: printf(" secure-boot-enroll: manual\n"); break; + case ENROLL_IF_SAFE: + printf(" secure-boot-enroll: if-safe\n"); + break; case ENROLL_FORCE: printf(" secure-boot-enroll: force\n"); break; @@ -1259,6 +1262,8 @@ static void config_defaults_load_from_file(Config *config, char *content) { config->secure_boot_enroll = ENROLL_MANUAL; else if (streq8(value, "force")) config->secure_boot_enroll = ENROLL_FORCE; + else if (streq8(value, "if-safe")) + config->secure_boot_enroll = ENROLL_IF_SAFE; else if (streq8(value, "off")) config->secure_boot_enroll = ENROLL_OFF; else @@ -1572,7 +1577,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) { .auto_entries = true, .auto_firmware = true, .reboot_for_bitlocker = false, - .secure_boot_enroll = ENROLL_MANUAL, + .secure_boot_enroll = ENROLL_IF_SAFE, .idx_default_efivar = IDX_INVALID, .console_mode = CONSOLE_MODE_KEEP, .console_mode_efivar = CONSOLE_MODE_KEEP, @@ -2511,10 +2516,11 @@ static EFI_STATUS secure_boot_discover_keys(Config *config, EFI_FILE *root_dir) }; config_add_entry(config, entry); - if (config->secure_boot_enroll == ENROLL_FORCE && strcaseeq16(dirent->FileName, u"auto")) + if (IN_SET(config->secure_boot_enroll, ENROLL_IF_SAFE, ENROLL_FORCE) && + strcaseeq16(dirent->FileName, u"auto")) /* if we auto enroll successfully this call does not return, if it fails we still * want to add other potential entries to the menu */ - secure_boot_enroll_at(root_dir, entry->path); + secure_boot_enroll_at(root_dir, entry->path, config->secure_boot_enroll == ENROLL_FORCE); } return EFI_SUCCESS; @@ -2700,7 +2706,7 @@ static EFI_STATUS run(EFI_HANDLE image) { /* if auto enrollment is activated, we try to load keys for the given entry. */ if (entry->type == LOADER_SECURE_BOOT_KEYS && config.secure_boot_enroll != ENROLL_OFF) { - err = secure_boot_enroll_at(root_dir, entry->path); + err = secure_boot_enroll_at(root_dir, entry->path, /*force=*/ true); if (err != EFI_SUCCESS) return err; continue; diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c index c8a3957b1e..8b796db65f 100644 --- a/src/boot/efi/secure-boot.c +++ b/src/boot/efi/secure-boot.c @@ -36,7 +36,7 @@ SecureBootMode secure_boot_mode(void) { static const char sbat[] _used_ _section_(".sbat") = SBAT_SECTION_TEXT; #endif -EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) { +EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force) { assert(root_dir); assert(path); @@ -44,11 +44,16 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path) { clear_screen(COLOR_NORMAL); - printf("Enrolling secure boot keys from directory: %ls\n", path); - /* Enrolling secure boot keys is safe to do in virtualized environments as there is nothing * we can brick there. */ - if (!in_hypervisor()) { + bool is_safe = in_hypervisor(); + + if (!is_safe && !force) + return EFI_SUCCESS; + + printf("Enrolling secure boot keys from directory: %ls\n", path); + + if (!is_safe) { printf("Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n"); unsigned timeout_sec = 15; diff --git a/src/boot/efi/secure-boot.h b/src/boot/efi/secure-boot.h index e98de81c2a..bdc34150da 100644 --- a/src/boot/efi/secure-boot.h +++ b/src/boot/efi/secure-boot.h @@ -9,13 +9,14 @@ typedef enum { ENROLL_OFF, /* no Secure Boot key enrollment whatsoever, even manual entries are not generated */ ENROLL_MANUAL, /* Secure Boot key enrollment is strictly manual: manual entries are generated and need to be selected by the user */ + ENROLL_IF_SAFE, /* Automatically enroll if it is safe (if we are running inside a VM, for example). */ ENROLL_FORCE, /* Secure Boot key enrollment may be automatic if it is available but might not be safe */ } secure_boot_enroll; bool secure_boot_enabled(void); SecureBootMode secure_boot_mode(void); -EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path); +EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool force); typedef bool (*security_validator_t)( const void *ctx, From c2aed1d16c591dc0390ac5dbd9bd0d1e775aa917 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Wed, 1 Feb 2023 15:27:45 +0100 Subject: [PATCH 3/4] git: Ignore mkosi secure boot keys --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8aa363eac4..844d67f0a1 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ __pycache__/ /mkosi.output/ /mkosi.default /mkosi.installdir/ +/mkosi.secure-boot.* # Ignore any mkosi config files with "local" in the name /mkosi.default.d/**/*local*.conf /tags From 2de6cc18f9ab6ceb46fd5008847f0226388fee90 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Tue, 31 Jan 2023 18:53:28 +0100 Subject: [PATCH 4/4] ci: Test with secure boot enabled under mkosi This gives us some nice test coverage for secure boot enrolling and the stub secure boot workound. The authenticated EFI variables are already created by mkosi, all we need to do is request secure boot to be used. --- .github/workflows/mkosi.yml | 5 ++++- test/mkosi-check-and-shutdown.sh | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml index d952e6b31b..84f930abd1 100644 --- a/.github/workflows/mkosi.yml +++ b/.github/workflows/mkosi.yml @@ -95,8 +95,11 @@ jobs: KernelCommandLine=${{ env.KERNEL_CMDLINE }} EOF + - name: Generate secure boot key + run: sudo mkosi genkey + - name: Build ${{ matrix.distro }} - run: sudo mkosi --idmap no + run: sudo mkosi --idmap no --secure-boot - name: Show ${{ matrix.distro }} image summary run: sudo mkosi summary diff --git a/test/mkosi-check-and-shutdown.sh b/test/mkosi-check-and-shutdown.sh index ed76ef370a..b86d2d3e69 100644 --- a/test/mkosi-check-and-shutdown.sh +++ b/test/mkosi-check-and-shutdown.sh @@ -3,6 +3,12 @@ systemctl --failed --no-legend | tee /failed-services +# Check that secure boot keys were properly enrolled. +if [[ -d /sys/firmware/efi/efivars/ ]]; then + cmp /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\1') + cmp /sys/firmware/efi/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c <(printf '\6\0\0\0\0') +fi + # Exit with non-zero EC if the /failed-services file is not empty (we have -e set) [[ ! -s /failed-services ]]