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 option


From: Jason Kushmaul
Subject: [PATCH] cryptodisk: add luks_recover_key attempts option
Date: Fri, 4 Oct 2019 21:11:09 -0400

Hello,

Daniel or other reviewer,

I was hoping to get a review for my accessibility patch offering motor
impaired individuals more access to full disk encrypted disks, by
allowing a configurable retry option.

I've addressed the review items from before from Daniel

>From d135f9f6b7d1503f551e8cced9ffe43a30af31d3 Mon Sep 17 00:00:00 2001
From: "Jason J. Kushmaul" <address@hidden>
Date: Sat, 20 Jul 2019 17:03:01 -0400
Subject: [PATCH] cryptodisk: add luks_recover_key attempts option

Those with motor impairments have a barrier preventing
them from enjoying LUKS full disk encryption with
strong passphrases due to no retry behavior.

This patch adds an accessibility configuration where
one may configure an arbitrary number of attempts
via the "-t" option.

Existing users will observe the original behavior
with a default of 1 attempt.

Reported-by: Jason J. Kushmaul <address@hidden>
Signed-off-by: Daniel Kiper <address@hidden>
---
 docs/grub.texi                   | 10 +++++++--
 grub-core/disk/cryptodisk.c      | 18 ++++++++++++++--
 grub-core/disk/luks.c            | 36 +++++++++++++++++++++++++-------
 grub-core/osdep/aros/config.c    |  2 ++
 grub-core/osdep/unix/config.c    |  6 ++++--
 grub-core/osdep/windows/config.c |  2 ++
 include/grub/cryptodisk.h        |  1 +
 include/grub/emu/config.h        |  1 +
 include/grub/util/misc.h         |  2 ++
 util/config.c                    | 29 +++++++++++++++++++++++++
 util/grub-install.c              | 12 +++++------
 11 files changed, 100 insertions(+), 19 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 3d50b16ba..01dc1114c 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 zero is 1 to match original
+behavior.  Currently only support with LUKS cryptodisks.
+
 @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
@@ -4195,12 +4200,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..a3f0fa44d 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -33,6 +33,7 @@

 GRUB_MOD_LICENSE ("GPLv3+");

+unsigned long max_attempts;
 grub_cryptodisk_dev_t grub_cryptodisk_list;

 static const struct grub_arg_option options[] =
@@ -41,6 +42,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}
   };

@@ -934,6 +936,18 @@ 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)
+        max_attempts = grub_strtoul (max_attempts_str, NULL, 10);
+    }
+
+  if (max_attempts == 0)
+    max_attempts = 1;
+
   have_it = 0;
   if (state[0].set)
     {
@@ -1141,8 +1155,8 @@ 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_("Mount a crypto device."), options);
+                              N_("[-t TRIES]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..b7c9d72ec 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,32 @@ luks_recover_key (grub_disk_t source,
   return GRUB_ACCESS_DENIED;
 }

+static grub_err_t
+luks_recover_key (grub_disk_t source,
+                  grub_cryptodisk_t dev)
+{
+    grub_err_t err;
+    struct grub_luks_phdr header;
+    unsigned long i;
+
+    err = grub_disk_read (source, 0, 0, sizeof (header), &header);
+    if (err)
+        return err;
+
+    err = GRUB_ERR_FILE_NOT_FOUND;
+    for (i  = 0; i < max_attempts; i++)
+      {
+        /* clear last failed attempt which assigns
+            grub_errno = GRUB_ERR_ACCESS_DENIED.
+           if the last attempt fails, grub_errno is not reset. */
+        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..2bd23951e 100644
--- a/grub-core/osdep/aros/config.c
+++ b/grub-core/osdep/aros/config.c
@@ -74,6 +74,8 @@ 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 =
grub_util_strtoul_with_default(getenv("GRUB_CRYPTODISK_ATTEMPTS"), 1);
+
   v = getenv ("GRUB_DISTRIBUTOR");
   if (v)
     cfg->grub_distributor = xstrdup (v);
diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
index 65effa9f3..00ca5c854 100644
--- a/grub-core/osdep/unix/config.c
+++ b/grub-core/osdep/unix/config.c
@@ -78,6 +78,8 @@ 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 =
grub_util_strtoul_with_default(getenv("GRUB_CRYPTODISK_ATTEMPTS"), 1);
+
   v = getenv ("GRUB_DISTRIBUTOR");
   if (v)
     cfg->grub_distributor = xstrdup (v);
@@ -105,8 +107,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..765e1b7fb 100644
--- a/grub-core/osdep/windows/config.c
+++ b/grub-core/osdep/windows/config.c
@@ -41,6 +41,8 @@ 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 =
grub_util_strtoul_with_default(getenv("GRUB_CRYPTODISK_ATTEMPTS"), 1);
+
   v = getenv ("GRUB_DISTRIBUTOR");
   if (v)
     cfg->grub_distributor = xstrdup (v);
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index 32f564ae0..5ad759a70 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -112,6 +112,7 @@ struct grub_cryptodisk_dev
 };
 typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t;

+extern unsigned long EXPORT_VAR (max_attempts);
 extern grub_cryptodisk_dev_t EXPORT_VAR (grub_cryptodisk_list);

 #ifndef GRUB_LST_GENERATOR
diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h
index 875d5896c..7b5563378 100644
--- a/include/grub/emu/config.h
+++ b/include/grub/emu/config.h
@@ -37,6 +37,7 @@ struct grub_util_config
 {
   int is_cryptodisk_enabled;
   char *grub_distributor;
+  unsigned long cryptodisk_attempts;
 };

 void
diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h
index e9e0a6724..dd51f3956 100644
--- a/include/grub/util/misc.h
+++ b/include/grub/util/misc.h
@@ -49,4 +49,6 @@ void grub_util_host_init (int *argc, char ***argv);

 int grub_qsort_strcmp (const void *, const void *);

+unsigned long grub_util_strtoul_with_default(const char *str,
unsigned long def);
+
 #endif /* ! GRUB_UTIL_MISC_HEADER */
diff --git a/util/config.c b/util/config.c
index ebcdd8f5e..ed8b8357a 100644
--- a/util/config.c
+++ b/util/config.c
@@ -23,6 +23,27 @@
 #include <grub/emu/config.h>
 #include <grub/util/misc.h>

+unsigned long
+grub_util_strtoul_with_default(const char *str, unsigned long def)
+{
+    unsigned long result = 0;
+
+    if (str)
+      {
+        /* avoid grub_errno=GRUB_ERR_BAD_NUMBER in grub_strtoul on empty */
+        while (grub_isspace (*str))
+            str++;
+        if (*str != '\0')
+            result = grub_strtoul(str, NULL, 10);
+      }
+
+    if (result == 0)
+        result = def;
+
+    return result;
+}
+
+
 void
 grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple)
 {
@@ -32,6 +53,14 @@ 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;
+          cfg->cryptodisk_attempts = grub_util_strtoul_with_default(ptr, 1);
+          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.22.0



reply via email to

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