zkey: Add KMS key properties and show them with list and validate

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 <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2020-06-03 11:01:31 +02:00
committed by Jan Höppner
parent f25aaf32b8
commit 92fc94f152
5 changed files with 224 additions and 36 deletions

View File

@@ -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);

View File

@@ -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 <stdbool.h>
#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,

View File

@@ -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);

View File

@@ -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.
.
.
.

View File

@@ -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;