forked from pool/s390-tools
a7f8ed0265
Lots of features implemented for SLES15 SP1. OBS-URL: https://build.opensuse.org/request/show/648783 OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=57
350 lines
12 KiB
Diff
350 lines
12 KiB
Diff
Subject: zkey: Add key verification pattern property
|
|
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
|
|
|
Summary: zkey: Support CCA master key change with LUKS2 volumes using paes
|
|
Description: Support the usage of protected key crypto for dm-crypt disks in
|
|
LUKS2 format by providing a tool allowing to re-encipher a
|
|
secure LUKS2 volume key when the CCA master key is changed
|
|
Upstream-ID: 512b47c0042a3cdedafce8d46dcc76053298116c
|
|
Problem-ID: SEC1424.1
|
|
|
|
Upstream-Description:
|
|
|
|
zkey: Add key verification pattern property
|
|
|
|
Store a verification pattern in the properties file along
|
|
with the secure key. The verification pattern allows to identify
|
|
the inner key even when the secure key is no longer valid.
|
|
|
|
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
|
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
|
|
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
|
|
|
|
|
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
|
---
|
|
zkey/keystore.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
|
zkey/zkey.1 | 4 -
|
|
zkey/zkey.c | 27 +++++++++--
|
|
3 files changed, 145 insertions(+), 18 deletions(-)
|
|
|
|
--- a/zkey/keystore.c
|
|
+++ b/zkey/keystore.c
|
|
@@ -58,6 +58,7 @@ struct key_filenames {
|
|
#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 IS_XTS(secure_key_size) (secure_key_size > SECURE_KEY_SIZE ? 1 : 0)
|
|
|
|
@@ -75,6 +76,7 @@ struct key_filenames {
|
|
#define REC_CREATION_TIME "Created"
|
|
#define REC_CHANGE_TIME "Changed"
|
|
#define REC_REENC_TIME "Re-enciphered"
|
|
+#define REC_KEY_VP "Verification pattern"
|
|
|
|
#define pr_verbose(keystore, fmt...) do { \
|
|
if (keystore->verbose) \
|
|
@@ -1270,6 +1272,77 @@ struct keystore *keystore_new(const char
|
|
}
|
|
|
|
/**
|
|
+ * Generate the key verification pattern from the specified secure key file
|
|
+ *
|
|
+ * @param[in] keystore the key store
|
|
+ * @param[in} keyfile the key file
|
|
+ * @param[in] vp buffer filled with the verification pattern
|
|
+ * @param[in] vp_len length of the buffer. Must be at
|
|
+ * least VERIFICATION_PATTERN_LEN bytes in size.
|
|
+ *
|
|
+ * @returns 0 for success or a negative errno in case of an error
|
|
+ */
|
|
+static int _keystore_generate_verification_pattern(struct keystore *keystore,
|
|
+ const char *keyfile,
|
|
+ char *vp, size_t vp_len)
|
|
+{
|
|
+ size_t key_size;
|
|
+ u8 *key;
|
|
+ int rc;
|
|
+
|
|
+ util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
|
+ util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
|
|
+ util_assert(vp != NULL, "Internal error: vp is NULL");
|
|
+
|
|
+ key = read_secure_key(keyfile, &key_size, keystore->verbose);
|
|
+ if (key == NULL)
|
|
+ return -EIO;
|
|
+
|
|
+ rc = generate_key_verification_pattern((const char *)key, key_size,
|
|
+ vp, vp_len, keystore->verbose);
|
|
+
|
|
+ free(key);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Checks if the key verification pattern property exists. If not, then it is
|
|
+ * created from the secure key.
|
|
+ *
|
|
+ * @param[in] keystore the key store
|
|
+ * @param[in] file_names the file names of the key
|
|
+ * @param[in] key_props the properties of the key
|
|
+ *
|
|
+ * @returns 0 for success or a negative errno in case of an error
|
|
+ */
|
|
+static int _keystore_ensure_vp_exists(struct keystore *keystore,
|
|
+ const struct key_filenames *file_names,
|
|
+ struct properties *key_props)
|
|
+{
|
|
+ char vp[VERIFICATION_PATTERN_LEN];
|
|
+ char *temp;
|
|
+ int rc;
|
|
+
|
|
+ temp = properties_get(key_props, PROP_NAME_KEY_VP);
|
|
+ if (temp != NULL) {
|
|
+ free(temp);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ rc = _keystore_generate_verification_pattern(keystore,
|
|
+ file_names->skey_filename,
|
|
+ vp, sizeof(vp));
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
+ rc = properties_set(key_props, PROP_NAME_KEY_VP, vp);
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
* Sets a timestamp to be used as creation/update/reencipher time into
|
|
* the specified property
|
|
*
|
|
@@ -1348,7 +1421,7 @@ static int _keystore_set_default_propert
|
|
*/
|
|
static int _keystore_create_info_file(struct keystore *keystore,
|
|
const char *name,
|
|
- const char *info_filename,
|
|
+ const struct key_filenames *filenames,
|
|
const char *description,
|
|
const char *volumes, const char *apqns,
|
|
size_t sector_size)
|
|
@@ -1396,17 +1469,26 @@ static int _keystore_create_info_file(st
|
|
goto out;
|
|
}
|
|
|
|
- rc = properties_save(key_props, info_filename, 1);
|
|
+ rc = _keystore_ensure_vp_exists(keystore, filenames, key_props);
|
|
+ if (rc != 0) {
|
|
+ warnx("Failed to generate the key verification pattern: %s",
|
|
+ strerror(-rc));
|
|
+ warnx("Make sure that kernel module 'paes_s390' is loaded and "
|
|
+ "that the 'paes' cipher is available");
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ rc = properties_save(key_props, filenames->info_filename, 1);
|
|
if (rc != 0) {
|
|
pr_verbose(keystore,
|
|
"Key info file '%s' could not be written: %s",
|
|
- info_filename, strerror(-rc));
|
|
+ filenames->info_filename, strerror(-rc));
|
|
goto out;
|
|
}
|
|
|
|
- rc = _keystore_set_file_permission(keystore, info_filename);
|
|
+ rc = _keystore_set_file_permission(keystore, filenames->info_filename);
|
|
if (rc != 0) {
|
|
- remove(info_filename);
|
|
+ remove(filenames->info_filename);
|
|
goto out;
|
|
}
|
|
|
|
@@ -1519,8 +1601,7 @@ int keystore_generate_key(struct keystor
|
|
if (rc != 0)
|
|
goto out_free_props;
|
|
|
|
- rc = _keystore_create_info_file(keystore, name,
|
|
- file_names.info_filename,
|
|
+ rc = _keystore_create_info_file(keystore, name, &file_names,
|
|
description, volumes, apqns,
|
|
sector_size);
|
|
if (rc != 0)
|
|
@@ -1603,8 +1684,7 @@ int keystore_import_key(struct keystore
|
|
if (rc != 0)
|
|
goto out_free_props;
|
|
|
|
- rc = _keystore_create_info_file(keystore, name,
|
|
- file_names.info_filename,
|
|
+ rc = _keystore_create_info_file(keystore, name, &file_names,
|
|
description, volumes, apqns,
|
|
sector_size);
|
|
if (rc != 0)
|
|
@@ -1723,6 +1803,9 @@ int keystore_change_key(struct keystore
|
|
}
|
|
}
|
|
|
|
+ rc = _keystore_ensure_vp_exists(keystore, &file_names, key_props);
|
|
+ /* ignore return code, vp generation might fail if key is not valid */
|
|
+
|
|
rc = _keystore_set_timestamp_property(key_props, PROP_NAME_CHANGE_TIME);
|
|
if (rc != 0)
|
|
goto out;
|
|
@@ -1838,7 +1921,7 @@ static struct util_rec *_keystore_setup_
|
|
{
|
|
struct util_rec *rec;
|
|
|
|
- rec = util_rec_new_long("-", ":", REC_KEY, 23, 54);
|
|
+ rec = util_rec_new_long("-", ":", REC_KEY, 28, 54);
|
|
util_rec_def(rec, REC_KEY, UTIL_REC_ALIGN_LEFT, 54, REC_KEY);
|
|
if (validation)
|
|
util_rec_def(rec, REC_STATUS, UTIL_REC_ALIGN_LEFT, 54,
|
|
@@ -1858,6 +1941,7 @@ static struct util_rec *_keystore_setup_
|
|
util_rec_def(rec, REC_KEY_FILE, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_FILE);
|
|
util_rec_def(rec, REC_SECTOR_SIZE, UTIL_REC_ALIGN_LEFT, 54,
|
|
REC_SECTOR_SIZE);
|
|
+ util_rec_def(rec, REC_KEY_VP, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_VP);
|
|
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,
|
|
@@ -1876,6 +1960,7 @@ static void _keystore_print_record(struc
|
|
size_t clear_key_bitsize, bool valid,
|
|
bool is_old_mk, bool reenc_pending)
|
|
{
|
|
+ char temp_vp[VERIFICATION_PATTERN_LEN + 2];
|
|
char *volumes_argz = NULL;
|
|
size_t volumes_argz_len;
|
|
char *apqns_argz = NULL;
|
|
@@ -1888,6 +1973,8 @@ static void _keystore_print_record(struc
|
|
char *change;
|
|
char *apqns;
|
|
char *temp;
|
|
+ char *vp;
|
|
+ int len;
|
|
|
|
description = properties_get(properties, PROP_NAME_DESCRIPTION);
|
|
volumes = properties_get(properties, PROP_NAME_VOLUMES);
|
|
@@ -1913,6 +2000,7 @@ static void _keystore_print_record(struc
|
|
creation = properties_get(properties, PROP_NAME_CREATION_TIME);
|
|
change = properties_get(properties, PROP_NAME_CHANGE_TIME);
|
|
reencipher = properties_get(properties, PROP_NAME_REENC_TIME);
|
|
+ vp = properties_get(properties, PROP_NAME_KEY_VP);
|
|
|
|
util_rec_set(rec, REC_KEY, name);
|
|
if (validation)
|
|
@@ -1951,6 +2039,15 @@ static void _keystore_print_record(struc
|
|
else
|
|
util_rec_set(rec, REC_SECTOR_SIZE, "%lu bytes",
|
|
sector_size);
|
|
+ if (vp != NULL) {
|
|
+ len = sprintf(temp_vp, "%.*s%c%.*s",
|
|
+ VERIFICATION_PATTERN_LEN / 2, vp,
|
|
+ '\0', VERIFICATION_PATTERN_LEN / 2,
|
|
+ &vp[VERIFICATION_PATTERN_LEN / 2]);
|
|
+ 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_CREATION_TIME, creation);
|
|
util_rec_set(rec, REC_CHANGE_TIME,
|
|
change != NULL ? change : "(never)");
|
|
@@ -1976,6 +2073,8 @@ static void _keystore_print_record(struc
|
|
free(change);
|
|
if (reencipher != NULL)
|
|
free(reencipher);
|
|
+ if (vp != NULL)
|
|
+ free(vp);
|
|
}
|
|
|
|
struct validate_info {
|
|
@@ -2404,6 +2503,17 @@ static int _keystore_process_reencipher(
|
|
if (rc != 0)
|
|
goto out;
|
|
|
|
+ rc = _keystore_ensure_vp_exists(keystore, file_names,
|
|
+ properties);
|
|
+ if (rc != 0) {
|
|
+ warnx("Failed to generate the key verification pattern "
|
|
+ "for key '%s': %s", file_names->skey_filename,
|
|
+ strerror(-rc));
|
|
+ warnx("Make sure that kernel module 'paes_s390' is loaded and "
|
|
+ "that the 'paes' cipher is available");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
rc = properties_save(properties, file_names->info_filename, 1);
|
|
if (rc != 0) {
|
|
pr_verbose(keystore,
|
|
@@ -3040,7 +3150,7 @@ static int _keystore_process_crypttab(st
|
|
"At the time this utility was developed, systemd's "
|
|
"support of crypttab did not support to specify a "
|
|
"sector size with plain dm-crypt devices. The generated "
|
|
- "crypttab entry may or may not work, and may need "
|
|
+ "crypttab entry might or might not work, and might need "
|
|
"manual adoptions.", volume, sector_size);
|
|
util_print_indented(temp, 0);
|
|
}
|
|
--- a/zkey/zkey.1
|
|
+++ b/zkey/zkey.1
|
|
@@ -361,8 +361,8 @@ The
|
|
command displays the attributes of the secure keys, such as key sizes,
|
|
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, and timestamps for key creation, last modification and last
|
|
-re-encipherment.
|
|
+sector size, the key verification pattern, and timestamps for key creation, last
|
|
+modification and last re-encipherment.
|
|
.
|
|
.SS "Remove existing AES secure keys from the secure key repository"
|
|
.
|
|
--- a/zkey/zkey.c
|
|
+++ b/zkey/zkey.c
|
|
@@ -1057,6 +1057,7 @@ static int command_reencipher(void)
|
|
*/
|
|
static int command_validate_file(void)
|
|
{
|
|
+ char vp[VERIFICATION_PATTERN_LEN];
|
|
size_t secure_key_size;
|
|
size_t clear_key_size;
|
|
u8 *secure_key;
|
|
@@ -1089,14 +1090,30 @@ static int command_validate_file(void)
|
|
goto out;
|
|
}
|
|
|
|
+ rc = generate_key_verification_pattern((char *)secure_key,
|
|
+ secure_key_size, vp, sizeof(vp),
|
|
+ g.verbose);
|
|
+ if (rc != 0) {
|
|
+ warnx("Failed to generate the verification pattern: %s",
|
|
+ strerror(-rc));
|
|
+ warnx("Make sure that kernel module 'paes_s390' is loaded and "
|
|
+ "that the 'paes' cipher is available");
|
|
+ rc = EXIT_FAILURE;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
printf("Validation of secure key in file '%s':\n", g.pos_arg);
|
|
- printf(" Status: Valid\n");
|
|
- printf(" Secure key size: %lu bytes\n", secure_key_size);
|
|
- printf(" Clear key size: %lu bits\n", clear_key_size);
|
|
- printf(" XTS type key: %s\n",
|
|
+ printf(" Status: Valid\n");
|
|
+ printf(" Secure key size: %lu bytes\n", secure_key_size);
|
|
+ printf(" Clear key size: %lu bits\n", clear_key_size);
|
|
+ printf(" XTS type key: %s\n",
|
|
secure_key_size > SECURE_KEY_SIZE ? "Yes" : "No");
|
|
- printf(" Encrypted with: %s CCA master key\n",
|
|
+ printf(" Enciphered with: %s CCA master key\n",
|
|
is_old_mk ? "OLD" : "CURRENT");
|
|
+ printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
|
+ vp);
|
|
+ printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
|
+ &vp[VERIFICATION_PATTERN_LEN / 2]);
|
|
|
|
out:
|
|
free(secure_key);
|