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;
     }
 

Reply via email to