From bcce1e8d18b4455543556f04cce99747ac2987e5 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Wed, 17 Jun 2020 17:28:32 +0200 Subject: [PATCH] zkey: Add 'zkey kms list' command to list keys in a KMS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow to list the keys managed by a key management system. The keys are displayed together with the key properties stored in the KMS. Signed-off-by: Ingo Franzki Signed-off-by: Jan Höppner --- zkey/kms.c | 485 ++++++++++++++++++++++++++++++++++++++++++++++++++++ zkey/kms.h | 23 +++ zkey/zkey.1 | 71 ++++++++ zkey/zkey.c | 86 ++++++++++ 4 files changed, 665 insertions(+) diff --git a/zkey/kms.c b/zkey/kms.c index 5abc2d09..dddc0acd 100644 --- a/zkey/kms.c +++ b/zkey/kms.c @@ -7,11 +7,13 @@ * it under the terms of the MIT license. See LICENSE for details. */ +#include #include #include #include #include #include +#include #include #include #include @@ -60,6 +62,17 @@ #define KMS_KEY_PROP_XTS_KEY1_LABEL "xts-key1-label" #define KMS_KEY_PROP_XTS_KEY2_LABEL "xts-key2-label" +#define KMS_REC_LABEL "Key label" +#define KMS_REC_NAME "Name" +#define KMS_REC_KEY_TYPE "Key type" +#define KMS_REC_KEY_SIZE "Key size" +#define KMS_REC_DESCRIPTION "Description" +#define KMS_REC_XTS "XTS type key" +#define KMS_REC_VOLUMES "Volumes" +#define KMS_REC_VOLUME_TYPE "Volume type" +#define KMS_REC_SECTOR_SIZE "Sector size" +#define KMS_REC_ADDL_INFOS "Addl. infos" + static const char * const key_types[] = { KEY_TYPE_CCA_AESDATA, KEY_TYPE_CCA_AESCIPHER, @@ -2502,3 +2515,475 @@ out: return rc; } + +struct process_keys_data { + struct kms_info *kms_info; + bool verbose; + const char *label_filter; + const char *name_filter; + char **volume_filter; + char *volume_type; + char *zkey_name_system; + char *volume_system; + kms_process_callback callback; + void *private_data; +}; + +/** + * Finds a KMS property in the property array and returns its value or NULL if + * it has not been found. + * + * @param properties a list of properties of the key + * @param num_properties the number of properties in above array + * @param prop_name the name of the property to get + * + * @returns the properties value, or NULL if not found. + * Note: The returned string is the value field from the array element. + */ +static const char *_find_property(const struct kms_property *properties, + size_t num_properties, const char *prop_name) +{ + size_t i; + + for (i = 0; i < num_properties; i++) { + if (strcmp(properties[i].name, prop_name) == 0) + return properties[i].value; + } + return NULL; +} + +/* + * Checks if the value matches the filter list. The value is a comma + * separated string. + * + * If the filter values contain a second part separated by a colon (':'), then + * the filter matches only if both parts match. If the filter values do not + * contain a second part,then only the first part is checked, and the second + * parts of the values are ignored. + * + * @param[in] value the value to check + * @param[in] filter_list a list of filter strings to match the value with + * @param[in] match_func the filter match function. If NULL fnmatch() is used. + * + * @returns 1 for a match, 0 for not matched + */ +static int _match_volumes_filter(const char *volumes, char **volumes_filter) +{ + char **value_list; + int i, k, rc = 0; + char *ch; + + if (volumes_filter == NULL) + return 1; + + value_list = str_list_split(volumes); + for (i = 0; volumes_filter[i] != NULL && rc == 0; i++) { + for (k = 0; value_list[k] != NULL; k++) { + /* + * Ignore part after ':' of value if filter does + * not also contain a ':' part. + */ + if (strchr(volumes_filter[i], ':') == NULL) { + ch = strchr(value_list[k], ':'); + if (ch != NULL) + *ch = '\0'; + } + + if (fnmatch(volumes_filter[i], value_list[k], 0) == 0) { + rc = 1; + break; + } + } + } + + str_list_free_string_array(value_list); + return rc; +} + +/** + * Callback used with the process_kms_keys() function. Called for each key. + * + * @param key_id the key-ID of the key + * @param key_label the label of the key. + * @param key_type the type of the key (CCA-AESDATA, etc) + * @param key_bits the key size in bits + * @param properties a list of properties of the key + * @param num_properties the number of properties in above array + * @param addl_info_argz an argz string containing additional KMS plugin + * specific infos to be displayed, or NULL if none. + * @param addl_info_len length of the argz string in addl_info_argz + * @param private_data the private data pointer + * + * @returns 0 on success, or a negative errno in case of an error. + */ +static int _process_kms_keys_cb(const char *key_id, const char *key_label, + const char *key_type, size_t key_bits, + const struct kms_property *properties, + size_t num_properties, + const char *addl_info_argz, + size_t addl_info_len, void *private_data) +{ + struct process_keys_data *process_data = private_data; + const char *name, *volumes, *cipher, *iv_mode, *description; + const char *xts_key2_id = NULL, *xts_key2_label = NULL; + const char *xts_key, *volume_type, *temp; + size_t sector_size = 0; + bool xts = false; + + pr_verbose(process_data->verbose, "processing key_id: %s", key_id); + + xts_key = _find_property(properties, num_properties, + KMS_KEY_PROP_XTS_KEY); + if (xts_key != NULL) { + if (strcasecmp(xts_key, "XTS-KEY-1") != 0) { + pr_verbose(process_data->verbose, + "skipping '%s' due to %s=%s", key_id, + KMS_KEY_PROP_XTS_KEY, xts_key); + return 0; + } + xts = true; + + xts_key2_id = _find_property(properties, num_properties, + KMS_KEY_PROP_XTS_KEY2_ID); + xts_key2_label = _find_property(properties, num_properties, + KMS_KEY_PROP_XTS_KEY2_LABEL); + if (xts_key2_id == NULL || xts_key2_label == NULL) { + pr_verbose(process_data->verbose, "skipping '%s' due " + "to missing XTS cross refs", key_id); + return 0; + } + } + + name = _find_property(properties, num_properties, + process_data->zkey_name_system); + if (name == NULL) + name = _find_property(properties, num_properties, + KMS_KEY_PROP_NAME); + if (name == NULL) { + pr_verbose(process_data->verbose, "skipping '%s' due " + "to missing %s", key_id, KMS_KEY_PROP_NAME); + return 0; + } + + cipher = _find_property(properties, num_properties, + KMS_KEY_PROP_CIPHER); + iv_mode = _find_property(properties, num_properties, + KMS_KEY_PROP_IV_MODE); + description = _find_property(properties, num_properties, + KMS_KEY_PROP_DESCRIPTION); + volumes = _find_property(properties, num_properties, + process_data->volume_system); + if (volumes == NULL) + volumes = _find_property(properties, num_properties, + KMS_KEY_PROP_VOLUMES); + volume_type = _find_property(properties, num_properties, + KMS_KEY_PROP_VOLUME_TYPE); + temp = _find_property(properties, num_properties, + KMS_KEY_PROP_SECTOR_SIZE); + if (temp != NULL) + sscanf(temp, "%lu", §or_size); + + if (process_data->label_filter != NULL) { + if (fnmatch(process_data->label_filter, key_label, + FNM_PATHNAME) != 0) + return 0; + + if (xts && fnmatch(process_data->label_filter, xts_key2_label, + FNM_PATHNAME) != 0) + return 0; + } + + if (process_data->name_filter != NULL && + fnmatch(process_data->name_filter, name, FNM_PATHNAME) != 0) + return 0; + + if (process_data->volume_filter != NULL) { + if (volumes == NULL) + return 0; + + if (!_match_volumes_filter(volumes, + process_data->volume_filter)) + return 0; + } + + if (process_data->volume_type != NULL && + strcasecmp(process_data->volume_type, volume_type) != 0) + return 0; + + return process_data->callback(key_id, key_label, xts_key2_id, + xts_key2_label, xts, name, key_type, + xts ? key_bits * 2 : key_bits, + description, cipher, iv_mode, + volumes, volume_type, sector_size, + addl_info_argz, addl_info_len, + process_data->private_data); +} + +/** + * Processes KMS managed keys. The keys can be filtered by label, name, volume, + * and volume type. + * + * @param[in] kms_info information of the currently bound plugin. + * @param[in] label_filter the KMS label filter. Can contain wild cards. + * NULL means no name filter. + * @param[in] name_filter the name filter. Can contain wild cards. + * NULL means no name filter. + * @param[in] volume_filter the volume filter. Can contain wild cards, and + * mutliple volume filters separated by commas. + * If the filter does not contain the ':dm-name' + * part, then the volumes are matched without the + * dm-name part. If the filter contains the + * ':dm-name' part, then the filter is matched + * including the dm-name part. + * NULL means no volume filter. + * @param[in] volume_type If not NULL, specifies the volume type. + * @param[in] callback the callback that is called for each matching key + * @param[in] private_data the private data of the callback + * @param[in] kms_options an array of KMS options specified, or NULL if no + * KMS options have been specified + * @param[in] num_kms_options the number of options in above array + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 for success or a negative errno in case of an error. + */ +int process_kms_keys(struct kms_info *kms_info, + const char *label_filter, const char *name_filter, + const char *volume_filter, const char *volume_type, + struct kms_option *kms_options, size_t num_kms_options, + kms_process_callback callback, void *private_data, + bool verbose) +{ + struct process_keys_data process_data = { 0 }; + struct kms_property kms_props; + size_t num_kms_props = 0; + int rc = 0; + + util_assert(kms_info != NULL, "Internal error: kms_info is NULL"); + util_assert(callback != NULL, "Internal error: callback is NULL"); + + if (kms_info->funcs->kms_list_keys == NULL) { + pr_verbose(verbose, "The KMS plugin does not support to " + "list keys"); + return -ENOTSUP; + } + + process_data.kms_info = kms_info; + process_data.verbose = verbose; + process_data.label_filter = label_filter; + process_data.name_filter = name_filter; + if (volume_filter != NULL) + process_data.volume_filter = str_list_split(volume_filter); + if (volume_type != NULL) { + process_data.volume_type = util_strdup(volume_type); + util_str_toupper(process_data.volume_type); + } + process_data.callback = callback; + process_data.private_data = private_data; + process_data.zkey_name_system = + _get_system_specific_prop_name(KMS_KEY_PROP_NAME); + process_data.volume_system = + _get_system_specific_prop_name(KMS_KEY_PROP_VOLUMES); + + if (process_data.volume_type != NULL) { + kms_props.name = KMS_KEY_PROP_VOLUME_TYPE; + kms_props.value = process_data.volume_type; + num_kms_props = 1; + } + + rc = kms_info->funcs->kms_list_keys(kms_info->handle, label_filter, + num_kms_props > 0 ? + &kms_props : NULL, + num_kms_props, kms_options, + num_kms_options, + _process_kms_keys_cb, + &process_data); + + if (rc != 0) { + warnx("KMS plugin '%s' failed to list keys: %s", + kms_info->plugin_name, strerror(-rc)); + print_last_kms_error(kms_info); + } + + free(process_data.zkey_name_system); + free(process_data.volume_system); + if (process_data.volume_filter != NULL) + str_list_free_string_array(process_data.volume_filter); + if (process_data.volume_type != NULL) + free(process_data.volume_type); + + return rc; +} + +struct list_keys_data { + struct util_rec *rec; +}; + +/** + * Callback used with the list_kms_keys() function. Called for each key. + * + * @param key1_id the key-ID of the key (1st key of an XTS key) + * @param key1_label the label of the key (1st key of an XTS key) + * @param key2_id the key-ID of the 2nd XTS key, NULL if not XTS + * @param key2_label the label of the 2nd XTS key, NULL if not XTS + * @param xts if true, this is an XTS key pair + * @param name the zkey name of the key + * @param key_type the type of the key (CCA-AESDATA, etc) + * @param key_bits the key size in bits + * @param description the description of the key (can be NULL) + * @param cipher the cipher of the key (can be NULL) + * @param iv_mode the IV-mode of the key (can be NULL) + * @param volumes the associated volumes of the key (can be NULL) + * @param volume_type the volume type of the volume (can be NULL) + * @param sector_size the sector size of the volume (0 means default) + * @param addl_info_argz an argz string containing additional KMS plugin + * specific infos to be displayed, or NULL if none. + * @param addl_info_len length of the argz string in addl_info_argz + * @param private_data the private data pointer + * + * @returns 0 on success, or a negative errno in case of an error. + */ +static int _list_kms_keys_cb(const char *UNUSED(key1_id), + const char *key1_label, + const char *UNUSED(key2_id), + const char *key2_label, + bool xts, const char *name, + const char *key_type, size_t key_bits, + const char *description, + const char *UNUSED(cipher), + const char *UNUSED(iv_mode), const char *volumes, + const char *volume_type, size_t sector_size, + const char *addl_info_argz, size_t addl_info_len, + void *private_data) +{ + struct list_keys_data *list_data = private_data; + size_t volumes_argz_len, label_argz_len; + char *volumes_argz = NULL; + char *label_argz = NULL; + + if (xts) + label_argz_len = util_asprintf(&label_argz, "%s%c%s", + key1_label, '\0', key2_label); + else + label_argz_len = util_asprintf(&label_argz, "%s", key1_label); + label_argz_len += 1; + + if (volumes != NULL) + util_assert(argz_create_sep(volumes, ',', + &volumes_argz, + &volumes_argz_len) == 0, + "Internal error: argz_create_sep failed"); + + util_rec_set(list_data->rec, KMS_REC_NAME, name); + util_rec_set_argz(list_data->rec, KMS_REC_LABEL, label_argz, + label_argz_len); + util_rec_set(list_data->rec, KMS_REC_DESCRIPTION, + description != NULL ? description : ""); + util_rec_set(list_data->rec, KMS_REC_XTS, xts ? "Yes" : "No"); + util_rec_set(list_data->rec, KMS_REC_KEY_TYPE, key_type); + util_rec_set(list_data->rec, KMS_REC_KEY_SIZE, "%lu bits", key_bits); + if (volumes_argz != NULL) + util_rec_set_argz(list_data->rec, KMS_REC_VOLUMES, volumes_argz, + volumes_argz_len); + else + util_rec_set(list_data->rec, KMS_REC_VOLUMES, "(none)"); + util_rec_set(list_data->rec, KMS_REC_VOLUME_TYPE, + volume_type != NULL ? volume_type : ""); + if (sector_size == 0) + util_rec_set(list_data->rec, KMS_REC_SECTOR_SIZE, + "(system default)"); + else + util_rec_set(list_data->rec, KMS_REC_SECTOR_SIZE, "%lu bytes", + sector_size); + if (addl_info_argz != NULL) + util_rec_set_argz(list_data->rec, KMS_REC_ADDL_INFOS, + addl_info_argz, addl_info_len); + else + util_rec_set(list_data->rec, KMS_REC_ADDL_INFOS, "(none)"); + + util_rec_print(list_data->rec); + + if (volumes_argz != NULL) + free(volumes_argz); + if (label_argz != NULL) + free(label_argz); + + return 0; +} + +/** + * Lists KMS managed keys. The list can be filtered by label, name, volume, + * and volume type. + * + * @param[in] kms_info information of the currently bound plugin. + * @param[in] label_filter the KMS label filter. Can contain wild cards. + * NULL means no name filter. + * @param[in] name_filter the name filter. Can contain wild cards. + * NULL means no name filter. + * @param[in] volume_filter the volume filter. Can contain wild cards, and + * mutliple volume filters separated by commas. + * If the filter does not contain the ':dm-name' + * part, then the volumes are matched without the + * dm-name part. If the filter contains the + * ':dm-name' part, then the filter is matched + * including the dm-name part. + * NULL means no volume filter. + * @param[in] volume_type If not NULL, specifies the volume type. + * @param[in] kms_options an array of KMS options specified, or NULL if no + * KMS options have been specified + * @param[in] num_kms_options the number of options in above array + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 for success or a negative errno in case of an error. + */ +int list_kms_keys(struct kms_info *kms_info, const char *label_filter, + const char *name_filter, const char *volume_filter, + const char *volume_type, struct kms_option *kms_options, + size_t num_kms_options, bool verbose) +{ + struct list_keys_data list_data = { 0 }; + int rc; + + util_assert(kms_info != NULL, "Internal error: kms_info is NULL"); + + if (kms_info->plugin_lib == NULL) { + warnx("The repository is not bound to a KMS plugin"); + return -ENOENT; + } + + if (kms_info->funcs->kms_list_keys == NULL) { + pr_verbose(verbose, "The KMS plugin does not support to " + "list keys"); + return -ENOTSUP; + } + + list_data.rec = util_rec_new_long("-", ":", KMS_REC_NAME, 28, 54); + util_rec_def(list_data.rec, KMS_REC_NAME, UTIL_REC_ALIGN_LEFT, 54, + KMS_REC_NAME); + util_rec_def(list_data.rec, KMS_REC_LABEL, UTIL_REC_ALIGN_LEFT, 54, + KMS_REC_LABEL); + util_rec_def(list_data.rec, KMS_REC_DESCRIPTION, UTIL_REC_ALIGN_LEFT, + 54, KMS_REC_DESCRIPTION); + util_rec_def(list_data.rec, KMS_REC_KEY_SIZE, UTIL_REC_ALIGN_LEFT, 20, + KMS_REC_KEY_SIZE); + util_rec_def(list_data.rec, KMS_REC_XTS, UTIL_REC_ALIGN_LEFT, 20, + KMS_REC_XTS); + util_rec_def(list_data.rec, KMS_REC_KEY_TYPE, UTIL_REC_ALIGN_LEFT, 54, + KMS_REC_KEY_TYPE); + util_rec_def(list_data.rec, KMS_REC_VOLUMES, UTIL_REC_ALIGN_LEFT, 54, + KMS_REC_VOLUMES); + util_rec_def(list_data.rec, KMS_REC_VOLUME_TYPE, UTIL_REC_ALIGN_LEFT, + 54, KMS_REC_VOLUME_TYPE); + util_rec_def(list_data.rec, KMS_REC_SECTOR_SIZE, UTIL_REC_ALIGN_LEFT, + 20, KMS_REC_SECTOR_SIZE); + util_rec_def(list_data.rec, KMS_REC_ADDL_INFOS, UTIL_REC_ALIGN_LEFT, + 54, KMS_REC_ADDL_INFOS); + + rc = process_kms_keys(kms_info, label_filter, name_filter, + volume_filter, volume_type, kms_options, + num_kms_options, _list_kms_keys_cb, + &list_data, verbose); + + util_rec_free(list_data.rec); + + return rc; +} diff --git a/zkey/kms.h b/zkey/kms.h index 36ea0dc0..74fa480f 100644 --- a/zkey/kms.h +++ b/zkey/kms.h @@ -87,4 +87,27 @@ int remove_kms_key(struct kms_info *kms_info, struct properties *key_props, struct kms_option *kms_options, size_t num_kms_options, bool verbose); +typedef int (*kms_process_callback)(const char *key1_id, const char *key1_label, + const char *key2_id, const char *key2_label, + bool xts, const char *name, + const char *key_type, size_t key_bits, + const char *description, const char *cipher, + const char *iv_mode, const char *volumes, + const char *volume_type, size_t sector_size, + const char *addl_info_argz, + size_t addl_info_len, + void *private_data); + +int process_kms_keys(struct kms_info *kms_info, + const char *label_filter, const char *name_filter, + const char *volume_filter, const char *volume_type, + struct kms_option *kms_options, size_t num_kms_options, + kms_process_callback callback, void *private_data, + bool verbose); + +int list_kms_keys(struct kms_info *kms_info, const char *label_filter, + const char *name_filter, const char *volume_filter, + const char *volume_type, struct kms_option *kms_options, + size_t num_kms_options, bool verbose); + #endif diff --git a/zkey/zkey.1 b/zkey/zkey.1 index cb512dc8..6d323a90 100644 --- a/zkey/zkey.1 +++ b/zkey/zkey.1 @@ -1030,6 +1030,41 @@ re-enciphering. Re-enciphering from \fBCURRENT\fP to \fBNEW\fP is performed in staged mode per default. You can use option \fB\-\-staged\fP to force a staged re-enciphering for the \fBOLD\fP to \fBCURRENT\fP case. . +.SS "List secure keys managed by a key management system" +. +.B zkey kms +.BR list | li +.RB [ \-\-label | \-B +.IR key-label ] +.RB [ \-\-name | \-N +.IR key-name ] +.RB [ \-\-volumes | \-l +.IR volume1[:dmname1][,volume2[:dmname2][,...]] ] +.RB [ \-\-volume-type | \-t +.IR type ] +.RB [ KMS\-plugin\ specific\ options ] +.RB [ \-\-verbose | \-V ] +. +.PP +Use the +.B kms list +command to display secure keys managed by a key management system (KMS). +You can filter the displayed list by key label, key name, associated volumes, +and volume type. You can use wildcards for the key label, key name, and +associated volumes. The device-mapper name of an associated volume can be +omitted. If specified, then only those keys are listed that are associated +with the specified volume and device-mapper name. +.PP +A key management system plugin may offer plugin specific options that can be +specified with the \fBkms list\fP command. Use \fBkms list \-\-help\fP +to display the plugin specific options and their meaning. +.PP +The +.B kms list +command displays the attributes of the secure keys, such as key label, key name, +whether it is a secure key that can be used for the XTS cipher mode, the textual +description, associated volumes, the volume type, and sector size. +. . . .SH OPTIONS @@ -1685,6 +1720,42 @@ display the plugin specific options and their meaning. . . . +.SS "Options for the kms list command" +.TP +.BR \-B ", " \-\-label\~\fIkey-label\fP +Specifies the label of the secure key in the key management system (KMS). +You can use wildcards to select multiple secure keys. +When wildcards are used you must quote the value. +Only keys with labels that match the pattern are listed. +.TP +.BR \-N ", " \-\-name\~\fIkey-name\fP +Specifies the name of the secure key in the key management system (KMS). +You can use wildcards to select multiple secure keys. +When wildcards are used you must quote the value. +Only keys with names that match the pattern are listed. +This option is only used for secure keys contained in the secure key repository. +.TP +.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP +Specifies a comma-separated list of volumes (block devices) which are +associated with the secure AES key in the key management system (KMS). Only +those keys are listed, which are associated with the specified volumes. +The volume association also contains the device-mapper name, separated by a +colon, used with dm-crypt. You can omit the device-mapper name; if it is +specified then only those keys are listed that are associated with the +specified volume and device-mapper name. You can use wildcards to specify +the volumes and device-mapper names. +When wildcards are used you must quote the value. +.TP +.BR \-t ", " \-\-volume-type\~\fItype\fP +Specifies the volume type of the associated volumes used with dm-crypt. Possible +values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume +type are listed. +This option is only available if +.B zkey +has been compiled with LUKS2 support enabled. +. +. +. .SS "General options" .TP diff --git a/zkey/zkey.c b/zkey/zkey.c index 29dfd909..c17a00a1 100644 --- a/zkey/zkey.c +++ b/zkey/zkey.c @@ -76,6 +76,7 @@ static struct zkey_globals { char *volume_type; char *newname; char *key_type; + char *label; bool local; bool kms_bound; bool run; @@ -126,6 +127,7 @@ static struct zkey_globals { #define COMMAND_KMS_INFO "info" #define COMMAND_KMS_CONFIGURE "configure" #define COMMAND_KMS_REENCIPHER "reencipher" +#define COMMAND_KMS_LIST "list" #define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER" @@ -915,6 +917,50 @@ static struct util_opt opt_vec[] = { "staged mode per default.", .command = COMMAND_KMS " " COMMAND_KMS_REENCIPHER, }, + /***********************************************************/ + { + .flags = UTIL_OPT_FLAG_SECTION, + .desc = "OPTIONS", + .command = COMMAND_KMS " " COMMAND_KMS_LIST, + }, + { + .option = { "label", required_argument, NULL, 'B'}, + .argument = "LABEL", + .desc = "Label of the secure AES keys as known by the KMS that " + "are to be listed. You can use wildcards to select " + "the keys to be listed.", + .command = COMMAND_KMS " " COMMAND_KMS_LIST, + }, + { + .option = { "name", required_argument, NULL, 'N'}, + .argument = "NAME", + .desc = "Name of the secure AES keys as known by zkey that " + "are to be listed. You can use wildcards to select " + "the keys to be listed.", + .command = COMMAND_KMS " " COMMAND_KMS_LIST, + }, + { + .option = { "volumes", required_argument, NULL, 'l'}, + .argument = "VOLUME[:DMNAME][,...]", + .desc = "Comma-separated pairs of volume and device-mapper " + "names that are associated with the secure AES key in " + "the KMS. Use this option to list all keys " + "associated with specific volumes. The device-mapper " + "name (DMNAME) is optional. If specified, only those " + "keys are listed where both, the volume and the device-" + "mapper name matches.", + .command = COMMAND_KMS " " COMMAND_KMS_LIST, + }, +#ifdef HAVE_LUKS2_SUPPORT + { + .option = { "volume-type", required_argument, NULL, 't'}, + .argument = "type", + .desc = "The type of the associated volume(s). Possible values " + "are 'plain' and 'luks2'. Use this option to list all " + "keys with the specified volumes type.", + .command = COMMAND_KMS " " COMMAND_KMS_LIST, + }, +#endif /***********************************************************/ OPT_PLACEHOLDER, OPT_PLACEHOLDER, @@ -1016,6 +1062,7 @@ static int command_kms_unbind(void); static int command_kms_info(void); static int command_kms_configure(void); static int command_kms_reencipher(void); +static int command_kms_list(void); static struct zkey_command zkey_kms_commands[] = { { @@ -1089,6 +1136,20 @@ static struct zkey_command zkey_kms_commands[] = { .use_kms_plugin = 1, .kms_plugin_opts_cmd = KMS_COMMAND_REENCIPHER, }, + { + .command = COMMAND_KMS_LIST, + .abbrev_len = 2, + .function = command_kms_list, + .short_desc = "Lists secure keys managed by a key management " + "system", + .long_desc = "Lists secure keys managed by a key management " + "system (KMS)", + .need_keystore = 1, + .has_options = 1, + .use_kms_plugin = 1, + .need_kms_login = 1, + .kms_plugin_opts_cmd = KMS_COMMAND_LIST, + }, { .command = NULL } }; @@ -2448,6 +2509,28 @@ static int command_kms_reencipher(void) return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; } +/* + * Command handler for 'kms list'. + * + * List secure keys managed by a KMS + */ +static int command_kms_list(void) +{ + int rc; + + if (g.kms_info.plugin_lib == NULL) { + rc = -ENOENT; + warnx("The repository is not bound to a KMS plugin"); + return EXIT_FAILURE; + } + + rc = list_kms_keys(&g.kms_info, g.label, g.name, g.volumes, + g.volume_type, g.kms_options, g.num_kms_options, + g.verbose); + + return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} + /** * Opens the keystore. The keystore directory is either the * default directory or as specified in an environment variable @@ -2765,6 +2848,9 @@ int main(int argc, char *argv[]) case 'M': g.kms_bound = 1; break; + case 'B': + g.label = optarg; + break; case 'h': print_help(command, sub_command); return EXIT_SUCCESS;