grub-devel
[Top][All Lists]
Advanced

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

enable cryptomount to read passphrase from file


From: Alexandre Oliva
Subject: enable cryptomount to read passphrase from file
Date: Sun, 18 Jan 2015 01:29:45 -0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux)

Here's a compile-tested patch that attempts to add '-p FILE' support to
cryptomount, so that the passphrase can be read from a usb key or
somesuch.

I was unsure about how much to massage or verify the file, say, dropping
a trailing newline or truncating the passphrase at the first newline or
whatever.  I ended up deciding to keep it simple and just use the file
contents unchanged in any way (though the passphrase users will use it
as a C string, so any NUL in the file will effectively truncate the
passphrase).  Thoughts?


I've only checked that it builds, but I haven't really tested it yet
I'm not sure yet how to go about that without risking rendering my
boxes unbootable :-)  Suggestions are welcome.

Thanks,

Index: ChangeLog
from  Alexandre Oliva  <address@hidden>

        * docs/grub.texi (cryptomount): Add -p file.
        * grub-core/disk/cryptodisk.c (options): Likewise.
        (grub_cryptodisk_scan_device_real): Add key parameter.  Pass it to
        recover_key.
        (grub_cryptodisk_scan_device): Likewise.
        (grub_cmd_cryptomount): Read key from file.  Pass it on.
        (GRUB_MOD_INIT): Adjust cryptomount usage.
        * include/grub/cryptodisk.h (GRUB_CRYPTODISK_MAX_PASSPHRASE): New.
        (grub_cyrptodisk_dev::recover_key): Add key parameter.
        * grub-core/disk/geli.c (MAX_PASSPHRASE): Define to
        GRUB_CRYPTODISK_MAX_PASSPHRASE.
        (recover_key): Add key parameter; try it first if given, retry
        with keyboard-read passphrase.
        * grub-core/disk/luks.c (MAX_PASSPHRASE, luks_recover_key):
        Likewise.

Index: docs/grub.texi
--- grub.orig/docs/grub.texi    2014-10-14 23:30:59.000000000 -0300
+++ grub/docs/grub.texi 2015-01-18 01:26:49.499924206 -0200
@@ -4073,9 +4073,12 @@ Alias for @code{hashsum --hash crc32 arg
 @node cryptomount
 @subsection cryptomount
 
address@hidden 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
address@hidden Command cryptomount address@hidden file] device|@option{-u} 
uuid|@option{-a}|@option{-b}
+Setup access to encrypted device.  The passphrase will be asked
+interactively, unless @option{-p} @var{file} is specified and the
+passphrase read from the file succeeds.  The file should contain
address@hidden the passphrase, not even a trailing line break.  Option
address@hidden 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.
Index: grub-core/disk/cryptodisk.c
--- grub.orig/grub-core/disk/cryptodisk.c       2014-10-14 23:30:57.000000000 
-0300
+++ grub/grub-core/disk/cryptodisk.c    2015-01-18 01:08:27.506796052 -0200
@@ -40,6 +40,8 @@ static const struct grub_arg_option opti
     /* 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},
+    {"passfile", 'p', 0, N_("Read the passphrase from the named file."),
+     N_("FILE"), ARG_TYPE_STRING},
     {0, 0, 0, 0, 0, 0}
   };
 
@@ -806,7 +808,8 @@ 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,
+                                 const char *key)
 {
   grub_err_t err;
   grub_cryptodisk_t dev;
@@ -825,7 +828,7 @@ grub_cryptodisk_scan_device_real (const
     if (!dev)
       continue;
     
-    err = cr->recover_key (source, dev);
+    err = cr->recover_key (source, dev, key);
     if (err)
     {
       cryptodisk_close (dev);
@@ -890,10 +893,11 @@ grub_cryptodisk_cheat_mount (const char
 
 static int
 grub_cryptodisk_scan_device (const char *name,
-                            void *data __attribute__ ((unused)))
+                            void *data)
 {
   grub_err_t err;
   grub_disk_t source;
+  const char *key = data;
 
   /* Try to open disk.  */
   source = grub_disk_open (name);
@@ -903,7 +907,7 @@ grub_cryptodisk_scan_device (const char
       return 0;
     }
 
-  err = grub_cryptodisk_scan_device_real (name, source);
+  err = grub_cryptodisk_scan_device_real (name, source, key);
 
   grub_disk_close (source);
   
@@ -916,10 +920,49 @@ static grub_err_t
 grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
 {
   struct grub_arg_list *state = ctxt->state;
+  char *key = NULL;
+  char buf[GRUB_CRYPTODISK_MAX_PASSPHRASE];
 
   if (argc < 1 && !state[1].set && !state[2].set)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
 
+  /* Read key from file.  */
+  if (ctxt->state[3].set)
+    {
+      char *fname = ctxt->state[3].arg;
+      grub_file_t file;
+      file = grub_file_open (fname);
+      if (!file)
+       grub_printf_ (N_("Failed to open passphrase file\n"));
+      else if (file)
+       {
+         grub_ssize_t size;
+         size = grub_file_read (file, buf, sizeof (buf));
+         if (size < 0)
+           grub_printf_ (N_("Error reading from passphrase file\n"));
+         else if (size == 0)
+           grub_printf_ (N_("Passphrase file is empty\n"));
+         else if ((grub_size_t)size >= sizeof (buf))
+           grub_printf_ (N_("Passphrase file is too big\n"));
+         else
+           {
+#if 0
+             int count;
+             for (count = 0; count < size; count++)
+               if (buf[count] == 0
+                   || buf[count] == '\n'
+                   || buf[count] == '\r')
+                 break;
+             if (count != size)
+               grub_printf_ (N_("Extraneous byte in passphrase file!\n"));
+#endif
+             grub_memset (buf + size, 0, sizeof (buf) - size);
+             key = buf;
+           }
+       }
+      grub_file_close (file);
+    }
+
   have_it = 0;
   if (state[0].set)
     {
@@ -935,7 +978,7 @@ grub_cmd_cryptomount (grub_extcmd_contex
 
       check_boot = state[2].set;
       search_uuid = args[0];
-      grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
+      grub_device_iterate (&grub_cryptodisk_scan_device, key);
       search_uuid = NULL;
 
       if (!have_it)
@@ -946,7 +989,7 @@ grub_cmd_cryptomount (grub_extcmd_contex
     {
       search_uuid = NULL;
       check_boot = state[2].set;
-      grub_device_iterate (&grub_cryptodisk_scan_device, NULL);
+      grub_device_iterate (&grub_cryptodisk_scan_device, key);
       search_uuid = NULL;
       return GRUB_ERR_NONE;
     }
@@ -980,7 +1023,7 @@ grub_cmd_cryptomount (grub_extcmd_contex
          return GRUB_ERR_NONE;
        }
 
-      err = grub_cryptodisk_scan_device_real (args[0], disk);
+      err = grub_cryptodisk_scan_device_real (args[0], disk, key);
 
       grub_disk_close (disk);
 
@@ -1117,7 +1160,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 FILE] SOURCE|-u UUID|-a|-b"),
                              N_("Mount a crypto device."), options);
   grub_procfs_register ("luks_script", &luks_script);
 }
Index: include/grub/cryptodisk.h
--- grub.orig/include/grub/cryptodisk.h 2014-10-14 23:31:00.000000000 -0300
+++ grub/include/grub/cryptodisk.h      2015-01-18 00:14:22.572709178 -0200
@@ -54,6 +54,10 @@ typedef enum
 #define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES)
 #define GRUB_CRYPTODISK_MAX_KEYLEN 128
 
+/* Backends may limit passphrases to smaller sizes, but this should be
+   the max among them all.  */
+#define GRUB_CRYPTODISK_MAX_PASSPHRASE 256
+
 struct grub_cryptodisk;
 
 typedef gcry_err_code_t
@@ -107,7 +111,8 @@ 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,
+                            const char *key);
 };
 typedef struct grub_cryptodisk_dev *grub_cryptodisk_dev_t;
 
Index: grub-core/disk/geli.c
--- grub.orig/grub-core/disk/geli.c     2014-10-14 23:30:57.000000000 -0300
+++ grub/grub-core/disk/geli.c  2015-01-18 01:06:31.422050391 -0200
@@ -135,7 +135,7 @@ const char *algorithms[] = {
   [0x16] = "aes"
 };
 
-#define MAX_PASSPHRASE 256
+#define MAX_PASSPHRASE GRUB_CRYPTODISK_MAX_PASSPHRASE
 
 static gcry_err_code_t
 geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno)
@@ -384,7 +384,7 @@ configure_ciphers (grub_disk_t disk, con
 }
 
 static grub_err_t
-recover_key (grub_disk_t source, grub_cryptodisk_t dev)
+recover_key (grub_disk_t source, grub_cryptodisk_t dev, const char *key)
 {
   grub_size_t keysize;
   grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN];
@@ -419,16 +419,31 @@ recover_key (grub_disk_t source, grub_cr
 
   grub_puts_ (N_("Attempting to decrypt master key..."));
 
-  /* Get the passphrase from the user.  */
+ retry:
   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");
+  if (key && grub_strlen (key) >= MAX_PASSPHRASE)
+    {
+      grub_printf_ (N_("Discarding too-long supplied passphrase\n"));
+      key = NULL;
+    }
+  if (key)
+    {
+      grub_size_t len = grub_strlen (key);
+      grub_memcpy (passphrase, key, len);
+      grub_memset (passphrase + len, 0, sizeof (passphrase) - len);
+    }
+  else
+    {
+      /* Get the passphrase from the user.  */
+      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)
@@ -548,6 +563,13 @@ recover_key (grub_disk_t source, grub_cr
       return GRUB_ERR_NONE;
     }
 
+  if (key)
+    {
+      grub_printf_ (N_("Supplied passphrase failed to unlock key\n"));
+      key = NULL;
+      goto retry;
+    }
+
   return GRUB_ACCESS_DENIED;
 }
 
Index: grub-core/disk/luks.c
--- grub.orig/grub-core/disk/luks.c     2014-10-14 23:30:57.000000000 -0300
+++ grub/grub-core/disk/luks.c  2015-01-18 01:06:26.336192968 -0200
@@ -29,7 +29,7 @@
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
-#define MAX_PASSPHRASE 256
+#define MAX_PASSPHRASE GRUB_CRYPTODISK_MAX_PASSPHRASE
 
 #define LUKS_KEY_ENABLED  0x00AC71F3
 
@@ -297,7 +297,8 @@ configure_ciphers (grub_disk_t disk, con
 
 static grub_err_t
 luks_recover_key (grub_disk_t source,
-                 grub_cryptodisk_t dev)
+                 grub_cryptodisk_t dev,
+                 const char *key)
 {
   struct grub_luks_phdr header;
   grub_size_t keysize;
@@ -328,18 +329,33 @@ luks_recover_key (grub_disk_t source,
   if (!split_key)
     return grub_errno;
 
-  /* Get the passphrase from the user.  */
+ retry:
   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))
+  if (key && grub_strlen (key) >= MAX_PASSPHRASE)
     {
-      grub_free (split_key);
-      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
+      grub_printf_ (N_("Discarding too-long supplied passphrase\n"));
+      key = NULL;
+    }
+  if (key)
+    {
+      grub_size_t len = grub_strlen (key);
+      grub_memcpy (passphrase, key, len);
+      grub_memset (passphrase + len, 0, sizeof (passphrase) - len);
+    }
+  else
+    {
+      /* Get the passphrase from the user.  */
+      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.  */
@@ -451,6 +467,13 @@ luks_recover_key (grub_disk_t source,
       return GRUB_ERR_NONE;
     }
 
+  if (key)
+    {
+      grub_printf_ (N_("Supplied passphrase failed to unlock key\n"));
+      key = NULL;
+      goto retry;
+    }
+
   return GRUB_ACCESS_DENIED;
 }
 
-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer

reply via email to

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