grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] cryptodisk: add luks_recover_key attempts


From: Jason Kushmaul
Subject: [PATCH] cryptodisk: add luks_recover_key attempts
Date: Sat, 29 Jun 2019 21:44:51 -0400

Add a configurable option for luks key recovery.  Existing
users will continue to have the default of 1 attempt.

Cryptodisk is not accessible to motor impaired individuals
who may need the extra attempts without having to reboot or
manually rescue only to be asked again.

Reported-by: Jason J. Kushmaul <address@hidden>
---
 docs/grub.texi                   | 10 +++++++--
 grub-core/disk/cryptodisk.c      | 24 +++++++++++++++++++---
 grub-core/disk/luks.c            | 35 +++++++++++++++++++++++++-------
 grub-core/osdep/aros/config.c    | 16 +++++++++++++++
 grub-core/osdep/unix/config.c    | 20 ++++++++++++++++--
 grub-core/osdep/windows/config.c | 16 +++++++++++++++
 include/grub/emu/config.h        |  1 +
 util/config.c                    | 14 +++++++++++++
 util/grub-install.c              | 12 +++++------
 9 files changed, 128 insertions(+), 20 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 308b25074..00df49fa1 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -1508,6 +1508,11 @@ check for encrypted disks and generate additional commands needed to access
 them during boot.  Note that in this case unattended boot is not possible
 because GRUB will wait for passphrase to unlock encrypted container.
 
+@item GRUB_CRYPTODISK_ATTEMPTS
+If set, @command{grub-install} will allow the provided number of attempts
+on key recovery.  The default if not present, or outside of [1,256] is 1.
+Currently only supported for LUKS.
+
 @item GRUB_INIT_TUNE
 Play a tune on the speaker when GRUB starts.  This is particularly useful
 for users unable to see the screen.  The value of this option is passed
@@ -4194,12 +4199,13 @@ 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}
+@deffn Command cryptomount [@option{-t} tries] 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
 (@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.
+devices; option @option{-b} configures all geli containers that have boot flag set;
+option @option{-t}, luks only, configures passphrase retry attempts, defaulting to 1.
 
 GRUB suports devices encrypted using LUKS and geli. Note that necessary modules (@var{luks} and @var{geli}) have to be loaded manually before this command can
 be used.
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 5037768fc..3b90e550e 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},
+    {"tries", 't', 0, N_("Max passphrase attempts."), 0, GRUB_KEY_ARG},
     {0, 0, 0, 0, 0, 0}
   };
 
@@ -807,6 +808,7 @@ grub_util_cryptodisk_get_uuid (grub_disk_t disk)
 
 #endif
 
+unsigned max_attempts;
 static int check_boot, have_it;
 static char *search_uuid;
 
@@ -820,7 +822,7 @@ cryptodisk_close (grub_cryptodisk_t dev)
 }
 
 static grub_err_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_err_t err;
   grub_cryptodisk_t dev;
@@ -933,7 +935,23 @@ 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");
-
+  
+  /* Default to original behavior of 1 attempt */
+  max_attempts = 1;
+  if (state[3].set)
+  {
+      const char *max_attempts_str = state[3].arg;
+      if (max_attempts_str)
+      {
+          char *end = NULL;
+          long  tmpl = grub_strtol (max_attempts_str, &end, 10);
+          if (tmpl > 0 && tmpl <= 256)
+          {
+              max_attempts = (unsigned) tmpl;
+          }
+      }
+  }
+  
   have_it = 0;
   if (state[0].set)
     {
@@ -1141,7 +1159,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_("[-t] SOURCE|-u UUID|-a|-b"),
       N_("Mount a crypto device."), options);
   grub_procfs_register ("luks_script", &luks_script);
 }
diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c
index 86c50c612..02b999f07 100644
--- a/grub-core/disk/luks.c
+++ b/grub-core/disk/luks.c
@@ -308,10 +308,10 @@ 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)
+luks_recover_key_attempt (grub_disk_t source,
+                          grub_cryptodisk_t dev,
+                          struct grub_luks_phdr header)
 {
-  struct grub_luks_phdr header;
   grub_size_t keysize;
   grub_uint8_t *split_key = NULL;
   char passphrase[MAX_PASSPHRASE] = "";
@@ -322,10 +322,6 @@ luks_recover_key (grub_disk_t source,
   grub_size_t max_stripes = 1;
   char *tmp;
 
-  err = grub_disk_read (source, 0, 0, sizeof (header), &header);
-  if (err)
-    return err;
-
   grub_puts_ (N_("Attempting to decrypt master key..."));
   keysize = grub_be_to_cpu32 (header.keyBytes);
   if (keysize > GRUB_CRYPTODISK_MAX_KEYLEN)
@@ -467,6 +463,31 @@ luks_recover_key (grub_disk_t source,
   return GRUB_ACCESS_DENIED;
 }
 
+
+extern unsigned max_attempts;
+static grub_err_t
+luks_recover_key (grub_disk_t source,
+                  grub_cryptodisk_t dev)
+{
+    grub_err_t err;
+    struct grub_luks_phdr header;
+    err = grub_disk_read (source, 0, 0, sizeof (header), &header);
+    if (err)
+        return err;
+    
+    if (!max_attempts || max_attempts > 256)
+      max_attempts = 1;
+    err = GRUB_ERR_FILE_NOT_FOUND;
+    for (unsigned attempt = 0; attempt < max_attempts; attempt++)
+    {
+        grub_errno = GRUB_ERR_NONE;
+        err = luks_recover_key_attempt(source, dev, header);
+        if (err != GRUB_ERR_ACCESS_DENIED)
+            break;
+    }
+    return err;
+}
+
 struct grub_cryptodisk_dev luks_crypto = {
   .scan = configure_ciphers,
   .recover_key = luks_recover_key
diff --git a/grub-core/osdep/aros/config.c b/grub-core/osdep/aros/config.c
index c82d0ea8e..683823233 100644
--- a/grub-core/osdep/aros/config.c
+++ b/grub-core/osdep/aros/config.c
@@ -73,6 +73,22 @@ grub_util_load_config (struct grub_util_config *cfg)
   v = getenv ("GRUB_ENABLE_CRYPTODISK");
   if (v && v[0] == 'y' && v[1] == '\0')
     cfg->is_cryptodisk_enabled = 1;
+  
+  cfg->cryptodisk_attempts = 1;
+  v = getenv("GRUB_CRYPTODISK_ATTEMPTS");
+  if (v)
+    {
+      char *end = NULL;
+      long attempts = grub_strtol(v, &end, 10);
+      if (attempts > 0 && attempts <= 256)
+        {
+          cfg->cryptodisk_attempts = (unsigned) attempts;
+        }
+      else
+        {
+          grub_util_warn (_("grub_util_load_config: GRUB_CRYPTODISK_ATTEMPTS must be postive and less than 256"));
+        }
+    }
 
   v = getenv ("GRUB_DISTRIBUTOR");
   if (v)
diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
index 65effa9f3..3cf0f21c6 100644
--- a/grub-core/osdep/unix/config.c
+++ b/grub-core/osdep/unix/config.c
@@ -78,6 +78,22 @@ grub_util_load_config (struct grub_util_config *cfg)
   if (v && v[0] == 'y' && v[1] == '\0')
     cfg->is_cryptodisk_enabled = 1;
 
+  cfg->cryptodisk_attempts = 1;
+  v = getenv("GRUB_CRYPTODISK_ATTEMPTS");
+  if (v)
+  {
+      char *end = NULL;
+      long attempts = grub_strtol(v, &end, 10);
+      if (attempts > 0 && attempts <= 256)
+      {
+          cfg->cryptodisk_attempts = (unsigned) attempts;
+      }
+      else
+      {
+          grub_util_warn (_("grub_util_load_config: GRUB_CRYPTODISK_ATTEMPTS must be postive and less than 256"));
+      }
+  }
+
   v = getenv ("GRUB_DISTRIBUTOR");
   if (v)
     cfg->grub_distributor = xstrdup (v);
@@ -105,8 +121,8 @@ grub_util_load_config (struct grub_util_config *cfg)
       *ptr++ = *iptr;
     }
 
-  strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
-  "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\"");
+  strcpy (ptr, "'; printf \"GRUB_CRYPTODISK_ATTEMPTS=%s\\nGRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
+  "\"$GRUB_CRYPTODISK_ATTEMPTS\" \"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\"");
 
   argv[2] = script;
   argv[3] = '\0';
diff --git a/grub-core/osdep/windows/config.c b/grub-core/osdep/windows/config.c
index 928ab1a49..2e3808f22 100644
--- a/grub-core/osdep/windows/config.c
+++ b/grub-core/osdep/windows/config.c
@@ -41,6 +41,22 @@ grub_util_load_config (struct grub_util_config *cfg)
   if (v && v[0] == 'y' && v[1] == '\0')
     cfg->is_cryptodisk_enabled = 1;
 
+  cfg->cryptodisk_attempts = 1;
+  v = getenv("GRUB_CRYPTODISK_ATTEMPTS");
+  if (v)
+  {
+      char *end = NULL;
+      long attempts = grub_strtol(v, &end, 10);
+      if (attempts > 0 && attempts <= 256)
+      {
+          cfg->cryptodisk_attempts = (unsigned) attempts;
+      }
+      else
+      {
+          grub_util_warn (_("grub_util_load_config: GRUB_CRYPTODISK_ATTEMPTS must be postive and less than 256"));
+      }
+  }
+
   v = getenv ("GRUB_DISTRIBUTOR");
   if (v)
     cfg->grub_distributor = xstrdup (v);
diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h
index 875d5896c..fd4cb9e33 100644
--- a/include/grub/emu/config.h
+++ b/include/grub/emu/config.h
@@ -36,6 +36,7 @@ grub_util_get_localedir (void);
 struct grub_util_config
 {
   int is_cryptodisk_enabled;
+  unsigned cryptodisk_attempts;
   char *grub_distributor;
 };
 
diff --git a/util/config.c b/util/config.c
index ebcdd8f5e..9d460712c 100644
--- a/util/config.c
+++ b/util/config.c
@@ -32,6 +32,20 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple)
     {
       const char *ptr;
       for (ptr = buffer; *ptr && grub_isspace (*ptr); ptr++);
+        if (grub_strncmp (ptr, "GRUB_CRYPTODISK_ATTEMPTS=",
+            sizeof ("GRUB_CRYPTODISK_ATTEMPTS=") - 1) == 0)
+          {
+            ptr += sizeof ("GRUB_CRYPTODISK_ATTEMPTS=") - 1;
+            char *end = NULL;
+            long tmpl = strtol(ptr, &end, 10);
+            if (!tmpl || tmpl > 256) {
+                grub_util_warn (_("grub_util_parse_config: GRUB_CRYPTODISK_ATTEMPTS was out of range=%ld, defaulting to 1"), tmpl);
+                cfg->cryptodisk_attempts = 1;
+            }
+            cfg->cryptodisk_attempts = tmpl;
+            continue;
+          }
+
       if (grub_strncmp (ptr, "GRUB_ENABLE_CRYPTODISK=",
  sizeof ("GRUB_ENABLE_CRYPTODISK=") - 1) == 0)
  {
diff --git a/util/grub-install.c b/util/grub-install.c
index 8a55ad4b8..081fcc446 100644
--- a/util/grub-install.c
+++ b/util/grub-install.c
@@ -509,7 +509,7 @@ have_bootdev (enum grub_install_plat pl)
 }
 
 static void
-probe_cryptodisk_uuid (grub_disk_t disk)
+probe_cryptodisk_uuid (grub_disk_t disk, unsigned attempts)
 {
   grub_disk_memberlist_t list = NULL, tmp;
 
@@ -520,7 +520,7 @@ probe_cryptodisk_uuid (grub_disk_t disk)
     }
   while (list)
     {
-      probe_cryptodisk_uuid (list->disk);
+      probe_cryptodisk_uuid (list->disk, attempts);
       tmp = list->next;
       free (list);
       list = tmp;
@@ -532,8 +532,8 @@ probe_cryptodisk_uuid (grub_disk_t disk)
  load_cfg_f = grub_util_fopen (load_cfg, "wb");
       have_load_cfg = 1;
 
-      fprintf (load_cfg_f, "cryptomount -u %s\n",
-      uuid);
+      fprintf (load_cfg_f, "cryptomount -u %s -t %u\n",
+               uuid, attempts);
     }
 }
 
@@ -1531,7 +1531,7 @@ main (int argc, char *argv[])
       if (config.is_cryptodisk_enabled)
  {
   if (grub_dev->disk)
-    probe_cryptodisk_uuid (grub_dev->disk);
+    probe_cryptodisk_uuid (grub_dev->disk, config.cryptodisk_attempts);
 
   for (curdrive = grub_drives + 1; *curdrive; curdrive++)
     {
@@ -1539,7 +1539,7 @@ main (int argc, char *argv[])
       if (!dev)
  continue;
       if (dev->disk)
- probe_cryptodisk_uuid (dev->disk);
+ probe_cryptodisk_uuid (dev->disk, config.cryptodisk_attempts);
       grub_device_close (dev);
     }
  }
--
2.20.1

reply via email to

[Prev in Thread] Current Thread [Next in Thread]