[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v3 11/12] cryptodisk: Support key protectors
From: |
Gary Lin |
Subject: |
Re: [PATCH v3 11/12] cryptodisk: Support key protectors |
Date: |
Mon, 17 Apr 2023 15:11:38 +0800 |
On Wed, Apr 12, 2023 at 03:20:18PM -0300, Glenn Washburn wrote:
> On 4/12/23 06:15, Gary Lin wrote:
> > From: Hernan Gatta <hegatta@linux.microsoft.com>
> >
> > 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 <hegatta@linux.microsoft.com>
> > Signed-off-by: Michael Chang <mchang@suse.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
>
> Except for some trivial changes below.
>
> Reviewed-by: Glenn Washburn <development@efficientek.com>
>
Thanks! I'm working on v4 for some improvements. Will fix them in v4 and
gratefully add your "Reviewed-by" :)
Gary Lin
> > ---
> > 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 c3b7df96d..7d8db722e 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 34b67a705..8fdae74cf 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>
> > @@ -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)
>
> Daniel like to NULL pointer checks to be 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)
>
> cargs->key_cache[i].key == NULL
>
> > + {
> > + ret = grub_key_protector_recover_key (cargs->protectors[i],
> > + &cargs->key_cache[i].key,
> > +
> > &cargs->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, dev, cargs);
> > + if (ret != GRUB_ERR_NONE)
> > + {
> > + 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
> > + {
> > + ret = grub_cryptodisk_insert (dev, name, source);
> > + if (ret != GRUB_ERR_NONE)
> > + goto error;
> > + 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;
> > + }
> > +
> > + 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 = cr->recover_key (source, dev, cargs);
> > + if (ret != GRUB_ERR_NONE)
> > + goto error;
> > +
> > + ret = grub_cryptodisk_insert (dev, name, source);
> > + if (ret != GRUB_ERR_NONE)
> > + goto error;
> > - goto cleanup;
> > - }
> > - grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this
> > device");
> > goto cleanup;
> > error:
> > @@ -1258,6 +1334,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 == NULL || cargs->protectors == NULL)
> > + 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)
> > {
> > @@ -1270,6 +1360,10 @@ 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[OPTION_PASSWORD].set && state[OPTION_PROTECTOR].set) /*
> > password and key protector */
> > + return grub_error (GRUB_ERR_BAD_ARGUMENT,
> > + "a password and a key protector cannot both be set");
> > +
> > if (state[OPTION_PASSWORD].set) /* password */
> > {
> > cargs.key_data = (grub_uint8_t *) state[OPTION_PASSWORD].arg;
> > @@ -1362,6 +1456,15 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt,
> > int argc, char **args)
> > return grub_errno;
> > }
> > + if (state[OPTION_PROTECTOR].set) /* key protector(s) */
> > + {
> > + cargs.key_cache = grub_zalloc (state[OPTION_PROTECTOR].set * sizeof
> > (*cargs.key_cache));
> > + if (!cargs.key_cache)
>
> cargs.key_cache == NULL
>
> Glenn
>
> > + return grub_error (GRUB_ERR_OUT_OF_MEMORY,
> > + "no memory for key protector key cache");
> > + cargs.protectors = state[OPTION_PROTECTOR].args;
> > + }
> > +
> > if (state[OPTION_UUID].set) /* uuid */
> > {
> > int found_uuid;
> > @@ -1370,6 +1473,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;
> > @@ -1378,6 +1482,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int
> > argc, char **args)
> > cargs.check_boot = state[OPTION_BOOT].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;
> > @@ -1397,6 +1502,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int
> > argc, char **args)
> > {
> > cargs.check_boot = state[OPTION_BOOT].set;
> > grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
> > + grub_cryptodisk_clear_key_cache (&cargs);
> > return GRUB_ERR_NONE;
> > }
> > else
> > @@ -1420,6 +1526,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;
> > @@ -1430,12 +1537,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)
> > @@ -1576,6 +1685,7 @@ GRUB_MOD_INIT (cryptodisk)
> > cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
> > N_("[ [-p password] | [-k keyfile"
> > " [-O keyoffset] [-S keysize] ] ] [-H file]"
> > + " [-P protector [-P 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 d94df68b6..0b41e249e 100644
> > --- a/include/grub/cryptodisk.h
> > +++ b/include/grub/cryptodisk.h
> > @@ -70,6 +70,18 @@ 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 */
> > @@ -81,6 +93,10 @@ struct grub_cryptomount_args
> > /* recover_key: Length of key_data */
> > grub_size_t key_len;
> > grub_file_t hdr_file;
> > + /* 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;
>
- [PATCH v3 06/12] test_asn1: test module for libtasn1, (continued)
- [PATCH v3 06/12] test_asn1: test module for libtasn1, Gary Lin, 2023/04/12
- [PATCH v3 07/12] libtasn1: Add the documentation, Gary Lin, 2023/04/12
- [PATCH v3 03/12] libtasn1: disable code not needed in grub, Gary Lin, 2023/04/12
- [PATCH v3 08/12] protectors: Add key protectors framework, Gary Lin, 2023/04/12
- [PATCH v3 09/12] tpm2: Add TPM Software Stack (TSS), Gary Lin, 2023/04/12
- [PATCH v3 02/12] libtasn1: import libtasn1-4.19.0, Gary Lin, 2023/04/12
- [PATCH v3 01/12] posix_wrap: tweaks in preparation for libtasn1, Gary Lin, 2023/04/12
- [PATCH v3 10/12] protectors: Add TPM2 Key Protector, Gary Lin, 2023/04/12
- [PATCH v3 11/12] cryptodisk: Support key protectors, Gary Lin, 2023/04/12
- [PATCH v3 12/12] util/grub-protect: Add new tool, Gary Lin, 2023/04/12