SHA256
1
0
forked from pool/s390-tools
s390-tools/s390-tools-sles15sp1-0018-zkey-Add-key-verification-pattern-property.patch

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