Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package grub2 for openSUSE:Factory checked in at 2022-08-12 17:46:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/grub2 (Old) and /work/SRC/openSUSE:Factory/.grub2.new.1521 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "grub2" Fri Aug 12 17:46:18 2022 rev:269 rq:994511 version:2.06 Changes: -------- --- /work/SRC/openSUSE:Factory/grub2/grub2.changes 2022-06-09 14:09:24.364336047 +0200 +++ /work/SRC/openSUSE:Factory/.grub2.new.1521/grub2.changes 2022-08-12 17:46:21.218070773 +0200 @@ -1,0 +2,34 @@ +Wed Jun 8 03:25:26 UTC 2022 - Michael Chang <[email protected]> + +- Add tpm, tpm2, luks2 and gcry_sha512 to default grub.efi (bsc#1197625) +- Make grub-tpm.efi a symlink to grub.efi + * grub2.spec +- Log error when tpm event log is full and continue + * 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch +- Patch superseded + * 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch + +------------------------------------------------------------------- +Wed Jun 8 03:17:29 UTC 2022 - Michael Chang <[email protected]> + +- Add patches for automatic TPM disk unlock (jsc#SLE-24018) (bsc#1196668) + * 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch + * 0002-cryptodisk-Refactor-to-discard-have_it-global.patch + * 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch + * 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch + * 0005-cryptodisk-Improve-cryptomount-u-error-message.patch + * 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch + * 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch + * 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch + * 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch + * 0010-protectors-Add-key-protectors-framework.patch + * 0011-tpm2-Add-TPM-Software-Stack-TSS.patch + * 0012-protectors-Add-TPM2-Key-Protector.patch + * 0013-cryptodisk-Support-key-protectors.patch + * 0014-util-grub-protect-Add-new-tool.patch +- Fix no disk unlocking happen (bsc#1196668) + * 0001-crytodisk-fix-cryptodisk-module-looking-up.patch +- Fix build error + * fix-tpm2-build.patch + +------------------------------------------------------------------- Old: ---- 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch New: ---- 0001-crytodisk-fix-cryptodisk-module-looking-up.patch 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch 0002-cryptodisk-Refactor-to-discard-have_it-global.patch 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch 0005-cryptodisk-Improve-cryptomount-u-error-message.patch 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch 0010-protectors-Add-key-protectors-framework.patch 0011-tpm2-Add-TPM-Software-Stack-TSS.patch 0012-protectors-Add-TPM2-Key-Protector.patch 0013-cryptodisk-Support-key-protectors.patch 0014-util-grub-protect-Add-new-tool.patch fix-tpm2-build.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ grub2.spec ++++++ --- /var/tmp/diff_new_pack.mTVNnA/_old 2022-08-12 17:46:24.442078831 +0200 +++ /var/tmp/diff_new_pack.mTVNnA/_new 2022-08-12 17:46:24.450078851 +0200 @@ -315,7 +315,6 @@ Patch790: 0001-30_uefi-firmware-fix-printf-format-with-null-byte.patch Patch791: 0001-i386-pc-build-btrfs-zstd-support-into-separate-modul.patch Patch792: 0001-templates-Follow-the-path-of-usr-merged-kernel-confi.patch -Patch793: 0001-tpm-Pass-unknown-error-as-non-fatal-but-debug-print-.patch Patch794: 0001-Filter-out-POSIX-locale-for-translation.patch Patch795: 0001-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch Patch796: 0001-disk-diskfilter-Use-nodes-in-logical-volume-s-segmen.patch @@ -407,6 +406,23 @@ Patch882: 0030-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch Patch883: 0031-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch Patch884: 0032-Use-grub_loader_set_ex-for-secureboot-chainloader.patch +Patch885: 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch +Patch886: 0002-cryptodisk-Refactor-to-discard-have_it-global.patch +Patch887: 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch +Patch888: 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch +Patch889: 0005-cryptodisk-Improve-cryptomount-u-error-message.patch +Patch890: 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch +Patch891: 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch +Patch892: 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch +Patch893: 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch +Patch894: 0010-protectors-Add-key-protectors-framework.patch +Patch895: 0011-tpm2-Add-TPM-Software-Stack-TSS.patch +Patch896: 0012-protectors-Add-TPM2-Key-Protector.patch +Patch897: 0013-cryptodisk-Support-key-protectors.patch +Patch898: 0014-util-grub-protect-Add-new-tool.patch +Patch899: fix-tpm2-build.patch +Patch900: 0001-crytodisk-fix-cryptodisk-module-looking-up.patch +Patch901: 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch Requires: gettext-runtime %if 0%{?suse_version} >= 1140 @@ -675,9 +691,9 @@ password password_pbkdf2 png reboot search search_fs_uuid \ search_fs_file search_label sleep test video fat loadenv" PXE_MODULES="tftp http" -CRYPTO_MODULES="luks gcry_rijndael gcry_sha1 gcry_sha256" +CRYPTO_MODULES="luks luks2 gcry_rijndael gcry_sha1 gcry_sha256 gcry_sha512" %ifarch %{efi} -CD_MODULES="${CD_MODULES} chain efifwsetup efinet read" +CD_MODULES="${CD_MODULES} chain efifwsetup efinet read tpm tpm2" PXE_MODULES="${PXE_MODULES} efinet" %else CD_MODULES="${CD_MODULES} net" @@ -715,10 +731,6 @@ ./grub-mkimage -O %{grubefiarch} -o grub.efi --prefix= %{?sbat_generation:--sbat sbat.csv} \ -d grub-core ${GRUB_MODULES} -%ifarch x86_64 -./grub-mkimage -O %{grubefiarch} -o grub-tpm.efi --prefix= %{?sbat_generation:--sbat sbat.csv} \ - -d grub-core ${GRUB_MODULES} tpm -%endif %ifarch x86_64 aarch64 if test -e %{_sourcedir}/_projectcert.crt ; then @@ -898,7 +910,7 @@ %make_install install -m 644 grub.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/. %ifarch x86_64 -install -m 644 grub-tpm.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/. +ln -srf %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/grub.efi %{buildroot}/%{_datadir}/%{name}/%{grubefiarch}/grub-tpm.efi %endif # Create grub.efi link to system efi directory @@ -920,9 +932,6 @@ %ifarch x86_64 aarch64 export BRP_PESIGN_FILES="%{_datadir}/%{name}/%{grubefiarch}/grub.efi" -%ifarch x86_64 -BRP_PESIGN_FILES="${BRP_PESIGN_FILES} %{_datadir}/%{name}/%{grubefiarch}/grub-tpm.efi" -%endif install -m 444 grub.der %{buildroot}/%{sysefidir}/ %endif @@ -1249,6 +1258,7 @@ %{_bindir}/%{name}-render-label %{_bindir}/%{name}-script-check %{_bindir}/%{name}-syslinux2cfg +%{_bindir}/%{name}-protect %if 0%{?has_systemd:1} %{_unitdir}/grub2-once.service %endif ++++++ 0001-crytodisk-fix-cryptodisk-module-looking-up.patch ++++++ >From 822f71318a69c150da3ad7df5fe8667dfa6e8069 Mon Sep 17 00:00:00 2001 From: Michael Chang <[email protected]> Date: Thu, 31 Mar 2022 15:45:35 +0800 Subject: [PATCH] crytodisk: fix cryptodisk module looking up The error "no cryptodisk module can handle this device" may happen even encrypted disk were correctly formatted and required modules were loaded. It is casued by missing break to the loop in which cryptodisk modules are iterated to find the one matching target's disk format. With the break statement, the loop will be always ended with testing last cryptodisk module on the list that may not be able to handle the format of encrypted disk's. Signed-off-by: Michael Chang <[email protected]> --- grub-core/disk/cryptodisk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 00c44773fb..6d22bf871c 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1021,6 +1021,7 @@ grub_cryptodisk_scan_device_real (const char *name, if (!dev) continue; crd = cr; + break; } if (!dev) -- 2.34.1 ++++++ 0001-luks2-Add-debug-message-to-align-with-luks-and-geli-.patch ++++++ >From 8eae4c33a32d9951641e289d2809a92a223b1642 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:50 -0600 Subject: [PATCH 01/14] luks2: Add debug message to align with luks and geli modules Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/luks2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c index 371a53b837..fea196dd4a 100644 --- a/grub-core/disk/luks2.c +++ b/grub-core/disk/luks2.c @@ -370,7 +370,10 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) uuid[j] = '\0'; if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) - return NULL; + { + grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); + return NULL; + } cryptodisk = grub_zalloc (sizeof (*cryptodisk)); if (!cryptodisk) -- 2.34.1 ++++++ 0001-tpm-Log-EFI_VOLUME_FULL-and-continue.patch ++++++ >From 8c9f7cefdf9d03cae65773ef35e103fc346ee17f Mon Sep 17 00:00:00 2001 From: Michael Chang <[email protected]> Date: Tue, 3 May 2022 12:38:34 +0800 Subject: [PATCH] tpm: Log EFI_VOLUME_FULL and continue Appending entries to tpm event log would fail if it is full and in this case EFI_VOLUME_FULL is returned. Since the measurement itself is successful but only the event is not logged, the booting shouldn't be forced to stop and instead grub should log the error and continue. All errors other than EFI_VOLUME_FULL remains to stop grub from booting so the failure can be examined. In case of unknown tpm error, the return code from efi firmware is also displayed for reference. Signed-off-by: Michael Chang <[email protected]> --- grub-core/commands/efi/tpm.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c index a97d85368a..98fd5892b0 100644 --- a/grub-core/commands/efi/tpm.c +++ b/grub-core/commands/efi/tpm.c @@ -144,8 +144,10 @@ grub_efi_log_event_status (grub_efi_status_t status) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); case GRUB_EFI_NOT_FOUND: return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + case GRUB_EFI_VOLUME_FULL: + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("TPM event log is full")); default: - return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error: %" PRIuGRUB_SIZE), status); } } @@ -159,6 +161,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, grub_efi_tpm_protocol_t *tpm; grub_efi_physical_address_t lastevent; grub_uint32_t algorithm; + grub_err_t err; grub_uint32_t eventnum = 0; tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, @@ -182,7 +185,12 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, algorithm, event, &eventnum, &lastevent); grub_free (event); - return grub_efi_log_event_status (status); + err = grub_efi_log_event_status (status); + /* Log EFI_VOLUME_FULL and continue */ + if (err == GRUB_ERR_OUT_OF_RANGE) + grub_print_error (); + + return err; } static grub_err_t @@ -193,6 +201,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, EFI_TCG2_EVENT *event; grub_efi_status_t status; grub_efi_tpm2_protocol_t *tpm; + grub_err_t err; tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); @@ -218,7 +227,12 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, (grub_uint64_t) size, event); grub_free (event); - return grub_efi_log_event_status (status); + err = grub_efi_log_event_status (status); + /* Log EFI_VOLUME_FULL and continue */ + if (err == GRUB_ERR_OUT_OF_RANGE) + grub_print_error (); + + return err; } grub_err_t -- 2.34.1 ++++++ 0002-cryptodisk-Refactor-to-discard-have_it-global.patch ++++++ >From 4ace73cc192bc63a00f4208b34981a6d91947811 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:51 -0600 Subject: [PATCH 02/14] cryptodisk: Refactor to discard have_it global The global "have_it" was never used by the crypto-backends, but was used to determine if a crypto-backend successfully mounted a cryptodisk with a given UUID. This is not needed however, because grub_device_iterate() will return 1 if and only if grub_cryptodisk_scan_device() returns 1. And grub_cryptodisk_scan_device() will now only return 1 if a search_uuid has been specified and a cryptodisk was successfully setup by a crypto-backend or a cryptodisk of the requested UUID is already open. To implement this grub_cryptodisk_scan_device_real() is modified to return a cryptodisk or NULL on failure and having the appropriate grub_errno set to indicated failure. Note that grub_cryptodisk_scan_device_real() will fail now with a new errno GRUB_ERR_BAD_MODULE when none of the cryptodisk backend modules succeed in identifying the source disk. With this change grub_device_iterate() will return 1 when a crypto device is successfully decrypted or when the source device has already been successfully opened. Prior to this change, trying to mount an already successfully opened device would trigger an error with the message "no such cryptodisk found", which is at best misleading. The mount should silently succeed in this case, which is what happens with this patch. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/cryptodisk.c | 56 +++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 90f82b2d39..9df3d310fe 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -983,7 +983,7 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) #endif -static int check_boot, have_it; +static int check_boot; static char *search_uuid; static void @@ -995,7 +995,7 @@ cryptodisk_close (grub_cryptodisk_t dev) grub_free (dev); } -static grub_err_t +static grub_cryptodisk_t grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) { grub_err_t err; @@ -1005,13 +1005,13 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) dev = grub_cryptodisk_get_by_source_disk (source); if (dev) - return GRUB_ERR_NONE; + return dev; FOR_CRYPTODISK_DEVS (cr) { dev = cr->scan (source, search_uuid, check_boot); if (grub_errno) - return grub_errno; + return NULL; if (!dev) continue; @@ -1019,16 +1019,16 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) if (err) { cryptodisk_close (dev); - return err; + return NULL; } grub_cryptodisk_insert (dev, name, source); - have_it = 1; - - return GRUB_ERR_NONE; + return dev; } - return GRUB_ERR_NONE; + + grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); + return NULL; } #ifdef GRUB_UTIL @@ -1082,8 +1082,10 @@ static int grub_cryptodisk_scan_device (const char *name, void *data __attribute__ ((unused))) { - grub_err_t err; + int ret = 0; grub_disk_t source; + grub_cryptodisk_t dev; + grub_errno = GRUB_ERR_NONE; /* Try to open disk. */ source = grub_disk_open (name); @@ -1093,13 +1095,26 @@ grub_cryptodisk_scan_device (const char *name, return 0; } - err = grub_cryptodisk_scan_device_real (name, source); + dev = grub_cryptodisk_scan_device_real (name, source); + if (dev) + { + ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); + goto cleanup; + } - grub_disk_close (source); - - if (err) + /* + * Do not print error when err is GRUB_ERR_BAD_MODULE to avoid many unhelpful + * error messages. + */ + if (grub_errno == GRUB_ERR_BAD_MODULE) + grub_error_pop (); + + if (grub_errno != GRUB_ERR_NONE) grub_print_error (); - return have_it && search_uuid ? 1 : 0; + + cleanup: + grub_disk_close (source); + return ret; } static grub_err_t @@ -1110,9 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) if (argc < 1 && !state[1].set && !state[2].set) return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); - have_it = 0; if (state[0].set) { + int found_uuid; grub_cryptodisk_t dev; dev = grub_cryptodisk_get_by_uuid (args[0]); @@ -1125,10 +1140,10 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) check_boot = state[2].set; search_uuid = args[0]; - grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); search_uuid = NULL; - if (!have_it) + if (!found_uuid) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); return GRUB_ERR_NONE; } @@ -1142,7 +1157,6 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) } else { - grub_err_t err; grub_disk_t disk; grub_cryptodisk_t dev; char *diskname; @@ -1178,13 +1192,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) return GRUB_ERR_NONE; } - err = grub_cryptodisk_scan_device_real (diskname, disk); + dev = grub_cryptodisk_scan_device_real (diskname, disk); grub_disk_close (disk); if (disklast) *disklast = ')'; - return err; + return (dev == NULL) ? grub_errno : GRUB_ERR_NONE; } } -- 2.34.1 ++++++ 0003-cryptodisk-Return-failure-in-cryptomount-when-no-cry.patch ++++++ >From 86fe3bbbf75e62387cc9842654fd6c852e9457a6 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:52 -0600 Subject: [PATCH 03/14] cryptodisk: Return failure in cryptomount when no cryptodisk modules are loaded This displays an error notifying the user that they'll want to load a backend module to make cryptomount useful. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/cryptodisk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 9df3d310fe..27491871a5 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1125,6 +1125,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) if (argc < 1 && !state[1].set && !state[2].set) return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); + if (grub_cryptodisk_list == NULL) + return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + if (state[0].set) { int found_uuid; -- 2.34.1 ++++++ 0004-cryptodisk-Improve-error-messaging-in-cryptomount-in.patch ++++++ >From f41488d0e361a34f4d3f8fb6c92729a2901a5c76 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:53 -0600 Subject: [PATCH 04/14] cryptodisk: Improve error messaging in cryptomount invocations Update such that "cryptomount -u UUID" will not print two error messages when an invalid passphrase is given and the most relevant error message will be displayed. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/cryptodisk.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 27491871a5..3a896c6634 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1109,7 +1109,10 @@ grub_cryptodisk_scan_device (const char *name, if (grub_errno == GRUB_ERR_BAD_MODULE) grub_error_pop (); - if (grub_errno != GRUB_ERR_NONE) + if (search_uuid != NULL) + /* Push error onto stack to save for cryptomount. */ + grub_error_push (); + else grub_print_error (); cleanup: @@ -1146,9 +1149,19 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); search_uuid = NULL; - if (!found_uuid) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); - return GRUB_ERR_NONE; + if (found_uuid) + return GRUB_ERR_NONE; + else if (grub_errno == GRUB_ERR_NONE) + { + /* + * Try to pop the next error on the stack. If there is not one, then + * no device matched the given UUID. + */ + grub_error_pop (); + if (grub_errno == GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); + } + return grub_errno; } else if (state[1].set || (argc == 0 && state[2].set)) { -- 2.34.1 ++++++ 0005-cryptodisk-Improve-cryptomount-u-error-message.patch ++++++ >From 9ef619a7c1d38988f6d91496ea5c59062dcf6013 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:54 -0600 Subject: [PATCH 05/14] cryptodisk: Improve cryptomount -u error message When a cryptmount is specified with a UUID, but no cryptodisk backends find a disk with that UUID, return a more detailed message giving telling the user that they might not have a needed cryptobackend module loaded. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/cryptodisk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 3a896c6634..5a9780b14c 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1159,7 +1159,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) */ grub_error_pop (); if (grub_errno == GRUB_ERR_NONE) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found"); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no such cryptodisk found, perhaps a needed disk or cryptodisk module is not loaded"); } return grub_errno; } -- 2.34.1 ++++++ 0006-cryptodisk-Add-infrastructure-to-pass-data-from-cryp.patch ++++++ >From 0a5619abd170b3ad43e44cb8036062506d8623cc Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:55 -0600 Subject: [PATCH 06/14] cryptodisk: Add infrastructure to pass data from cryptomount to cryptodisk modules Previously, the cryptomount arguments were passed by global variable and function call argument, neither of which are ideal. This change passes data via a grub_cryptomount_args struct, which can be added to over time as opposed to continually adding arguments to the cryptodisk scan and recover_key. As an example, passing a password as a cryptomount argument is implemented. However, the backends are not implemented, so testing this will return a not implemented error. Also, add comments to cryptomount argument parsing to make it more obvious which argument states are being handled. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/cryptodisk.c | 31 +++++++++++++++++++++---------- grub-core/disk/geli.c | 6 +++++- grub-core/disk/luks.c | 7 ++++++- grub-core/disk/luks2.c | 7 ++++++- include/grub/cryptodisk.h | 9 ++++++++- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 5a9780b14c..14c661a86e 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = /* TRANSLATORS: It's still restricted to cryptodisks only. */ {"all", 'a', 0, N_("Mount all."), 0, 0}, {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, + {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -996,7 +997,9 @@ cryptodisk_close (grub_cryptodisk_t dev) } static grub_cryptodisk_t -grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) +grub_cryptodisk_scan_device_real (const char *name, + grub_disk_t source, + grub_cryptomount_args_t cargs) { grub_err_t err; grub_cryptodisk_t dev; @@ -1015,7 +1018,7 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source) if (!dev) continue; - err = cr->recover_key (source, dev); + err = cr->recover_key (source, dev, cargs); if (err) { cryptodisk_close (dev); @@ -1080,11 +1083,12 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) static int grub_cryptodisk_scan_device (const char *name, - void *data __attribute__ ((unused))) + void *data) { int ret = 0; grub_disk_t source; grub_cryptodisk_t dev; + grub_cryptomount_args_t cargs = data; grub_errno = GRUB_ERR_NONE; /* Try to open disk. */ @@ -1095,7 +1099,7 @@ grub_cryptodisk_scan_device (const char *name, return 0; } - dev = grub_cryptodisk_scan_device_real (name, source); + dev = grub_cryptodisk_scan_device_real (name, source, cargs); if (dev) { ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); @@ -1124,6 +1128,7 @@ static grub_err_t grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) { struct grub_arg_list *state = ctxt->state; + struct grub_cryptomount_args cargs = {0}; if (argc < 1 && !state[1].set && !state[2].set) return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); @@ -1131,7 +1136,13 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) if (grub_cryptodisk_list == NULL) return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); - if (state[0].set) + if (state[3].set) /* password */ + { + cargs.key_data = (grub_uint8_t *) state[3].arg; + cargs.key_len = grub_strlen (state[3].arg); + } + + if (state[0].set) /* uuid */ { int found_uuid; grub_cryptodisk_t dev; @@ -1146,7 +1157,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) check_boot = state[2].set; search_uuid = args[0]; - found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); search_uuid = NULL; if (found_uuid) @@ -1163,11 +1174,11 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) } return grub_errno; } - else if (state[1].set || (argc == 0 && state[2].set)) + else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ { search_uuid = NULL; check_boot = state[2].set; - grub_device_iterate (&grub_cryptodisk_scan_device, NULL); + grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); search_uuid = NULL; return GRUB_ERR_NONE; } @@ -1208,7 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) return GRUB_ERR_NONE; } - dev = grub_cryptodisk_scan_device_real (diskname, disk); + dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs); grub_disk_close (disk); if (disklast) @@ -1347,7 +1358,7 @@ GRUB_MOD_INIT (cryptodisk) { grub_disk_dev_register (&grub_cryptodisk_dev); cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, - N_("SOURCE|-u UUID|-a|-b"), + N_("[-p password] <SOURCE|-u UUID|-a|-b>"), N_("Mount a crypto device."), options); grub_procfs_register ("luks_script", &luks_script); } diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c index 2f34a35e6b..777da3a055 100644 --- a/grub-core/disk/geli.c +++ b/grub-core/disk/geli.c @@ -398,7 +398,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, } static grub_err_t -recover_key (grub_disk_t source, grub_cryptodisk_t dev) +recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs) { grub_size_t keysize; grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN]; @@ -414,6 +414,10 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) grub_disk_addr_t sector; grub_err_t err; + /* Keyfiles are not implemented yet */ + if (cargs->key_data != NULL || cargs->key_len) + return GRUB_ERR_NOT_IMPLEMENTED_YET; + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) return grub_error (GRUB_ERR_BUG, "cipher block is too long"); diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c index 13103ea6a2..c5858fcf8a 100644 --- a/grub-core/disk/luks.c +++ b/grub-core/disk/luks.c @@ -152,7 +152,8 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, static grub_err_t luks_recover_key (grub_disk_t source, - grub_cryptodisk_t dev) + grub_cryptodisk_t dev, + grub_cryptomount_args_t cargs) { struct grub_luks_phdr header; grub_size_t keysize; @@ -165,6 +166,10 @@ luks_recover_key (grub_disk_t source, grub_size_t max_stripes = 1; char *tmp; + /* Keyfiles are not implemented yet */ + if (cargs->key_data != NULL || cargs->key_len) + return GRUB_ERR_NOT_IMPLEMENTED_YET; + err = grub_disk_read (source, 0, 0, sizeof (header), &header); if (err) return err; diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c index fea196dd4a..2cbec8acc2 100644 --- a/grub-core/disk/luks2.c +++ b/grub-core/disk/luks2.c @@ -545,7 +545,8 @@ luks2_decrypt_key (grub_uint8_t *out_key, static grub_err_t luks2_recover_key (grub_disk_t source, - grub_cryptodisk_t crypt) + grub_cryptodisk_t crypt, + grub_cryptomount_args_t cargs) { grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; char passphrase[MAX_PASSPHRASE], cipher[32]; @@ -559,6 +560,10 @@ luks2_recover_key (grub_disk_t source, grub_json_t *json = NULL, keyslots; grub_err_t ret; + /* Keyfiles are not implemented yet */ + if (cargs->key_data != NULL || cargs->key_len) + return GRUB_ERR_NOT_IMPLEMENTED_YET; + ret = luks2_read_header (source, &header); if (ret) return ret; diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h index dcf17fbb3a..282f8ac456 100644 --- a/include/grub/cryptodisk.h +++ b/include/grub/cryptodisk.h @@ -66,6 +66,13 @@ typedef gcry_err_code_t (*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, grub_uint64_t zoneno); +struct grub_cryptomount_args +{ + grub_uint8_t *key_data; + grub_size_t key_len; +}; +typedef struct grub_cryptomount_args *grub_cryptomount_args_t; + struct grub_cryptodisk { struct grub_cryptodisk *next; @@ -119,7 +126,7 @@ struct grub_cryptodisk_dev grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, int boot_only); - grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev); + grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); }; typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; -- 2.34.1 ++++++ 0007-cryptodisk-Refactor-password-input-out-of-crypto-dev.patch ++++++ >From a3ae3f800f6aa3f6036351133ed69fa47c9fa371 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:56 -0600 Subject: [PATCH 07/14] cryptodisk: Refactor password input out of crypto dev modules into cryptodisk The crypto device modules should only be setting up the crypto devices and not getting user input. This has the added benefit of simplifying the code such that three essentially duplicate pieces of code are merged into one. Add documentation of passphrase option for cryptomount as it is now usable. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- docs/grub.texi | 8 ++++-- grub-core/disk/cryptodisk.c | 56 +++++++++++++++++++++++++++++-------- grub-core/disk/geli.c | 26 ++++------------- grub-core/disk/luks.c | 27 +++--------------- grub-core/disk/luks2.c | 25 +++-------------- include/grub/cryptodisk.h | 1 + 6 files changed, 64 insertions(+), 79 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index f4794fddac..4504bcabec 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4310,9 +4310,11 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum} @node cryptomount @subsection cryptomount -@deffn Command cryptomount device|@option{-u} uuid|@option{-a}|@option{-b} -Setup access to encrypted device. If necessary, passphrase -is requested interactively. Option @var{device} configures specific grub device +@deffn Command cryptomount [@option{-p} password] device|@option{-u} uuid|@option{-a}|@option{-b} +Setup access to encrypted device. If @option{-p} is not given, a passphrase +is requested interactively. Otherwise, the given @var{password} will be used and +no passphrase will be requested interactively. +Option @var{device} configures specific grub device (@pxref{Naming convention}); option @option{-u} @var{uuid} configures device with specified @var{uuid}; option @option{-a} configures all detected encrypted devices; option @option{-b} configures all geli containers that have boot flag set. diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 14c661a86e..d12368a1f7 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1001,9 +1001,11 @@ grub_cryptodisk_scan_device_real (const char *name, grub_disk_t source, grub_cryptomount_args_t cargs) { - grub_err_t err; + grub_err_t ret = GRUB_ERR_NONE; grub_cryptodisk_t dev; grub_cryptodisk_dev_t cr; + int askpass = 0; + char *part = NULL; dev = grub_cryptodisk_get_by_source_disk (source); @@ -1017,21 +1019,53 @@ grub_cryptodisk_scan_device_real (const char *name, return NULL; if (!dev) continue; - - err = cr->recover_key (source, dev, cargs); - if (err) - { - cryptodisk_close (dev); - return NULL; - } + + if (!cargs->key_len) + { + /* Get the passphrase from the user, if no key data. */ + askpass = 1; + if (source->partition != NULL) + part = grub_partition_get_name (source->partition); + grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, + source->partition != NULL ? "," : "", + part != NULL ? part : "", + dev->uuid); + grub_free (part); + + cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); + if (cargs->key_data == NULL) + return NULL; + + if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); + goto error; + } + cargs->key_len = grub_strlen ((char *) cargs->key_data); + } + + ret = cr->recover_key (source, dev, cargs); + if (ret != GRUB_ERR_NONE) + goto error; grub_cryptodisk_insert (dev, name, source); - return dev; + goto cleanup; } - grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); - return NULL; + goto cleanup; + + error: + cryptodisk_close (dev); + dev = NULL; + + cleanup: + if (askpass) + { + cargs->key_len = 0; + grub_free (cargs->key_data); + } + return dev; } #ifdef GRUB_UTIL diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c index 777da3a055..7299a47d19 100644 --- a/grub-core/disk/geli.c +++ b/grub-core/disk/geli.c @@ -135,8 +135,6 @@ const char *algorithms[] = { [0x16] = "aes" }; -#define MAX_PASSPHRASE 256 - static gcry_err_code_t geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno) { @@ -406,17 +404,14 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t grub_uint8_t verify_key[GRUB_CRYPTO_MAX_MDLEN]; grub_uint8_t zero[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE]; grub_uint8_t geli_cipher_key[64]; - char passphrase[MAX_PASSPHRASE] = ""; unsigned i; gcry_err_code_t gcry_err; struct grub_geli_phdr header; - char *tmp; grub_disk_addr_t sector; grub_err_t err; - /* Keyfiles are not implemented yet */ - if (cargs->key_data != NULL || cargs->key_len) - return GRUB_ERR_NOT_IMPLEMENTED_YET; + if (cargs->key_data == NULL || cargs->key_len == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) return grub_error (GRUB_ERR_BUG, "cipher block is too long"); @@ -438,23 +433,12 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t grub_puts_ (N_("Attempting to decrypt master key...")); - /* Get the passphrase from the user. */ - tmp = NULL; - if (source->partition) - tmp = grub_partition_get_name (source->partition); - grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, - source->partition ? "," : "", tmp ? : "", - dev->uuid); - grub_free (tmp); - if (!grub_password_get (passphrase, MAX_PASSPHRASE)) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); - /* Calculate the PBKDF2 of the user supplied passphrase. */ if (grub_le_to_cpu32 (header.niter) != 0) { grub_uint8_t pbkdf_key[64]; - gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, - grub_strlen (passphrase), + gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, + cargs->key_len, header.salt, sizeof (header.salt), grub_le_to_cpu32 (header.niter), @@ -477,7 +461,7 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_args_t return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt)); - grub_crypto_hmac_write (hnd, passphrase, grub_strlen (passphrase)); + grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len); gcry_err = grub_crypto_hmac_fini (hnd, geomkey); if (gcry_err) diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c index c5858fcf8a..39a7af6a43 100644 --- a/grub-core/disk/luks.c +++ b/grub-core/disk/luks.c @@ -29,8 +29,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); -#define MAX_PASSPHRASE 256 - #define LUKS_KEY_ENABLED 0x00AC71F3 /* On disk LUKS header */ @@ -158,17 +156,14 @@ luks_recover_key (grub_disk_t source, struct grub_luks_phdr header; grub_size_t keysize; grub_uint8_t *split_key = NULL; - char passphrase[MAX_PASSPHRASE] = ""; grub_uint8_t candidate_digest[sizeof (header.mkDigest)]; unsigned i; grub_size_t length; grub_err_t err; grub_size_t max_stripes = 1; - char *tmp; - /* Keyfiles are not implemented yet */ - if (cargs->key_data != NULL || cargs->key_len) - return GRUB_ERR_NOT_IMPLEMENTED_YET; + if (cargs->key_data == NULL || cargs->key_len == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); err = grub_disk_read (source, 0, 0, sizeof (header), &header); if (err) @@ -188,20 +183,6 @@ luks_recover_key (grub_disk_t source, if (!split_key) return grub_errno; - /* Get the passphrase from the user. */ - tmp = NULL; - if (source->partition) - tmp = grub_partition_get_name (source->partition); - grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, - source->partition ? "," : "", tmp ? : "", - dev->uuid); - grub_free (tmp); - if (!grub_password_get (passphrase, MAX_PASSPHRASE)) - { - grub_free (split_key); - return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); - } - /* Try to recover master key from each active keyslot. */ for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) { @@ -216,8 +197,8 @@ luks_recover_key (grub_disk_t source, grub_dprintf ("luks", "Trying keyslot %d\n", i); /* Calculate the PBKDF2 of the user supplied passphrase. */ - gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase, - grub_strlen (passphrase), + gcry_err = grub_crypto_pbkdf2 (dev->hash, cargs->key_data, + cargs->key_len, header.keyblock[i].passwordSalt, sizeof (header.keyblock[i].passwordSalt), grub_be_to_cpu32 (header.keyblock[i]. diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c index 2cbec8acc2..09740b53f9 100644 --- a/grub-core/disk/luks2.c +++ b/grub-core/disk/luks2.c @@ -35,8 +35,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define LUKS_MAGIC_1ST "LUKS\xBA\xBE" #define LUKS_MAGIC_2ND "SKUL\xBA\xBE" -#define MAX_PASSPHRASE 256 - enum grub_luks2_kdf_type { LUKS2_KDF_TYPE_ARGON2I, @@ -549,8 +547,7 @@ luks2_recover_key (grub_disk_t source, grub_cryptomount_args_t cargs) { grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; - char passphrase[MAX_PASSPHRASE], cipher[32]; - char *json_header = NULL, *part = NULL, *ptr; + char cipher[32], *json_header = NULL, *ptr; grub_size_t candidate_key_len = 0, json_idx, size; grub_luks2_header_t header; grub_luks2_keyslot_t keyslot; @@ -560,9 +557,8 @@ luks2_recover_key (grub_disk_t source, grub_json_t *json = NULL, keyslots; grub_err_t ret; - /* Keyfiles are not implemented yet */ - if (cargs->key_data != NULL || cargs->key_len) - return GRUB_ERR_NOT_IMPLEMENTED_YET; + if (cargs->key_data == NULL || cargs->key_len == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); ret = luks2_read_header (source, &header); if (ret) @@ -589,18 +585,6 @@ luks2_recover_key (grub_disk_t source, goto err; } - /* Get the passphrase from the user. */ - if (source->partition) - part = grub_partition_get_name (source->partition); - grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, - source->partition ? "," : "", part ? : "", - crypt->uuid); - if (!grub_password_get (passphrase, MAX_PASSPHRASE)) - { - ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied"); - goto err; - } - if (grub_json_getvalue (&keyslots, json, "keyslots") || grub_json_getsize (&size, &keyslots)) { @@ -725,7 +709,7 @@ luks2_recover_key (grub_disk_t source, } ret = luks2_decrypt_key (candidate_key, source, crypt, &keyslot, - (const grub_uint8_t *) passphrase, grub_strlen (passphrase)); + cargs->key_data, cargs->key_len); if (ret) { grub_dprintf ("luks2", "Decryption with keyslot \"%" PRIuGRUB_UINT64_T "\" failed: %s\n", @@ -777,7 +761,6 @@ luks2_recover_key (grub_disk_t source, } err: - grub_free (part); grub_free (json_header); grub_json_free (json); return ret; diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h index 282f8ac456..5bd970692f 100644 --- a/include/grub/cryptodisk.h +++ b/include/grub/cryptodisk.h @@ -59,6 +59,7 @@ typedef enum #define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3) #define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES) #define GRUB_CRYPTODISK_MAX_KEYLEN 128 +#define GRUB_CRYPTODISK_MAX_PASSPHRASE 256 struct grub_cryptodisk; -- 2.34.1 ++++++ 0008-cryptodisk-Move-global-variables-into-grub_cryptomou.patch ++++++ >From 5323778d84a7289acba0e50d84fb1afd45fff596 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:57 -0600 Subject: [PATCH 08/14] cryptodisk: Move global variables into grub_cryptomount_args struct Note that cargs.search_uuid does not need to be initialized in various parts of the cryptomount argument parsing, just once when cargs is declared with a struct initializer. The previous code used a global variable which would retain the value across cryptomount invocations. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/cryptodisk.c | 24 +++++++++--------------- grub-core/disk/geli.c | 9 ++++----- grub-core/disk/luks.c | 9 ++++----- grub-core/disk/luks2.c | 8 ++++---- include/grub/cryptodisk.h | 9 +++++++-- 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index d12368a1f7..7ca880402d 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -984,9 +984,6 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk) #endif -static int check_boot; -static char *search_uuid; - static void cryptodisk_close (grub_cryptodisk_t dev) { @@ -1014,7 +1011,7 @@ grub_cryptodisk_scan_device_real (const char *name, FOR_CRYPTODISK_DEVS (cr) { - dev = cr->scan (source, search_uuid, check_boot); + dev = cr->scan (source, cargs); if (grub_errno) return NULL; if (!dev) @@ -1077,6 +1074,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) grub_cryptodisk_t dev; grub_cryptodisk_dev_t cr; grub_disk_t source; + struct grub_cryptomount_args cargs = {0}; /* Try to open disk. */ source = grub_disk_open (sourcedev); @@ -1093,7 +1091,7 @@ grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat) FOR_CRYPTODISK_DEVS (cr) { - dev = cr->scan (source, search_uuid, check_boot); + dev = cr->scan (source, &cargs); if (grub_errno) return grub_errno; if (!dev) @@ -1136,7 +1134,7 @@ grub_cryptodisk_scan_device (const char *name, dev = grub_cryptodisk_scan_device_real (name, source, cargs); if (dev) { - ret = (search_uuid != NULL && grub_strcasecmp (search_uuid, dev->uuid) == 0); + ret = (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, dev->uuid) == 0); goto cleanup; } @@ -1147,7 +1145,7 @@ grub_cryptodisk_scan_device (const char *name, if (grub_errno == GRUB_ERR_BAD_MODULE) grub_error_pop (); - if (search_uuid != NULL) + if (cargs->search_uuid != NULL) /* Push error onto stack to save for cryptomount. */ grub_error_push (); else @@ -1189,10 +1187,9 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) return GRUB_ERR_NONE; } - check_boot = state[2].set; - search_uuid = args[0]; + cargs.check_boot = state[2].set; + cargs.search_uuid = args[0]; found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); - search_uuid = NULL; if (found_uuid) return GRUB_ERR_NONE; @@ -1210,10 +1207,8 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) } else if (state[1].set || (argc == 0 && state[2].set)) /* -a|-b */ { - search_uuid = NULL; - check_boot = state[2].set; + cargs.check_boot = state[2].set; grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); - search_uuid = NULL; return GRUB_ERR_NONE; } else @@ -1224,8 +1219,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) char *disklast = NULL; grub_size_t len; - search_uuid = NULL; - check_boot = state[2].set; + cargs.check_boot = state[2].set; diskname = args[0]; len = grub_strlen (diskname); if (len && diskname[0] == '(' && diskname[len - 1] == ')') diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c index 7299a47d19..23789c43f3 100644 --- a/grub-core/disk/geli.c +++ b/grub-core/disk/geli.c @@ -240,8 +240,7 @@ grub_util_get_geli_uuid (const char *dev) #endif static grub_cryptodisk_t -configure_ciphers (grub_disk_t disk, const char *check_uuid, - int boot_only) +configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) { grub_cryptodisk_t newdev; struct grub_geli_phdr header; @@ -289,7 +288,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, return NULL; } - if (boot_only && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) + if (cargs->check_boot && !(grub_le_to_cpu32 (header.flags) & GRUB_GELI_FLAGS_BOOT)) { grub_dprintf ("geli", "not a boot volume\n"); return NULL; @@ -302,9 +301,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, return NULL; } - if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) + if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) { - grub_dprintf ("geli", "%s != %s\n", uuid, check_uuid); + grub_dprintf ("geli", "%s != %s\n", uuid, cargs->search_uuid); return NULL; } diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c index 39a7af6a43..f0feb38447 100644 --- a/grub-core/disk/luks.c +++ b/grub-core/disk/luks.c @@ -63,8 +63,7 @@ gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, grub_size_t blocknumbers); static grub_cryptodisk_t -configure_ciphers (grub_disk_t disk, const char *check_uuid, - int check_boot) +configure_ciphers (grub_disk_t disk, grub_cryptomount_args_t cargs) { grub_cryptodisk_t newdev; const char *iptr; @@ -76,7 +75,7 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, char hashspec[sizeof (header.hashSpec) + 1]; grub_err_t err; - if (check_boot) + if (cargs->check_boot) return NULL; /* Read the LUKS header. */ @@ -103,9 +102,9 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, } *optr = 0; - if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) + if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) { - grub_dprintf ("luks", "%s != %s\n", uuid, check_uuid); + grub_dprintf ("luks", "%s != %s\n", uuid, cargs->search_uuid); return NULL; } diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c index 09740b53f9..ccfacb63a3 100644 --- a/grub-core/disk/luks2.c +++ b/grub-core/disk/luks2.c @@ -346,14 +346,14 @@ luks2_read_header (grub_disk_t disk, grub_luks2_header_t *outhdr) } static grub_cryptodisk_t -luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) +luks2_scan (grub_disk_t disk, grub_cryptomount_args_t cargs) { grub_cryptodisk_t cryptodisk; grub_luks2_header_t header; char uuid[sizeof (header.uuid) + 1]; grub_size_t i, j; - if (check_boot) + if (cargs->check_boot) return NULL; if (luks2_read_header (disk, &header)) @@ -367,9 +367,9 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int check_boot) uuid[j++] = header.uuid[i]; uuid[j] = '\0'; - if (check_uuid && grub_strcasecmp (check_uuid, uuid) != 0) + if (cargs->search_uuid != NULL && grub_strcasecmp (cargs->search_uuid, uuid) != 0) { - grub_dprintf ("luks2", "%s != %s\n", uuid, check_uuid); + grub_dprintf ("luks2", "%s != %s\n", uuid, cargs->search_uuid); return NULL; } diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h index 5bd970692f..c6524c9ea9 100644 --- a/include/grub/cryptodisk.h +++ b/include/grub/cryptodisk.h @@ -69,7 +69,13 @@ typedef gcry_err_code_t struct grub_cryptomount_args { + /* scan: Flag to indicate that only bootable volumes should be decrypted */ + grub_uint32_t check_boot : 1; + /* scan: Only volumes matching this UUID should be decrpyted */ + char *search_uuid; + /* recover_key: Key data used to decrypt voume */ grub_uint8_t *key_data; + /* recover_key: Length of key_data */ grub_size_t key_len; }; typedef struct grub_cryptomount_args *grub_cryptomount_args_t; @@ -125,8 +131,7 @@ struct grub_cryptodisk_dev struct grub_cryptodisk_dev *next; struct grub_cryptodisk_dev **prev; - grub_cryptodisk_t (*scan) (grub_disk_t disk, const char *check_uuid, - int boot_only); + grub_cryptodisk_t (*scan) (grub_disk_t disk, grub_cryptomount_args_t cargs); grub_err_t (*recover_key) (grub_disk_t disk, grub_cryptodisk_t dev, grub_cryptomount_args_t cargs); }; typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t; -- 2.34.1 ++++++ 0009-cryptodisk-Improve-handling-of-partition-name-in-cry.patch ++++++ >From b1acd971fa648fa3c6f3a54db4fdf45fae02ce54 Mon Sep 17 00:00:00 2001 From: Glenn Washburn <[email protected]> Date: Thu, 9 Dec 2021 11:14:58 -0600 Subject: [PATCH 09/14] cryptodisk: Improve handling of partition name in cryptomount password prompt Call grub_partition_get_name() unconditionally to initialize the part variable. Then part will only be NULL when grub_partition_get_name() errors. Note that when source->partition is NULL, then grub_partition_get_name() returns an allocated empty string. So no comma or partition will be printed, as desired. Signed-off-by: Glenn Washburn <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/disk/cryptodisk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 7ca880402d..497097394f 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1021,11 +1021,10 @@ grub_cryptodisk_scan_device_real (const char *name, { /* Get the passphrase from the user, if no key data. */ askpass = 1; - if (source->partition != NULL) - part = grub_partition_get_name (source->partition); + part = grub_partition_get_name (source->partition); grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, source->partition != NULL ? "," : "", - part != NULL ? part : "", + part != NULL ? part : N_("UNKNOWN"), dev->uuid); grub_free (part); -- 2.34.1 ++++++ 0010-protectors-Add-key-protectors-framework.patch ++++++ >From 2d959549857305d5e4d95a19a0850885f85179d6 Mon Sep 17 00:00:00 2001 From: Hernan Gatta <[email protected]> Date: Tue, 1 Feb 2022 05:02:53 -0800 Subject: [PATCH 10/14] protectors: Add key protectors framework A key protector encapsulates functionality to retrieve an unlocking key for a fully-encrypted disk from a specific source. A key protector module registers itself with the key protectors framework when it is loaded and unregisters when unloaded. Additionally, a key protector may accept parameters that describe how it should operate. The key protectors framework, besides offering registration and unregistration functions, also offers a one-stop routine for finding and invoking a key protector by name. If a key protector with the specified name exists and if an unlocking key is successfully retrieved by it, the function returns to the caller the retrieved key and its length. Signed-off-by: Hernan Gatta <[email protected]> --- grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 1 + grub-core/kern/protectors.c | 75 +++++++++++++++++++++++++++++++++++++ include/grub/protector.h | 48 ++++++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 grub-core/kern/protectors.c create mode 100644 include/grub/protector.h diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index de241f0d04..dc07ba6f87 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -90,6 +90,7 @@ endif KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h +KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/protector.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index f3140815b8..b0001a33cf 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -138,6 +138,7 @@ kernel = { common = kern/misc.c; common = kern/parser.c; common = kern/partition.c; + common = kern/protectors.c; common = kern/rescue_parser.c; common = kern/rescue_reader.c; common = kern/term.c; diff --git a/grub-core/kern/protectors.c b/grub-core/kern/protectors.c new file mode 100644 index 0000000000..21954dfa48 --- /dev/null +++ b/grub-core/kern/protectors.c @@ -0,0 +1,75 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2022 Microsoft Corporation + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/list.h> +#include <grub/misc.h> +#include <grub/mm.h> +#include <grub/protector.h> + +struct grub_key_protector *grub_key_protectors = NULL; + +grub_err_t +grub_key_protector_register (struct grub_key_protector *protector) +{ + if (!protector || !protector->name || !grub_strlen(protector->name)) + return GRUB_ERR_BAD_ARGUMENT; + + if (grub_key_protectors && + grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), + protector->name)) + return GRUB_ERR_BAD_ARGUMENT; + + grub_list_push (GRUB_AS_LIST_P (&grub_key_protectors), + GRUB_AS_LIST (protector)); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_key_protector_unregister (struct grub_key_protector *protector) +{ + if (!protector) + return GRUB_ERR_BAD_ARGUMENT; + + grub_list_remove (GRUB_AS_LIST (protector)); + + return GRUB_ERR_NONE; +} + +grub_err_t +grub_key_protector_recover_key (const char *protector, grub_uint8_t **key, + grub_size_t *key_size) +{ + struct grub_key_protector *kp = NULL; + + if (!grub_key_protectors) + return GRUB_ERR_OUT_OF_RANGE; + + if (!protector || !grub_strlen (protector)) + return GRUB_ERR_BAD_ARGUMENT; + + kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), + protector); + if (!kp) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + N_("A key protector with name '%s' could not be found. " + "Is the name spelled correctly and is the " + "corresponding module loaded?"), protector); + + return kp->recover_key (key, key_size); +} diff --git a/include/grub/protector.h b/include/grub/protector.h new file mode 100644 index 0000000000..179020a344 --- /dev/null +++ b/include/grub/protector.h @@ -0,0 +1,48 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2022 Microsoft Corporation + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef GRUB_PROTECTOR_HEADER +#define GRUB_PROTECTOR_HEADER 1 + +#include <grub/err.h> +#include <grub/types.h> + +struct grub_key_protector +{ + struct grub_key_protector *next; + struct grub_key_protector **prev; + + const char *name; + + grub_err_t (*recover_key) (grub_uint8_t **key, grub_size_t *key_size); +}; + +extern struct grub_key_protector *EXPORT_VAR (grub_key_protectors); + +grub_err_t +EXPORT_FUNC (grub_key_protector_register) (struct grub_key_protector *protector); + +grub_err_t +EXPORT_FUNC (grub_key_protector_unregister) (struct grub_key_protector *protector); + +grub_err_t +EXPORT_FUNC (grub_key_protector_recover_key) (const char *protector, + grub_uint8_t **key, + grub_size_t *key_size); + +#endif /* ! GRUB_PROTECTOR_HEADER */ -- 2.34.1 ++++++ 0011-tpm2-Add-TPM-Software-Stack-TSS.patch ++++++ ++++ 3524 lines (skipped) ++++++ 0012-protectors-Add-TPM2-Key-Protector.patch ++++++ ++++ 978 lines (skipped) ++++++ 0013-cryptodisk-Support-key-protectors.patch ++++++ >From 9888bf40d960339a59dc18fb6e1df5f65b4668e3 Mon Sep 17 00:00:00 2001 From: Hernan Gatta <[email protected]> Date: Tue, 1 Feb 2022 05:02:56 -0800 Subject: [PATCH 13/14] cryptodisk: Support key protectors Add a new parameter to cryptomount to support the key protectors framework: -k. The parameter is used to automatically retrieve a key from specified key protectors. The parameter may be repeated to specify any number of key protectors. These are tried in order until one provides a usable key for any given disk. Signed-off-by: <Hernan Gatta [email protected]> --- Makefile.util.def | 1 + grub-core/disk/cryptodisk.c | 166 +++++++++++++++++++++++++++++------- include/grub/cryptodisk.h | 14 +++ 3 files changed, 151 insertions(+), 30 deletions(-) diff --git a/Makefile.util.def b/Makefile.util.def index ef5c818e0e..b3ec2a4bb6 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -35,6 +35,7 @@ library = { common = grub-core/kern/list.c; common = grub-core/kern/misc.c; common = grub-core/kern/partition.c; + common = grub-core/kern/protectors.c; common = grub-core/lib/crypto.c; common = grub-core/lib/json/json.c; common = grub-core/disk/luks.c; diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 497097394f..00c44773fb 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -26,6 +26,7 @@ #include <grub/file.h> #include <grub/procfs.h> #include <grub/partition.h> +#include <grub/protector.h> #ifdef GRUB_UTIL #include <grub/emu/hostdisk.h> @@ -42,6 +43,8 @@ static const struct grub_arg_option options[] = {"all", 'a', 0, N_("Mount all."), 0, 0}, {"boot", 'b', 0, N_("Mount all volumes with `boot' flag set."), 0, 0}, {"password", 'p', 0, N_("Password to open volumes."), 0, ARG_TYPE_STRING}, + {"protector", 'k', GRUB_ARG_OPTION_REPEATABLE, + N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING}, {0, 0, 0, 0, 0, 0} }; @@ -1000,7 +1003,8 @@ grub_cryptodisk_scan_device_real (const char *name, { grub_err_t ret = GRUB_ERR_NONE; grub_cryptodisk_t dev; - grub_cryptodisk_dev_t cr; + grub_cryptodisk_dev_t cr, crd = NULL; + int i; int askpass = 0; char *part = NULL; @@ -1016,39 +1020,108 @@ grub_cryptodisk_scan_device_real (const char *name, return NULL; if (!dev) continue; + crd = cr; + } - if (!cargs->key_len) - { - /* Get the passphrase from the user, if no key data. */ - askpass = 1; - part = grub_partition_get_name (source->partition); - grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, - source->partition != NULL ? "," : "", - part != NULL ? part : N_("UNKNOWN"), - dev->uuid); - grub_free (part); - - cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); - if (cargs->key_data == NULL) - return NULL; - - if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) - { - grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); - goto error; - } - cargs->key_len = grub_strlen ((char *) cargs->key_data); - } + if (!dev) + { + grub_error (GRUB_ERR_BAD_MODULE, + "no cryptodisk module can handle this device"); + return NULL; + } - ret = cr->recover_key (source, dev, cargs); - if (ret != GRUB_ERR_NONE) + if (cargs->protectors) + { + for (i = 0; cargs->protectors[i]; i++) + { + if (cargs->key_cache[i].invalid) + continue; + + if (!cargs->key_cache[i].key) + { + ret = grub_key_protector_recover_key (cargs->protectors[i], + &cargs->key_cache[i].key, + &cargs->key_cache[i].key_len); + if (ret) + { + if (grub_errno) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + } + + grub_dprintf ("cryptodisk", + "failed to recover a key from key protector " + "%s, will not try it again for any other " + "disks, if any, during this invocation of " + "cryptomount\n", + cargs->protectors[i]); + + cargs->key_cache[i].invalid = 1; + continue; + } + } + + cargs->key_data = cargs->key_cache[i].key; + cargs->key_len = cargs->key_cache[i].key_len; + + ret = crd->recover_key (source, dev, cargs); + if (ret) + { + part = grub_partition_get_name (source->partition); + grub_dprintf ("cryptodisk", + "recovered a key from key protector %s but it " + "failed to unlock %s%s%s (%s)\n", + cargs->protectors[i], source->name, + source->partition != NULL ? "," : "", + part != NULL ? part : N_("UNKNOWN"), dev->uuid); + grub_free (part); + continue; + } + else + { + grub_cryptodisk_insert (dev, name, source); + goto cleanup; + }; + } + + part = grub_partition_get_name (source->partition); + grub_error (GRUB_ERR_ACCESS_DENIED, + N_("no key protector provided a usable key for %s%s%s (%s)"), + source->name, source->partition != NULL ? "," : "", + part != NULL ? part : N_("UNKNOWN"), dev->uuid); + grub_free (part); goto error; + } - grub_cryptodisk_insert (dev, name, source); + if (!cargs->key_len) + { + /* Get the passphrase from the user, if no key data. */ + askpass = 1; + part = grub_partition_get_name (source->partition); + grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name, + source->partition != NULL ? "," : "", + part != NULL ? part : N_("UNKNOWN"), dev->uuid); + grub_free (part); + + cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE); + if (cargs->key_data == NULL) + goto error; + + if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE)) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied"); + goto error; + } + cargs->key_len = grub_strlen ((char *) cargs->key_data); + } + + ret = crd->recover_key (source, dev, cargs); + if (ret != GRUB_ERR_NONE) + goto error; + + grub_cryptodisk_insert (dev, name, source); - goto cleanup; - } - grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device"); goto cleanup; error: @@ -1155,6 +1228,20 @@ grub_cryptodisk_scan_device (const char *name, return ret; } +static void +grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs) +{ + int i; + + if (!cargs->key_cache) + return; + + for (i = 0; cargs->protectors[i]; i++) + grub_free (cargs->key_cache[i].key); + + grub_free (cargs->key_cache); +} + static grub_err_t grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) { @@ -1167,12 +1254,25 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) if (grub_cryptodisk_list == NULL) return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded"); + if (state[3].set && state[4].set) /* password and key protector */ + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "a password and a key protector cannot both be set"); + if (state[3].set) /* password */ { cargs.key_data = (grub_uint8_t *) state[3].arg; cargs.key_len = grub_strlen (state[3].arg); } + if (state[4].set) /* key protector(s) */ + { + cargs.key_cache = grub_zalloc (state[4].set * sizeof (*cargs.key_cache)); + if (!cargs.key_cache) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "no memory for key protector key cache"); + cargs.protectors = state[4].args; + } + if (state[0].set) /* uuid */ { int found_uuid; @@ -1181,6 +1281,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) dev = grub_cryptodisk_get_by_uuid (args[0]); if (dev) { + grub_cryptodisk_clear_key_cache (&cargs); grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id); return GRUB_ERR_NONE; @@ -1189,6 +1290,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) cargs.check_boot = state[2].set; cargs.search_uuid = args[0]; found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + grub_cryptodisk_clear_key_cache (&cargs); if (found_uuid) return GRUB_ERR_NONE; @@ -1208,6 +1310,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) { cargs.check_boot = state[2].set; grub_device_iterate (&grub_cryptodisk_scan_device, &cargs); + grub_cryptodisk_clear_key_cache (&cargs); return GRUB_ERR_NONE; } else @@ -1231,6 +1334,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) disk = grub_disk_open (diskname); if (!disk) { + grub_cryptodisk_clear_key_cache (&cargs); if (disklast) *disklast = ')'; return grub_errno; @@ -1241,12 +1345,14 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args) { grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id); grub_disk_close (disk); + grub_cryptodisk_clear_key_cache (&cargs); if (disklast) *disklast = ')'; return GRUB_ERR_NONE; } dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs); + grub_cryptodisk_clear_key_cache (&cargs); grub_disk_close (disk); if (disklast) @@ -1385,7 +1491,7 @@ GRUB_MOD_INIT (cryptodisk) { grub_disk_dev_register (&grub_cryptodisk_dev); cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0, - N_("[-p password] <SOURCE|-u UUID|-a|-b>"), + N_("[-p password] [-k protector [-k protector ...]] <SOURCE|-u UUID|-a|-b>"), N_("Mount a crypto device."), options); grub_procfs_register ("luks_script", &luks_script); } diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h index c6524c9ea9..b556498fba 100644 --- a/include/grub/cryptodisk.h +++ b/include/grub/cryptodisk.h @@ -67,6 +67,16 @@ typedef gcry_err_code_t (*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev, grub_uint64_t zoneno); +struct grub_cryptomount_cached_key +{ + grub_uint8_t *key; + grub_size_t key_len; + + /* The key protector associated with this cache entry failed, so avoid it + * even if the cached entry (an instance of this structure) is empty. */ + int invalid; +}; + struct grub_cryptomount_args { /* scan: Flag to indicate that only bootable volumes should be decrypted */ @@ -77,6 +87,10 @@ struct grub_cryptomount_args grub_uint8_t *key_data; /* recover_key: Length of key_data */ grub_size_t key_len; + /* recover_key: Names of the key protectors to use (NULL-terminated) */ + char **protectors; + /* recover_key: Key cache to avoid invoking the same key protector twice */ + struct grub_cryptomount_cached_key *key_cache; }; typedef struct grub_cryptomount_args *grub_cryptomount_args_t; -- 2.34.1 ++++++ 0014-util-grub-protect-Add-new-tool.patch ++++++ ++++ 1409 lines (skipped) ++++++ fix-tpm2-build.patch ++++++ --- grub-core/Makefile.core.def | 1 + grub-core/tpm2/module.c | 2 +- util/grub-protect.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -2569,6 +2569,7 @@ common = tpm2/mu.c; common = tpm2/tpm2.c; efi = tpm2/tcg2.c; + enable = efi; }; module = { --- a/util/grub-protect.c +++ b/util/grub-protect.c @@ -542,7 +542,7 @@ if (pcr_values.digests[i].size != pcr_digest_len) { fprintf (stderr, - _("Bad PCR value size: expected %lu bytes but got %u bytes.\n"), + _("Bad PCR value size: expected %" PRIuGRUB_SIZE " bytes but got %u bytes.\n"), pcr_digest_len, pcr_values.digests[i].size); goto exit2; } --- a/grub-core/tpm2/module.c +++ b/grub-core/tpm2/module.c @@ -195,7 +195,7 @@ if (sealed_key_size > buf.cap) { grub_dprintf ("tpm2", "Sealed key file is larger than decode buffer " - "(%lu vs %lu bytes).\n", sealed_key_size, buf.cap); + "(%" PRIuGRUB_SIZE " vs %" PRIuGRUB_SIZE " bytes).\n", sealed_key_size, buf.cap); return GRUB_ERR_BAD_ARGUMENT; }
