From: Hernan Gatta <hegatta@linux.microsoft.com>
To: grub-devel@gnu.org
Cc: shkhisti@microsoft.com, jaskaran.khurana@microsoft.com,
christopher.co@microsoft.com, daniel.mihai@microsoft.com,
rharwood@redhat.com, jaredz@redhat.com,
development@efficientek.com, jejb@linux.ibm.com
Subject: [PATCH v2 4/5] cryptodisk: Support key protectors
Date: Tue, 1 Feb 2022 05:02:56 -0800 [thread overview]
Message-ID: <1643720577-22911-5-git-send-email-hegatta@linux.microsoft.com> (raw)
In-Reply-To: <1643720577-22911-1-git-send-email-hegatta@linux.microsoft.com>
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 hegatta@linux.microsoft.com>
---
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 f8b356c..39b53b3 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 4970973..00c4477 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 c6524c9..b556498 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;
--
1.8.3.1
next prev parent reply other threads:[~2022-02-01 13:04 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-01 13:02 [PATCH v2 0/5] Automatic TPM Disk Unlock Hernan Gatta
2022-02-01 13:02 ` [PATCH v2 1/5] protectors: Add key protectors framework Hernan Gatta
2022-02-01 13:02 ` [PATCH v2 2/5] tpm2: Add TPM Software Stack (TSS) Hernan Gatta
2022-02-01 13:02 ` [PATCH v2 3/5] protectors: Add TPM2 Key Protector Hernan Gatta
2022-03-22 3:47 ` Michael Chang
2022-03-22 5:46 ` Michael Chang
2022-02-01 13:02 ` Hernan Gatta [this message]
2022-02-01 13:02 ` [PATCH v2 5/5] util/grub-protect: Add new tool Hernan Gatta
2022-03-22 5:54 ` Michael Chang
2022-02-01 21:40 ` [PATCH v2 0/5] Automatic TPM Disk Unlock Didier Spaier
2022-09-23 4:16 ` Max Vohra
2023-02-06 5:53 ` Gary Lin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1643720577-22911-5-git-send-email-hegatta@linux.microsoft.com \
--to=hegatta@linux.microsoft.com \
--cc=christopher.co@microsoft.com \
--cc=daniel.mihai@microsoft.com \
--cc=development@efficientek.com \
--cc=grub-devel@gnu.org \
--cc=jaredz@redhat.com \
--cc=jaskaran.khurana@microsoft.com \
--cc=jejb@linux.ibm.com \
--cc=rharwood@redhat.com \
--cc=shkhisti@microsoft.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.