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 <hega...@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 <hega...@linux.microsoft.com> > > Signed-off-by: Michael Chang <mch...@suse.com> > > Signed-off-by: Gary Lin <g...@suse.com> > > Except for some trivial changes below. > > Reviewed-by: Glenn Washburn <developm...@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; > _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel