File s390-tools-sles15sp2-07-zkey-Add-function-to-cross-check-APQNs-for-valid-mas.patch of Package s390-tools.16701

Subject: zkey: Add function to cross check APQNs for valid master keys
From: Ingo Franzki <ifranzki@linux.ibm.com>

Summary:     zkey: check master key consistency
Description: Enhances the zkey tool to perform a cross check whether the
             APQNs associated with a secure key have the same master key.
             Display the master key verification pattern of a secure key
             during the zkey validate command. This helps to better identify
             which master key is the correct one, in case of master key 
             inconsistencies.
             Select an appropriate APQN when re-enciphering a secure key.
             Re-enciphering is done using the CCA host library. Special
             handling is required to select an appropriate APQN for use with
             the CCA host library.
Upstream-ID: b32c0314746ddee69e59f892f105acd720d06452
Problem-ID:  SEC1916

Upstream-Description:

             zkey: Add function to cross check APQNs for valid master keys

             Add a utility function to cross check the master keys of a set of
             APQNs. It checks for valid master keys in the CURRENT and OLD
             master key registers, as well as newly loaded master keys in the NEW
             register. It issues information and warning messages for various
             findings and also indicates improper master key setup to the caller.

             Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
             Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
             Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>


Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
---
 zkey/utils.c |  217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 zkey/utils.h |    3 
 2 files changed, 220 insertions(+)

--- a/zkey/utils.c
+++ b/zkey/utils.c
@@ -506,3 +506,220 @@ int print_mk_info(const char *apqns, boo
 	util_rec_free(info.rec);
 	return rc;
 }
+
+struct cross_check_info {
+	u64	mkvp;
+	u64	new_mkvp;
+	bool	key_mkvp;
+	u32	num_cur_match;
+	u32	num_old_match;
+	u32	num_new_match;
+	bool	mismatch;
+	bool	print_mks;
+	int	num_checked;
+	bool	verbose;
+};
+
+static int cross_check_mk_info(int card, int domain, void *handler_data)
+{
+	struct cross_check_info *info = (struct cross_check_info *)handler_data;
+	struct mk_info mk_info;
+	char temp[200];
+	int rc;
+
+	rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
+	if (rc == -ENODEV) {
+		info->print_mks = 1;
+		printf("WARNING: APQN %02x.%04x: Not available or not of "
+		       "type CCA\n", card, domain);
+		return 0;
+	}
+	if (rc != 0)
+		return rc;
+
+	info->num_checked++;
+
+	if (mk_info.new_mk.mk_state == MK_STATE_PARTIAL) {
+		info->print_mks = 1;
+		sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
+			"register is only partially loaded.", card, domain);
+		util_print_indented(temp, 0);
+	}
+
+	if (info->new_mkvp == 0 &&
+	    mk_info.new_mk.mk_state == MK_STATE_FULL)
+		info->new_mkvp = mk_info.new_mk.mkvp;
+
+	if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
+	    mk_info.new_mk.mkvp != info->new_mkvp) {
+		info->print_mks = 1;
+		sprintf(temp, "WARNING: APQN %02x.%04x: The NEW master key "
+			      "register contains a different master key than "
+			      "the NEW register of other APQNs.", card,
+			domain);
+		util_print_indented(temp, 0);
+	}
+
+	if (mk_info.cur_mk.mk_state != MK_STATE_VALID) {
+		info->print_mks = 1;
+		info->mismatch = 1;
+		printf("WARNING: APQN %02x.%04x: No master key is set.\n", card,
+		       domain);
+		return 0;
+	}
+
+	if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
+	    mk_info.old_mk.mkvp == mk_info.cur_mk.mkvp) {
+		info->print_mks = 1;
+		sprintf(temp, "INFO: APQN %02x.%04x: The OLD master key "
+			"register contains the same master key as the CURRENT "
+			"master key register.", card, domain);
+		util_print_indented(temp, 0);
+	}
+	if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
+	    mk_info.new_mk.mkvp == mk_info.cur_mk.mkvp) {
+		info->print_mks = 1;
+		sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
+			"register contains the same master key as the CURRENT "
+			"master key register.", card, domain);
+		util_print_indented(temp, 0);
+	}
+	if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
+	    mk_info.old_mk.mk_state == MK_STATE_VALID &&
+	    mk_info.new_mk.mkvp == mk_info.old_mk.mkvp) {
+		info->print_mks = 1;
+		sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
+			"register contains the same master key as the OLD "
+			"master key register.", card, domain);
+		util_print_indented(temp, 0);
+	}
+
+	if (info->mkvp == 0)
+		info->mkvp = mk_info.cur_mk.mkvp;
+
+	if (info->key_mkvp) {
+		if (mk_info.cur_mk.mk_state == MK_STATE_VALID &&
+		    mk_info.cur_mk.mkvp == info->mkvp)
+			info->num_cur_match++;
+
+		if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
+		    mk_info.old_mk.mkvp == info->mkvp)
+			info->num_old_match++;
+
+		if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
+		    mk_info.new_mk.mkvp == info->mkvp)
+			info->num_new_match++;
+	}
+
+	if (mk_info.cur_mk.mkvp != info->mkvp) {
+
+		if (info->key_mkvp) {
+			if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
+			    mk_info.old_mk.mkvp == info->mkvp) {
+				info->print_mks = 1;
+				sprintf(temp, "INFO: APQN %02x.%04x: The master"
+					" key has been changed to a new "
+					"master key, but the secure key has "
+					"not yet been re-enciphered.", card,
+					domain);
+				util_print_indented(temp, 0);
+			} else if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
+				   mk_info.new_mk.mkvp == info->mkvp) {
+				info->print_mks = 1;
+				sprintf(temp, "INFO: APQN %02x.%04x: The master"
+					" key has been changed but is not "
+					"yet been set (made active).", card,
+					domain);
+				util_print_indented(temp, 0);
+			} else {
+				info->print_mks = 1;
+				info->mismatch = 1;
+				sprintf(temp, "WARNING: APQN %02x.%04x: The "
+					"CURRENT master key register contains "
+					"a master key that is different from "
+					"the one used by the secure key.", card,
+					domain);
+				util_print_indented(temp, 0);
+			}
+		} else {
+			info->print_mks = 1;
+			info->mismatch = 1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Cross checks the master key information for all specified APQNs. It checks
+ * if all specified APQNs have the same current master key, and if it matches
+ * the master key specified by the mkvp parameter (optional). If not, it prints
+ * out an information message about the APQNs that have a different master key.
+ *
+ * @param[in] apqns     a comma separated list of APQNs. If NULL is specified,
+ *                      or an empty string, then all online CCA APQNs are
+ *                      checked.
+ * @param[in] mkvp      The master key verification pattern of a secure key.
+ *                      If this is all zero, then the master keys are not
+ *                      matched against it.
+ * @param[in] print_mks if true, then a the full master key info of all
+ *                      specified APQns is printed, in case of a mismatch.
+ * @param[in] verbose   if true, verbose messages are printed
+ *
+ * @returns 0 for success or a negative errno in case of an error. -ENODEV is
+ *          returned if at least one APQN has a mismatching master key.
+ *          -ENOTSUP is returned when the mkvps sysfs attribute is not
+ *          available, because the zcrypt kernel module is on an older level.
+ */
+int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks, bool verbose)
+{
+	struct cross_check_info info;
+	char temp[200];
+	int rc;
+
+	memset(&info, 0, sizeof(info));
+	info.key_mkvp = mkvp != 0;
+	info.mkvp = mkvp;
+	info.verbose = verbose;
+
+	pr_verbose(verbose, "Cross checking APQNs with mkvp 0x%016llx: %s",
+		   mkvp, apqns != NULL ? apqns : "ANY");
+
+	rc = handle_apqns(apqns, cross_check_mk_info, &info, verbose);
+	if (rc != 0)
+		return rc;
+
+	if (info.mismatch) {
+		if (info.key_mkvp)
+			printf("WARNING: Not all APQNs have the correct master "
+			       "key (%016llx).\n", mkvp);
+		else
+			printf("WARNING: Not all APQNs have the same master "
+			       "key.\n");
+
+		rc = -ENODEV;
+	}
+	if (info.num_checked == 0) {
+		printf("WARNING: None of the APQNs is available or of "
+		       "type CCA\n");
+		rc = -ENODEV;
+	}
+	if (info.num_old_match > 0 && info.num_new_match > 0) {
+		sprintf(temp, "WARNING: On %u APQNs the OLD master key "
+			"register contains the master key use by the secure "
+			"key, and on %u APQNs the NEW master key register "
+			"contains the master key use by the secure key.",
+			info.num_old_match, info.num_new_match);
+		util_print_indented(temp, 0);
+		info.print_mks = 1;
+		rc = -ENODEV;
+	}
+
+	if (print_mks && info.print_mks) {
+		printf("\n");
+		print_mk_info(apqns, verbose);
+		printf("\n");
+	}
+
+	return rc;
+}
--- a/zkey/utils.h
+++ b/zkey/utils.h
@@ -48,4 +48,7 @@ int handle_apqns(const char *apqns, apqn
 
 int print_mk_info(const char *apqns, bool verbose);
 
+int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks,
+		      bool verbose);
+
 #endif
openSUSE Build Service is sponsored by