From 92fc94f15281bb326eafb5fb4e9f7b815d7e4fa8 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Wed, 3 Jun 2020 11:01:31 +0200 Subject: [PATCH] zkey: Add KMS key properties and show them with list and validate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support keys that are bound to a key management system (via a KMS plugin) add new key properties that reflect this. Display if a key is bound to a KMS with the 'zkey list' and 'zkey validate' commands. Signed-off-by: Ingo Franzki Signed-off-by: Jan Höppner --- zkey/keystore.c | 153 ++++++++++++++++++++++++++++++++++++++++-------- zkey/keystore.h | 30 +++++++++- zkey/kms.h | 2 + zkey/zkey.1 | 42 +++++++++++-- zkey/zkey.c | 33 ++++++++++- 5 files changed, 224 insertions(+), 36 deletions(-) diff --git a/zkey/keystore.c b/zkey/keystore.c index 76a17785..a0656876 100644 --- a/zkey/keystore.c +++ b/zkey/keystore.c @@ -3,7 +3,7 @@ * * Keystore handling functions * - * Copyright IBM Corp. 2018, 2019 + * Copyright IBM Corp. 2018, 2020 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -49,19 +49,6 @@ struct key_filenames { #define LOCK_FILE_NAME ".lock" -#define PROP_NAME_KEY_TYPE "key-type" -#define PROP_NAME_CIPHER "cipher" -#define PROP_NAME_IV_MODE "iv-mode" -#define PROP_NAME_DESCRIPTION "description" -#define PROP_NAME_VOLUMES "volumes" -#define PROP_NAME_APQNS "apqns" -#define PROP_NAME_SECTOR_SIZE "sector-size" -#define PROP_NAME_CREATION_TIME "creation-time" -#define PROP_NAME_CHANGE_TIME "update-time" -#define PROP_NAME_REENC_TIME "reencipher-time" -#define PROP_NAME_KEY_VP "verification-pattern" -#define PROP_NAME_VOLUME_TYPE "volume-type" - #define VOLUME_TYPE_PLAIN "plain" #define VOLUME_TYPE_LUKS2 "luks2" #ifdef HAVE_LUKS2_SUPPORT @@ -87,6 +74,8 @@ struct key_filenames { #define REC_REENC_TIME "Re-enciphered" #define REC_KEY_VP "Verification pattern" #define REC_VOLUME_TYPE "Volume type" +#define REC_KMS "KMS" +#define REC_KMS_KEY_LABEL "KMS key label" #define pr_verbose(keystore, fmt...) do { \ if (keystore->verbose) \ @@ -349,6 +338,35 @@ static int _keystore_valid_key_type(const char *key_type) return 0; } +/** + * Checks if the keys is KMS-bound + * + * @param[in] key_props the key properties + * @param[out] kms_name the name of the KMS plugin, if KMS-bound + * + * @return true if the key is KMS bound, false otherwise + */ +static bool _keystore_is_kms_bound_key(struct properties *key_props, + char **kms_name) +{ + bool ret = false; + char *kms; + + if (kms_name != NULL) + *kms_name = NULL; + + kms = properties_get(key_props, PROP_NAME_KMS); + if (kms != NULL && strcasecmp(kms, "LOCAL") != 0) + ret = true; + + if (kms_name != NULL && ret == true) + *kms_name = kms; + else if (kms != NULL) + free(kms); + + return ret; +} + /** * Prints a message followed by a list of associated volumes, if volumes are * associated and the volume-type matches (if specified) @@ -945,6 +963,8 @@ typedef int (*process_key_t)(struct keystore *keystore, * NULL means no APQN filter. * @param[in] volume_type If not NULL, specifies the volume type. * @param[in] key_type The key type. NULL means no key type filter. + * @param[in] local if true, only local keys are processed + * @param[in] kms_bound if true, only KMS-bound keys are processed * @param[in] process_func the callback function called for a matching key * @param[in/out] process_private private data passed to the process_func * @@ -958,6 +978,7 @@ static int _keystore_process_filtered(struct keystore *keystore, const char *apqn_filter, const char *volume_type, const char *key_type, + bool local, bool kms_bound, process_key_t process_func, void *process_private) { @@ -1058,6 +1079,21 @@ static int _keystore_process_filtered(struct keystore *keystore, goto free_prop; } + if (local && _keystore_is_kms_bound_key(key_props, NULL)) { + pr_verbose(keystore, + "Key '%s' filtered out because it is KMS " + "bound", name); + rc = 0; + goto free_prop; + } + if (kms_bound && !_keystore_is_kms_bound_key(key_props, NULL)) { + pr_verbose(keystore, + "Key '%s' filtered out because it is not " + "KMS bound", name); + rc = 0; + goto free_prop; + } + rc = process_func(keystore, name, key_props, &file_names, process_private); if (rc != 0) { @@ -1270,7 +1306,7 @@ static int _keystore_volume_check(const char *volume, bool remove, bool set, info->set = set; rc = _keystore_process_filtered(info->keystore, NULL, info->volume, - NULL, NULL, NULL, + NULL, NULL, NULL, false, false, _keystore_volume_check_process, info); out: free((void *)info->volume); @@ -1365,11 +1401,13 @@ static int _keystore_unlock_repository(struct keystore *keystore) * Allocates new keystore object * * @param[in] directory the directory where the keystore resides + * @param[in] kms_info KMS plugin info * @param[in] verbose if true, verbose messages are printed * * @returns a new keystore object */ -struct keystore *keystore_new(const char *directory, bool verbose) +struct keystore *keystore_new(const char *directory, + struct kms_info *kms_info, bool verbose) { struct keystore *keystore; struct stat sb; @@ -1408,6 +1446,8 @@ struct keystore *keystore_new(const char *directory, bool verbose) if (keystore->directory[strlen(keystore->directory)-1] == '/') keystore->directory[strlen(keystore->directory)-1] = '\0'; + keystore->kms_info = kms_info; + rc = _keystore_lock_repository(keystore); if (rc != 0) { keystore_free(keystore); @@ -1566,6 +1606,7 @@ static int _keystore_set_default_properties(struct properties *key_props) * default is used. * @param[in] volume_type the type of volume * @param[in] key_type the type of the key + * @param[in] kms the name of the KMS plugin, or NULL if no KMS is bound */ static int _keystore_create_info_file(struct keystore *keystore, const char *name, @@ -1575,7 +1616,8 @@ static int _keystore_create_info_file(struct keystore *keystore, bool noapqncheck, size_t sector_size, const char *volume_type, - const char *key_type) + const char *key_type, + const char *kms) { struct volume_check vol_check = { .keystore = keystore, .name = name, .set = 0 }; @@ -1646,6 +1688,14 @@ static int _keystore_create_info_file(struct keystore *keystore, goto out; } + if (kms != NULL) { + rc = properties_set(key_props, PROP_NAME_KMS, kms); + if (rc != 0) { + warnx("Invalid characters in KMS"); + goto out; + } + } + rc = _keystore_ensure_vp_exists(keystore, filenames, key_props); if (rc != 0) { warnx("Failed to generate the key verification pattern: %s", @@ -1768,7 +1818,7 @@ int keystore_generate_key(struct keystore *keystore, const char *name, rc = _keystore_create_info_file(keystore, name, &file_names, description, volumes, apqns, noapqncheck, sector_size, volume_type, - key_type); + key_type, NULL); if (rc != 0) goto out_free_props; @@ -1936,7 +1986,7 @@ int keystore_import_key(struct keystore *keystore, const char *name, rc = _keystore_create_info_file(keystore, name, &file_names, description, volumes, apqns, noapqncheck, sector_size, volume_type, - key_type); + key_type, NULL); if (rc != 0) goto out_free_props; @@ -2272,6 +2322,9 @@ static struct util_rec *_keystore_setup_record(bool validation) util_rec_def(rec, REC_VOLUME_TYPE, UTIL_REC_ALIGN_LEFT, 54, REC_VOLUME_TYPE); util_rec_def(rec, REC_KEY_VP, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_VP); + util_rec_def(rec, REC_KMS, UTIL_REC_ALIGN_LEFT, 54, REC_KMS); + util_rec_def(rec, REC_KMS_KEY_LABEL, UTIL_REC_ALIGN_LEFT, 54, + REC_KMS_KEY_LABEL); util_rec_def(rec, REC_CREATION_TIME, UTIL_REC_ALIGN_LEFT, 54, REC_CREATION_TIME); util_rec_def(rec, REC_CHANGE_TIME, UTIL_REC_ALIGN_LEFT, 54, @@ -2291,9 +2344,14 @@ static void _keystore_print_record(struct util_rec *rec, bool is_old_mk, bool reenc_pending, u8 *mkvp) { char temp_vp[VERIFICATION_PATTERN_LEN + 2]; + char *kms_xts_key1_label = NULL; + char *kms_xts_key2_label = NULL; + char *kms_key_label = NULL; char *volumes_argz = NULL; + size_t label_argz_len = 0; size_t volumes_argz_len; char *apqns_argz = NULL; + char *label_argz = NULL; size_t sector_size = 0; size_t apqns_argz_len; char *description; @@ -2305,6 +2363,7 @@ static void _keystore_print_record(struct util_rec *rec, char *change; char *apqns; char *temp; + char *kms; char *vp; int len; @@ -2335,6 +2394,30 @@ static void _keystore_print_record(struct util_rec *rec, vp = properties_get(properties, PROP_NAME_KEY_VP); volume_type = _keystore_get_volume_type(properties); key_type = properties_get(properties, PROP_NAME_KEY_TYPE); + if (_keystore_is_kms_bound_key(properties, &kms)) { + if (is_xts) { + kms_xts_key1_label = properties_get(properties, + PROP_NAME_KMS_XTS_KEY1_LABEL); + kms_xts_key2_label = properties_get(properties, + PROP_NAME_KMS_XTS_KEY2_LABEL); + + if (kms_xts_key1_label != NULL && + kms_xts_key2_label != NULL) { + label_argz_len = util_asprintf(&label_argz, + "%s%c%s", kms_xts_key1_label, '\0', + kms_xts_key2_label) + 1; + } + } else { + kms_key_label = properties_get(properties, + PROP_NAME_KMS_KEY_LABEL); + + if (kms_key_label != NULL) { + label_argz = kms_key_label; + label_argz_len = strlen(label_argz) + 1; + kms_key_label = NULL; + } + } + } util_rec_set(rec, REC_KEY, name); if (validation) @@ -2389,7 +2472,13 @@ static void _keystore_print_record(struct util_rec *rec, util_rec_set_argz(rec, REC_KEY_VP, temp_vp, len + 1); } else { util_rec_set(rec, REC_KEY_VP, "(not available)"); - } + } + util_rec_set(rec, REC_KMS, kms != NULL ? kms : "(local)"); + if (kms != NULL && label_argz != NULL) + util_rec_set_argz(rec, REC_KMS_KEY_LABEL, label_argz, + label_argz_len); + else + util_rec_set(rec, REC_KMS_KEY_LABEL, "(local)"); util_rec_set(rec, REC_CREATION_TIME, creation); util_rec_set(rec, REC_CHANGE_TIME, change != NULL ? change : "(never)"); @@ -2421,6 +2510,16 @@ static void _keystore_print_record(struct util_rec *rec, free(volume_type); if (key_type != NULL) free(key_type); + if (kms != NULL) + free(kms); + if (kms_key_label != NULL) + free(kms_key_label); + if (kms_xts_key1_label != NULL) + free(kms_xts_key1_label); + if (kms_xts_key2_label != NULL) + free(kms_xts_key2_label); + if (label_argz != NULL) + free(label_argz); } struct validate_info { @@ -2641,7 +2740,7 @@ int keystore_validate_key(struct keystore *keystore, const char *name_filter, info.num_warnings = 0; rc = _keystore_process_filtered(keystore, name_filter, NULL, - apqn_filter, NULL, NULL, + apqn_filter, NULL, NULL, false, false, _keystore_process_validate, &info); util_rec_free(rec); @@ -3009,7 +3108,7 @@ int keystore_reencipher_key(struct keystore *keystore, const char *name_filter, info.num_skipped = 0; rc = _keystore_process_filtered(keystore, name_filter, NULL, - apqn_filter, NULL, NULL, + apqn_filter, NULL, NULL, false, false, _keystore_process_reencipher, &info); if (rc != 0) { @@ -3383,12 +3482,15 @@ out: * NULL means no APQN filter. * @param[in] volume_type The volume type. NULL means no volume type filter. * @param[in] key_type The key type. NULL means no key type filter. + * @param[in] local if true, only local keys are listed + * @param[in] kms_bound if true, only KMS-bound keys are listed * * @returns 0 for success or a negative errno in case of an error */ int keystore_list_keys(struct keystore *keystore, const char *name_filter, const char *volume_filter, const char *apqn_filter, - const char *volume_type, const char *key_type) + const char *volume_type, const char *key_type, + bool local, bool kms_bound) { struct util_rec *rec; int rc; @@ -3411,6 +3513,7 @@ int keystore_list_keys(struct keystore *keystore, const char *name_filter, rc = _keystore_process_filtered(keystore, name_filter, volume_filter, apqn_filter, volume_type, key_type, + local, kms_bound, _keystore_display_key, rec); util_rec_free(rec); @@ -3872,7 +3975,7 @@ int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter, info.process_func = _keystore_process_cryptsetup; rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL, - volume_type, NULL, + volume_type, NULL, false, false, _keystore_process_crypt, &info); str_list_free_string_array(info.volume_filter); @@ -3933,7 +4036,7 @@ int keystore_crypttab(struct keystore *keystore, const char *volume_filter, info.process_func = _keystore_process_crypttab; rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL, - volume_type, NULL, + volume_type, NULL, false, false, _keystore_process_crypt, &info); str_list_free_string_array(info.volume_filter); diff --git a/zkey/keystore.h b/zkey/keystore.h index d9528144..0f7e0b11 100644 --- a/zkey/keystore.h +++ b/zkey/keystore.h @@ -3,7 +3,7 @@ * * Keystore handling functions * - * Copyright IBM Corp. 2018 + * Copyright IBM Corp. 2018, 2020 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -15,6 +15,7 @@ #include #include "pkey.h" +#include "kms.h" struct keystore { bool verbose; @@ -22,9 +23,31 @@ struct keystore { int lock_fd; mode_t mode; gid_t owner; + struct kms_info *kms_info; }; -struct keystore *keystore_new(const char *directory, bool verbose); +#define PROP_NAME_KEY_TYPE "key-type" +#define PROP_NAME_CIPHER "cipher" +#define PROP_NAME_IV_MODE "iv-mode" +#define PROP_NAME_DESCRIPTION "description" +#define PROP_NAME_VOLUMES "volumes" +#define PROP_NAME_APQNS "apqns" +#define PROP_NAME_SECTOR_SIZE "sector-size" +#define PROP_NAME_CREATION_TIME "creation-time" +#define PROP_NAME_CHANGE_TIME "update-time" +#define PROP_NAME_REENC_TIME "reencipher-time" +#define PROP_NAME_KEY_VP "verification-pattern" +#define PROP_NAME_VOLUME_TYPE "volume-type" +#define PROP_NAME_KMS "kms" +#define PROP_NAME_KMS_KEY_ID "kms-key-id" +#define PROP_NAME_KMS_KEY_LABEL "kms-key-label" +#define PROP_NAME_KMS_XTS_KEY1_ID "kms-xts-key1-id" +#define PROP_NAME_KMS_XTS_KEY1_LABEL "kms-xts-key1-label" +#define PROP_NAME_KMS_XTS_KEY2_ID "kms-xts-key2-id" +#define PROP_NAME_KMS_XTS_KEY2_LABEL "kms-xts-key2-label" + +struct keystore *keystore_new(const char *directory, + struct kms_info *kms_info, bool verbose); int keystore_generate_key(struct keystore *keystore, const char *name, const char *description, const char *volumes, @@ -68,7 +91,8 @@ int keystore_remove_key(struct keystore *keystore, const char *name, int keystore_list_keys(struct keystore *keystore, const char *name_filter, const char *volume_filter, const char *apqn_filter, - const char *volume_type, const char *key_type); + const char *volume_type, const char *key_type, + bool local, bool kms_bound); int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter, bool execute, const char *volume_type, diff --git a/zkey/kms.h b/zkey/kms.h index 86c1fd05..59bed625 100644 --- a/zkey/kms.h +++ b/zkey/kms.h @@ -27,6 +27,8 @@ struct kms_info { kms_handle_t handle; }; +struct keystore; + int list_kms_plugins(bool verbose); int check_for_kms_plugin(struct kms_info *kms_info, bool verbose); diff --git a/zkey/zkey.1 b/zkey/zkey.1 index d0220447..48dfec11 100644 --- a/zkey/zkey.1 +++ b/zkey/zkey.1 @@ -1,8 +1,8 @@ -.\" Copyright IBM Corp. 2017, 2018 +.\" Copyright IBM Corp. 2017, 2020 .\" s390-tools is free software; you can redistribute it and/or modify .\" it under the terms of the MIT license. See LICENSE for details. .\" -.TH ZKEY 1 "May 2018" "s390-tools" +.TH ZKEY 1 "July 2020" "s390-tools" .SH NAME zkey \- Manage secure AES keys . @@ -56,6 +56,17 @@ length of 128, or 256 bits each, for keys that are used for the XTS cipher mode. Note that the file size is not related to the key bit size, but is specific for the secure key type. The key is enciphered with the master key of the CCA or EP11 cryptographic adapter. +.PP +Secure keys in a key repository can either be generated locally, or by a \fBkey +management system (KMS)\fP. A key repository can be bound to a key management +system (KMS) via a key management system plugin (KMS plugin), which builds the +interface to the key management system. This allows to integrate a zkey key +repository into an enterprise key management system, that manages the keys in +a larger environment. +When a key repository is bound to a key management system, then all keys are +generated by the key management system per default, and are thus also bound to +the key management system. Any additional information associated with the keys +in the repository is also stored in the key management system. . . . @@ -402,6 +413,8 @@ The exported secure key also remains in the secure key repository. .IR type ] .RB [ \-\-key-type | \-K .IR type ] +.RB [ \-\-local | \-L ] +.RB [ \-\-kms\-bound | \-M ] .RB [ \-\-verbose | \-V ] . .PP @@ -409,8 +422,9 @@ Use the .B list command to display a list of secure keys contained in the secure key repository. You can filter the displayed list by key name, associated volumes, associated -cryptographic adapters (APQNs), and volume type. You can use wildcards for the -key name, associated APQNs, and associated volumes. The device-mapper name of an +cryptographic adapters (APQNs), volume type, and whether the keys are local or +bound to a key management system (MKS). You can use wildcards for the key name, +associated APQNs, and associated volumes. The device-mapper name of an associated volume can be omitted; if it is specified then only those keys are listed that are associated with the specified volume and device-mapper name. .PP @@ -419,8 +433,9 @@ The command displays the attributes of the secure keys, such as key sizes, key type, whether it is a secure key that can be used for the XTS cipher mode, the textual description, associated cryptographic adapters (APQNs) and volumes, the -sector size, the key verification pattern, and timestamps for key creation, last -modification and last re-encipherment. +sector size, the key verification pattern, timestamps for key creation, last +modification and last re-encipherment, and whether the key is local or +bound to a key management systen (KMS). . .SS "Remove existing AES secure keys from the secure key repository" . @@ -1024,6 +1039,21 @@ Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP, \fBCCA-AESCIPHER\fP, and \fBEP11-AES\fP. Only keys with the specified key type are listed. This option is only used for secure keys contained in the secure key repository. +.TP +.BR \-L ", " \-\-local\fP +Lists only local keys. Local keys are not bound to a key management system +(KMS). +This option is only used for secure keys contained in the secure key repository, +and can not be specified together with the +.BR \-\-kms\-bound +option. +.TP +.BR \-M ", " \-\-kms\-bound\fP +Lists only keys that are bound to a key management system (KMS). +This option is only used for secure keys contained in the secure key repository, +and can not be specified together with the +.BR \-\-local +option. . . . diff --git a/zkey/zkey.c b/zkey/zkey.c index 74e35cd8..2add12f4 100644 --- a/zkey/zkey.c +++ b/zkey/zkey.c @@ -75,6 +75,8 @@ static struct zkey_globals { char *volume_type; char *newname; char *key_type; + bool local; + bool kms_bound; bool run; bool batch_mode; char *keyfile; @@ -89,6 +91,7 @@ static struct zkey_globals { struct ep11_lib ep11; int pkey_fd; struct keystore *keystore; + struct kms_info kms_info; } g = { .pkey_fd = -1, .sector_size = -1, @@ -457,6 +460,18 @@ static struct util_opt opt_vec[] = { "all keys with the specified key type.", .command = COMMAND_LIST, }, + { + .option = { "local", 0, NULL, 'L'}, + .desc = "List local keys only. Local keys are not bound to a " + "KMS plugin.", + .command = COMMAND_LIST, + }, + { + .option = { "kms-bound", 0, NULL, 'M'}, + .desc = "List KMS-bound keys only. KMS-bound keys are bound to " + "a KMS plugin.", + .command = COMMAND_LIST, + }, /***********************************************************/ { .flags = UTIL_OPT_FLAG_SECTION, @@ -1640,8 +1655,16 @@ static int command_list(void) { int rc; + if (g.local && g.kms_bound) { + warnx("Either '--local|-L' or '--kms-bound|-M' can be " + "specified, but not both"); + util_prg_print_parse_error(); + return EXIT_FAILURE; + } + rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns, - g.volume_type, g.key_type); + g.volume_type, g.key_type, g.local, + g.kms_bound); return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; } @@ -1991,7 +2014,7 @@ static int open_keystore(void) if (directory == NULL) directory = DEFAULT_KEYSTORE; - g.keystore = keystore_new(directory, g.verbose); + g.keystore = keystore_new(directory, &g.kms_info, g.verbose); return g.keystore == NULL ? EXIT_FAILURE : EXIT_SUCCESS; } @@ -2253,6 +2276,12 @@ int main(int argc, char *argv[]) g.format = 1; break; #endif + case 'L': + g.local = 1; + break; + case 'M': + g.kms_bound = 1; + break; case 'h': print_help(command, sub_command); return EXIT_SUCCESS;