Re: [PATCH v11 12/20] cryptodisk: Support key protectors

2024-04-12 Thread Stefan Berger



On 4/12/24 04:39, Gary Lin via Grub-devel wrote:

From: Hernan Gatta 

Add a new parameter to cryptomount to support the key protectors framework: -P.
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 
Signed-off-by: Michael Chang 
Signed-off-by: Gary Lin 
Reviewed-by: Glenn Washburn 
---
  Makefile.util.def   |   1 +
  grub-core/disk/cryptodisk.c | 172 +---
  include/grub/cryptodisk.h   |  16 
  3 files changed, 158 insertions(+), 31 deletions(-)

diff --git a/Makefile.util.def b/Makefile.util.def
index b53afb1d3..19ad5a96f 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -40,6 +40,7 @@ library = {
common = grub-core/disk/luks.c;
common = grub-core/disk/luks2.c;
common = grub-core/disk/geli.c;
+  common = grub-core/disk/key_protector.c;
common = grub-core/disk/cryptodisk.c;
common = grub-core/disk/AFSplitter.c;
common = grub-core/lib/pbkdf2.c;
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 2246af51b..0ca1a5c4d 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -26,6 +26,7 @@
  #include 
  #include 
  #include 
+#include 
  
  #ifdef GRUB_UTIL

  #include 
@@ -44,7 +45,8 @@ enum
  OPTION_KEYFILE,
  OPTION_KEYFILE_OFFSET,
  OPTION_KEYFILE_SIZE,
-OPTION_HEADER
+OPTION_HEADER,
+OPTION_PROTECTOR
};
  
  static const struct grub_arg_option options[] =

@@ -58,6 +60,8 @@ static const struct grub_arg_option options[] =
  {"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, 
ARG_TYPE_INT},
  {"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, 
ARG_TYPE_INT},
  {"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING},
+{"protector", 'P', GRUB_ARG_OPTION_REPEATABLE,
+ N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING},
  {0, 0, 0, 0, 0, 0}
};
  
@@ -1061,6 +1065,7 @@ grub_cryptodisk_scan_device_real (const char *name,

grub_err_t ret = GRUB_ERR_NONE;
grub_cryptodisk_t dev;
grub_cryptodisk_dev_t cr;
+  int i;
struct cryptodisk_read_hook_ctx read_hook_data = {0};
int askpass = 0;
char *part = NULL;
@@ -1113,41 +1118,112 @@ grub_cryptodisk_scan_device_real (const char *name,
goto error_no_close;
  if (!dev)
continue;
+break;
+  }
  
-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_no_close;
-
-   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 == NULL)
+{
+  grub_error (GRUB_ERR_BAD_MODULE,
+ "no cryptodisk module can handle this device");
+  goto error_no_close;
+}
  
-ret = cr->recover_key (source, dev, cargs);

-if (ret != GRUB_ERR_NONE)
-  goto error;
+  if (cargs->protectors)
+{
+  for (i = 0; cargs->protectors[i]; i++)
+   {
+ if (cargs->key_cache[i].invalid)
+   continue;
+
+ if (cargs->key_cache[i].key == NULL)
+   {
+ ret = grub_key_protector_recover_key (cargs->protectors[i],
+   >key_cache[i].key,
+   
>key_cache[i].key_len);
+ if (ret != GRUB_ERR_NONE)
+   {
+ 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 = 

[PATCH v11 12/20] cryptodisk: Support key protectors

2024-04-12 Thread Gary Lin via Grub-devel
From: Hernan Gatta 

Add a new parameter to cryptomount to support the key protectors framework: -P.
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 
Signed-off-by: Michael Chang 
Signed-off-by: Gary Lin 
Reviewed-by: Glenn Washburn 
---
 Makefile.util.def   |   1 +
 grub-core/disk/cryptodisk.c | 172 +---
 include/grub/cryptodisk.h   |  16 
 3 files changed, 158 insertions(+), 31 deletions(-)

diff --git a/Makefile.util.def b/Makefile.util.def
index b53afb1d3..19ad5a96f 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -40,6 +40,7 @@ library = {
   common = grub-core/disk/luks.c;
   common = grub-core/disk/luks2.c;
   common = grub-core/disk/geli.c;
+  common = grub-core/disk/key_protector.c;
   common = grub-core/disk/cryptodisk.c;
   common = grub-core/disk/AFSplitter.c;
   common = grub-core/lib/pbkdf2.c;
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 2246af51b..0ca1a5c4d 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #ifdef GRUB_UTIL
 #include 
@@ -44,7 +45,8 @@ enum
 OPTION_KEYFILE,
 OPTION_KEYFILE_OFFSET,
 OPTION_KEYFILE_SIZE,
-OPTION_HEADER
+OPTION_HEADER,
+OPTION_PROTECTOR
   };
 
 static const struct grub_arg_option options[] =
@@ -58,6 +60,8 @@ static const struct grub_arg_option options[] =
 {"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT},
 {"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, 
ARG_TYPE_INT},
 {"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING},
+{"protector", 'P', GRUB_ARG_OPTION_REPEATABLE,
+ N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING},
 {0, 0, 0, 0, 0, 0}
   };
 
@@ -1061,6 +1065,7 @@ grub_cryptodisk_scan_device_real (const char *name,
   grub_err_t ret = GRUB_ERR_NONE;
   grub_cryptodisk_t dev;
   grub_cryptodisk_dev_t cr;
+  int i;
   struct cryptodisk_read_hook_ctx read_hook_data = {0};
   int askpass = 0;
   char *part = NULL;
@@ -1113,41 +1118,112 @@ grub_cryptodisk_scan_device_real (const char *name,
   goto error_no_close;
 if (!dev)
   continue;
+break;
+  }
 
-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_no_close;
-
-   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 == NULL)
+{
+  grub_error (GRUB_ERR_BAD_MODULE,
+ "no cryptodisk module can handle this device");
+  goto error_no_close;
+}
 
-ret = cr->recover_key (source, dev, cargs);
-if (ret != GRUB_ERR_NONE)
-  goto error;
+  if (cargs->protectors)
+{
+  for (i = 0; cargs->protectors[i]; i++)
+   {
+ if (cargs->key_cache[i].invalid)
+   continue;
+
+ if (cargs->key_cache[i].key == NULL)
+   {
+ ret = grub_key_protector_recover_key (cargs->protectors[i],
+   >key_cache[i].key,
+   
>key_cache[i].key_len);
+ if (ret != GRUB_ERR_NONE)
+   {
+ 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 = grub_cryptodisk_insert (dev, name, source);
-if (ret != GRUB_ERR_NONE)
+ ret = cr->recover_key (source,