From 3fa511cfb9c956ba3a62bdc87e21886d7dac66f7 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Wed, 3 Jun 2020 15:30:49 +0200 Subject: [PATCH] zkey: Support KMS plugin specific options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some commands requires additional options that are to be determined by the KMS plugin. Add support to let the KMS plugin provide an option vector per command, and add the options to the already existing command options. Signed-off-by: Ingo Franzki Signed-off-by: Jan Höppner --- zkey/kms.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++ zkey/kms.h | 10 ++++ zkey/zkey.c | 89 ++++++++++++++++++++++++++- 3 files changed, 267 insertions(+), 1 deletion(-) diff --git a/zkey/kms.c b/zkey/kms.c index f54a3365..214d2c08 100644 --- a/zkey/kms.c +++ b/zkey/kms.c @@ -53,6 +53,30 @@ typedef const struct kms_functions *(*kms_get_functions_t)(void); warnx(fmt); \ } while (0) +#define ARRAY_ADD(array, num_elemnts, element_size, new_element) \ + do { \ + (num_elemnts)++; \ + (array) = util_realloc((array), \ + (num_elemnts) * element_size); \ + memcpy(&(array)[(num_elemnts) - 1], new_element, \ + element_size); \ + } while (0) + +#define ARRAY_REMOVE(array, num_elemnts, element_size, index) \ + do { \ + if ((index) < (num_elemnts) - 1) \ + memmove(&(array)[(index)], \ + &(array)[(index) + 1], \ + ((num_elemnts) - (index) - 1) * \ + element_size); \ + (num_elemnts)--; \ + if ((num_elemnts) > 0) { \ + (array) = util_realloc((array), \ + (num_elemnts) * element_size); \ + } \ + } while (0) + + /** * Opens kms-plugins.conf. Looks for the file in /etc/zkey/, or if environment * variable ZKEY_KMS_PLUGINS is set then it uses the file name and path @@ -812,3 +836,148 @@ kms_info: out: return rc; } + +/** + * Gets the KMS plugin command specific option vector and puts them into the + * placeholder slots in opt_vec. + * + * @param[in] kms_info information of the currently bound plugin. + * @param[in] opt_vec the option vector to modify. + * @param[in] placeholder_cmd the command with which the placeholder option + * vector entries are marked + * @param[in] plugin_command the plugin command to get the options for + * @param[in] opt_vec_command the command to use in the option vector entries + * @param[out] first_plugin_opt on return: the index of the first plugin option + * in opt_vec, or -1 if no plugin options are used. + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 for success or a negative errno in case of an error. + */ +int get_kms_options(struct kms_info *kms_info, struct util_opt *opt_vec, + const char *placeholder_cmd, const char *plugin_command, + const char *opt_vec_command, int *first_plugin_opt, + bool verbose) +{ + const struct util_opt *plugin_opts; + int i, k, first = 0, num_slots = 0; + + util_assert(kms_info != NULL, "Internal error: kms_info is NULL"); + util_assert(opt_vec != NULL, "Internal error: opt_vec is NULL"); + util_assert(placeholder_cmd != NULL, + "Internal error: placeholder_cmd is NULL"); + util_assert(plugin_command != NULL, + "Internal error: plugin_command is NULL"); + util_assert(first_plugin_opt != NULL, + "Internal error: first_plugin_opt is NULL"); + + *first_plugin_opt = -1; + + if (kms_info->plugin_lib == NULL) { + pr_verbose(verbose, "not bound to a KMS plugin"); + return 0; + } + + if (kms_info->funcs->kms_get_command_options == NULL) { + pr_verbose(verbose, "Plugin does not support command options"); + return 0; + } + + if (strcmp(plugin_command, KMS_COMMAND_CONFIGURE) != 0 && + strcmp(plugin_command, KMS_COMMAND_REENCIPHER) != 0 && + strcmp(plugin_command, KMS_COMMAND_GENERATE) != 0 && + strcmp(plugin_command, KMS_COMMAND_REMOVE) != 0 && + strcmp(plugin_command, KMS_COMMAND_LIST) != 0 && + strcmp(plugin_command, KMS_COMMAND_LIST_IMPORT) != 0) { + pr_verbose(verbose, "Command %s is not eligible for plugin " + "options", plugin_command); + return 0; + } + + for (i = 0; opt_vec[i].desc != NULL; i++) { + if (opt_vec[i].command != NULL && + strcmp(opt_vec[i].command, placeholder_cmd) == 0) { + if (first == 0) + first = i; + num_slots++; + } + } + + pr_verbose(verbose, "%u placeholder slots found", num_slots); + + plugin_opts = kms_info->funcs->kms_get_command_options(plugin_command, + num_slots); + if (plugin_opts == NULL) { + pr_verbose(verbose, "No plugin options for command %s", + plugin_command); + return 0; + } + + for (k = 0, i = first; plugin_opts[k].desc != NULL && + i < first + num_slots; i++, k++) { + memcpy(&opt_vec[i], &plugin_opts[k], sizeof(struct util_opt)); + opt_vec[i].command = (char *)opt_vec_command; + } + + pr_verbose(verbose, "%u plugin options", k); + + *first_plugin_opt = first; + + return 0; +} + +/** + * Checks if the option is a KMS plugin specific option and if so, adds it to + * list of KMS options. If the option is not handled by the plugin, then + * -ENOENT is returned. + * + * @param[in] kms_info information of the currently bound plugin. + * @param[in] opt_vec the option vector. + * @param[in] first_kms_option index of first KMS option in opt_vec + * @param[in] command the plugin command to handle + * @param[in] option the option character to handle + * @param[in] optarg the option argument or NULL + * @param[out] kms_options on return: an array of KMS options handled. The + * array is resized to add more options. + * @param[out] num_kms_options on return: 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 handle_kms_option(struct kms_info *kms_info, struct util_opt *opt_vec, + int first_kms_option, const char *command, int option, + const char *optarg, struct kms_option **kms_options, + size_t *num_kms_options, bool verbose) +{ + struct kms_option opt = { .option = option, .argument = optarg }; + int i; + + util_assert(kms_info != NULL, "Internal error: kms_info is NULL"); + util_assert(opt_vec != NULL, "Internal error: opt_vec is NULL"); + util_assert(command != NULL, "Internal error: command is NULL"); + util_assert(kms_options != NULL, "Internal error: kms_options is NULL"); + util_assert(num_kms_options != NULL, + "Internal error: num_kms_options is NULL"); + + if (kms_info->plugin_lib == NULL) { + pr_verbose(verbose, "not bound to a KMS plugin"); + return -ENOENT; + } + + if (first_kms_option < 0) { + pr_verbose(verbose, "No plugin specific options"); + return -ENOENT; + } + + for (i = first_kms_option; opt_vec[i].command != NULL && + strcmp(opt_vec[i].command, command) == 0; i++) { + if ((opt_vec[i].flags & UTIL_OPT_FLAG_SECTION) == 0 && + opt_vec[i].option.val == option) { + ARRAY_ADD(*kms_options, *num_kms_options, + sizeof(struct kms_option), &opt); + return 0; + } + } + + return -ENOENT; +} diff --git a/zkey/kms.h b/zkey/kms.h index 467c73ea..5a2ab1c0 100644 --- a/zkey/kms.h +++ b/zkey/kms.h @@ -47,4 +47,14 @@ int unbind_kms_plugin(struct kms_info *kms_info, struct keystore *keystore, int print_kms_info(struct kms_info *kms_info); +int get_kms_options(struct kms_info *kms_info, struct util_opt *opt_vec, + const char *placeholder_cmd, const char *plugin_command, + const char *opt_vec_command, int *first_plugin_opt, + bool verbose); + +int handle_kms_option(struct kms_info *kms_info, struct util_opt *opt_vec, + int first_kms_option, const char *command, int option, + const char *optarg, struct kms_option **kms_options, + size_t *num_kms_options, bool verbose); + #endif diff --git a/zkey/zkey.c b/zkey/zkey.c index 19cc0e75..ab1ce5ac 100644 --- a/zkey/zkey.c +++ b/zkey/zkey.c @@ -93,6 +93,9 @@ static struct zkey_globals { int pkey_fd; struct keystore *keystore; struct kms_info kms_info; + int first_kms_option; + struct kms_option *kms_options; + size_t num_kms_options; } g = { .pkey_fd = -1, .sector_size = -1, @@ -122,6 +125,15 @@ static struct zkey_globals { #define COMMAND_KMS_UNBIND "unbind" #define COMMAND_KMS_INFO "info" +#define OPT_COMMAND_PLACEHOLDER "PLACEHOLDER" + +#define OPT_PLACEHOLDER \ +{ \ + .option = { "", 0, NULL, ' ' }, \ + .desc = OPT_COMMAND_PLACEHOLDER, \ + .command = OPT_COMMAND_PLACEHOLDER, \ +} + #define ZKEY_COMMAND_MAX_LEN 10 #define ENVVAR_ZKEY_REPOSITORY "ZKEY_REPOSITORY" @@ -824,6 +836,47 @@ static struct util_opt opt_vec[] = { .command = COMMAND_CONVERT, }, /***********************************************************/ + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + OPT_PLACEHOLDER, + /***********************************************************/ { .flags = UTIL_OPT_FLAG_SECTION, .desc = "COMMON OPTIONS" @@ -859,6 +912,7 @@ struct zkey_command { char **arg_alternate_value; int need_keystore; int use_kms_plugin; + char *kms_plugin_opts_cmd; struct zkey_command *sub_commands; }; @@ -2253,7 +2307,6 @@ int main(int argc, char *argv[]) int rc, c; util_prg_init(&prg); - util_opt_init(opt_vec, NULL); /* Get command and subcommand if one is specified */ if (arg_count >= 2 && strncmp(args[1], "-", 1) != 0) { @@ -2305,12 +2358,44 @@ int main(int argc, char *argv[]) rc = check_for_kms_plugin(&g.kms_info, g.verbose); if (rc != 0) return EXIT_FAILURE; + + if (cmd->kms_plugin_opts_cmd) { + rc = get_kms_options(&g.kms_info, opt_vec, + OPT_COMMAND_PLACEHOLDER, + cmd->kms_plugin_opts_cmd, + sub_command != NULL ? + command_str : cmd->command, + &g.first_kms_option, + g.verbose); + if (rc != 0) + return EXIT_FAILURE; + } } + util_opt_init(opt_vec, NULL); + while (1) { c = util_opt_getopt_long(arg_count, args); if (c == -1) break; + + if (cmd != NULL && cmd->kms_plugin_opts_cmd) { + rc = handle_kms_option(&g.kms_info, opt_vec, + g.first_kms_option, + sub_command != NULL ? + command_str : cmd->command, + c, optarg, &g.kms_options, + &g.num_kms_options, g.verbose); + if (rc != 0 && rc != -ENOENT) { + warnx("Failed to process KMS plugin option: " + "'%c': %s", c, strerror(-rc)); + return EXIT_FAILURE; + } + + if (rc == 0) + continue; + } + switch (c) { case 'x': g.xts = 1; @@ -2532,5 +2617,7 @@ out: close(g.pkey_fd); if (g.keystore) keystore_free(g.keystore); + if (g.kms_options != NULL) + free(g.kms_options); return rc; }