File s390-tools-sles15sp1-0018-zkey-Add-key-verification-pattern-property.patch of Package s390-tools

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);
openSUSE Build Service is sponsored by