File s390-tools-sles15sp2-14-zkey-Add-function-to-select-a-specific-CCA-adapter.patch of Package s390-tools.15932

Subject: zkey: Add function to select a specific CCA adapter
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: 016a0a56fcb3dd0bf8bed693e5d64873f6288995
Problem-ID:  SEC1916

Upstream-Description:

             zkey: Add function to select a specific CCA adapter

             Some operations require the CCA host library to be used, such as
             re-enciphering a secure key. The CCA host library uses a different
             approach to select the APQN it operates with. To ensure that the
             desired APQN is used for an operation, a utility function is added
             to select a specific APQN for usage with the CCA host library.

             The CCA host library allows to set environment variables to override
             the default CCA APQN selection. The environment variables are inspected
             during CCA host library initialization only. To select a specific
             domain for CCA, the CSU_DEFAULT_DOMAIN environment variable is set,
             and then the CCA host library is un-loaded and re-loaded again.
             Furthermore, the 'Cryptographic Resource Allocate' verb of the CCA
             host library is used together with the 'Cryptographic Facility Query
             function' verb to iterate over the crypto cards known by the CCA host
             library, and to identify the desired crypto card based on its serial
             number. That way, a specific APQN can be selected for use with
             subsequent CCA verbs.

             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/Makefile |    4 
 zkey/cca.c    |  296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 zkey/cca.h    |   32 ++++++
 3 files changed, 329 insertions(+), 3 deletions(-)

--- a/zkey/Makefile
+++ b/zkey/Makefile
@@ -66,7 +66,7 @@ all: $(BUILD_TARGETS)
 
 zkey.o: zkey.c pkey.h cca.h misc.h
 pkey.o: pkey.c pkey.h
-cca.o: cca.c cca.h pkey.h
+cca.o: cca.c cca.h pkey.h utils.h
 utils.o: utils.h
 properties.o: check-dep-zkey properties.c properties.h
 keystore.o: keystore.c keystore.h properties.h pkey.h cca.h utils.h
@@ -77,7 +77,7 @@ zkey: zkey.o pkey.o cca.o properties.o k
 	$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
 
 zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c
-zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o $(libs)
+zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o utils.o $(libs)
 	$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
 
 install-common:
--- a/zkey/cca.c
+++ b/zkey/cca.c
@@ -12,6 +12,7 @@
 #include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdint.h>
 #include <sys/types.h>
@@ -21,6 +22,7 @@
 
 #include "cca.h"
 #include "pkey.h"
+#include "utils.h"
 
 #define pr_verbose(verbose, fmt...)	do {				\
 						if (verbose)		\
@@ -32,6 +34,8 @@
  */
 #define CCA_LIBRARY_NAME	"libcsulcca.so"
 #define CCA_WEB_PAGE		"http://www.ibm.com/security/cryptocards"
+#define CCA_DOMAIN_ENVAR	"CSU_DEFAULT_DOMAIN"
+#define CCA_ADAPTER_ENVAR	"CSU_DEFAULT_ADAPTER"
 
 /**
  * Prints CCA return and reason code information for certain known CCA
@@ -136,8 +140,20 @@ int load_cca_library(struct cca_lib *cca
 	/* Get the Key Token Change function */
 	cca->dll_CSNBKTC = (t_CSNBKTC)dlsym(cca->lib_csulcca, "CSNBKTC");
 
+	/* Get the Cryptographic Facility Query function */
+	cca->dll_CSUACFQ = (t_CSUACFQ)dlsym(cca->lib_csulcca, "CSUACFQ");
+
+	/* Get the Cryptographic Resource Allocate function */
+	cca->dll_CSUACRA = (t_CSUACRA)dlsym(cca->lib_csulcca, "CSUACRA");
+
+	/* Cryptographic Resource Deallocate function */
+	cca->dll_CSUACRD = (t_CSUACRD)dlsym(cca->lib_csulcca, "CSUACRD");
+
 	if (cca->dll_CSUACFV == NULL ||
-	    cca->dll_CSNBKTC == NULL) {
+	    cca->dll_CSNBKTC == NULL ||
+	    cca->dll_CSUACFQ == NULL ||
+	    cca->dll_CSUACRA == NULL ||
+	    cca->dll_CSUACRD == NULL) {
 		pr_verbose(verbose, "%s", dlerror());
 		warnx("The command requires the IBM CCA Host Libraries and "
 		      "Tools.\nFor the supported environments and downloads, "
@@ -213,3 +229,281 @@ int key_token_change(struct cca_lib *cca
 	}
 	return 0;
 }
+
+/**
+ * Queries the number of adapters known by the CCA host library
+ *
+ * @param[in] cca              the CCA library structure
+ * @param[out] adapters        the number of adapters
+ * @param[in] verbose          if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error.
+ */
+static int get_number_of_cca_adapters(struct cca_lib *cca,
+				      unsigned int *adapters, bool verbose)
+{
+	long exit_data_len = 0, rule_array_count, verb_data_length = 0;
+	unsigned char rule_array[16 * 8] = { 0, };
+	unsigned char exit_data[4] = { 0, };
+	long return_code, reason_code;
+
+	util_assert(cca != NULL, "Internal error: cca is NULL");
+	util_assert(adapters != NULL, "Internal error: adapters is NULL");
+
+	memset(rule_array, 0, sizeof(rule_array));
+	memcpy(rule_array, "STATCRD2", 8);
+	rule_array_count = 1;
+
+	cca->dll_CSUACFQ(&return_code, &reason_code,
+			 &exit_data_len, exit_data,
+			 &rule_array_count, rule_array,
+			 &verb_data_length, NULL);
+
+	pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
+		   "return_code: %ld, reason_code: %ld", return_code,
+		   reason_code);
+	if (return_code != 0) {
+		print_CCA_error(return_code, reason_code);
+		return -EIO;
+	}
+
+	rule_array[8] = '\0';
+	if (sscanf((char *)rule_array, "%u", adapters) != 1) {
+		pr_verbose(verbose, "Unparsable output: %s", rule_array);
+		return -EIO;
+	}
+
+	pr_verbose(verbose, "Number of CCA adapters: %u", *adapters);
+	return 0;
+}
+
+/**
+ * Allocate a specific CCA adapter.
+ *
+ * @param[in] cca              the CCA library structure
+ * @param[in] adapter          the adapter number, starting at 1. If 0 is
+ *                             specified, then the AUTOSELECT option is
+ *                             enabled.
+ * @param[in] verbose          if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error. -ENODEV is
+ *          returned if the adapter is not available.
+ */
+static int allocate_cca_adapter(struct cca_lib *cca, unsigned int adapter,
+				bool verbose)
+{
+	long exit_data_len = 0, rule_array_count;
+	unsigned char rule_array[8] = { 0, };
+	unsigned char exit_data[4] = { 0, };
+	long return_code, reason_code;
+	char res_name[9];
+	long res_name_len;
+
+	util_assert(cca != NULL, "Internal error: cca is NULL");
+
+	if (adapter > 0)
+		memcpy(rule_array, "DEVICE  ", 8);
+	else
+		memcpy(rule_array, "DEV-ANY ", 8);
+	rule_array_count = 1;
+
+	sprintf(res_name, "CRP%02d", adapter);
+	res_name_len = strlen(res_name);
+
+	cca->dll_CSUACRA(&return_code, &reason_code,
+			 &exit_data_len, exit_data,
+			 &rule_array_count, rule_array,
+			 &res_name_len, (unsigned char *)res_name);
+
+	pr_verbose(verbose, "CSUACRA (Cryptographic Resource Allocate) "
+		   "returned: return_code: %ld, reason_code: %ld", return_code,
+		   reason_code);
+	if (return_code != 0) {
+		print_CCA_error(return_code, reason_code);
+		return -ENODEV;
+	}
+
+	pr_verbose(verbose, "Adapter %u (%s) allocated", adapter, res_name);
+	return 0;
+}
+
+/**
+ * Deallocate a specific CCA adapter.
+ *
+ * @param[in] cca              the CCA library structure
+ * @param[in] adapter          the adapter number, starting at 1. If 0 is
+ *                             specified, then the AUTOSELECT option is
+ *                             disabled.
+ * @param[in] verbose          if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error. -ENODEV is
+ *          returned if the adapter is not available.
+ */
+static int deallocate_cca_adapter(struct cca_lib *cca, unsigned int adapter,
+				  bool verbose)
+{
+	long exit_data_len = 0, rule_array_count;
+	unsigned char rule_array[8] = { 0, };
+	unsigned char exit_data[4] = { 0, };
+	long return_code, reason_code;
+	char res_name[9];
+	long res_name_len;
+
+	util_assert(cca != NULL, "Internal error: cca is NULL");
+
+	if (adapter > 0)
+		memcpy(rule_array, "DEVICE  ", 8);
+	else
+		memcpy(rule_array, "DEV-ANY ", 8);
+	rule_array_count = 1;
+
+	sprintf(res_name, "CRP%02d", adapter);
+	res_name_len = strlen(res_name);
+
+	cca->dll_CSUACRD(&return_code, &reason_code,
+			 &exit_data_len, exit_data,
+			 &rule_array_count, rule_array,
+			 &res_name_len, (unsigned char *)res_name);
+
+	pr_verbose(verbose, "CSUACRD (Cryptographic Resource Deallocate) "
+		   "returned: return_code: %ld, reason_code: %ld", return_code,
+		   reason_code);
+	if (return_code != 0) {
+		print_CCA_error(return_code, reason_code);
+		return -ENODEV;
+	}
+
+	pr_verbose(verbose, "Adapter %u (%s) deallocated", adapter, res_name);
+	return 0;
+}
+
+/**
+ * Queries the serial number of the current CCA adapter
+ *
+ * @param[in] cca              the CCA library structure
+ * @param[out] serialnr        the buffer where the serial number is returned
+ * @param[in] verbose          if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error.
+ */
+static int get_cca_adapter_serialnr(struct cca_lib *cca, char serialnr[9],
+				    bool verbose)
+{
+	long exit_data_len = 0, rule_array_count, verb_data_length = 0;
+	unsigned char rule_array[16 * 8] = { 0, };
+	unsigned char exit_data[4] = { 0, };
+	long return_code, reason_code;
+
+	util_assert(cca != NULL, "Internal error: cca is NULL");
+
+	memset(rule_array, 0, sizeof(rule_array));
+	memcpy(rule_array, "STATCRD2", 8);
+	rule_array_count = 1;
+
+	cca->dll_CSUACFQ(&return_code, &reason_code,
+			 &exit_data_len, exit_data,
+			 &rule_array_count, rule_array,
+			 &verb_data_length, NULL);
+
+	pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
+		   "return_code: %ld, reason_code: %ld", return_code,
+		   reason_code);
+	if (return_code != 0) {
+		print_CCA_error(return_code, reason_code);
+		return -EIO;
+	}
+
+	memcpy(serialnr, rule_array+14*8, 8);
+	serialnr[8] = '\0';
+
+	pr_verbose(verbose, "Serial number of CCA adapter: %s", serialnr);
+	return 0;
+}
+
+/**
+ * Selects the specified APQN to be used for the CCA host library.
+ *
+ * @param[in] cca              the CCA library structure
+ * @param[in] card             the card number
+ * @param[in] domain           the domain number
+ * @param[in] verbose          if true, verbose messages are printed
+ *
+ * @returns 0 on success, a negative errno in case of an error. -ENOTSUP is
+ *          returned when the serialnr sysfs attribute is not available,
+ *          because the zcrypt kernel module is on an older level. -ENODEV is
+ *          returned if the APQN is not available.
+ */
+int select_cca_adapter(struct cca_lib *cca, int card, int domain, bool verbose)
+{
+	unsigned int adapters, adapter;
+	char adapter_serialnr[9];
+	char apqn_serialnr[9];
+	char temp[10];
+	int rc, found = 0;
+
+	util_assert(cca != NULL, "Internal error: cca is NULL");
+
+	pr_verbose(verbose, "Select %02x.%04x for the CCA host library", card,
+		   domain);
+
+	rc = sysfs_get_serialnr(card, apqn_serialnr, verbose);
+	if (rc != 0) {
+		pr_verbose(verbose, "Failed to get the serial number: %s",
+			   strerror(-rc));
+		return rc;
+	}
+
+	sprintf(temp, "%u", domain);
+	if (setenv(CCA_DOMAIN_ENVAR, temp, 1) != 0) {
+		rc = -errno;
+		pr_verbose(verbose, "Failed to set the %s environment variable:"
+			   " %s", CCA_DOMAIN_ENVAR, strerror(-rc));
+		return rc;
+	}
+	unsetenv(CCA_ADAPTER_ENVAR);
+
+	/*
+	 * Unload and reload the CCA host library so that it recognizes the
+	 * changed CSU_DEFAULT_DOMAIN environment variable value.
+	 */
+	if (cca->lib_csulcca != NULL)
+		dlclose(cca->lib_csulcca);
+	memset(cca, 0, sizeof(struct cca_lib));
+
+	rc = load_cca_library(cca, verbose);
+	if (rc != 0)
+		return rc;
+
+	rc = get_number_of_cca_adapters(cca, &adapters, verbose);
+	if (rc != 0)
+		return rc;
+
+	/* Disable the AUTOSELECT option */
+	rc = deallocate_cca_adapter(cca, 0, verbose);
+	if (rc != 0)
+		return rc;
+
+	for (adapter = 1; adapter <= adapters; adapter++) {
+		rc = allocate_cca_adapter(cca, adapter, verbose);
+		if (rc != 0)
+			return rc;
+
+		rc = get_cca_adapter_serialnr(cca, adapter_serialnr, verbose);
+		if (rc == 0) {
+			if (memcmp(apqn_serialnr, adapter_serialnr, 8) == 0) {
+				found = 1;
+				break;
+			}
+		}
+
+		rc = deallocate_cca_adapter(cca, adapter, verbose);
+		if (rc != 0)
+			return rc;
+	}
+
+	if (!found)
+		return -ENODEV;
+
+	pr_verbose(verbose, "Selected adapter %u (CRP%02d)", adapter, adapter);
+	return 0;
+}
--- a/zkey/cca.h
+++ b/zkey/cca.h
@@ -32,6 +32,33 @@ typedef void (*t_CSUACFV)(long *return_c
 			  long *version_data_length,
 			  unsigned char *version_data);
 
+typedef void (*t_CSUACFQ)(long *return_code,
+			  long *reason_code,
+			  long *exit_data_length,
+			  unsigned char *exit_data,
+			  long *rule_array_count,
+			  unsigned char *rule_array,
+			  long *verb_data_length,
+			  unsigned char *verb_data);
+
+typedef void (*t_CSUACRA)(long *return_code,
+			  long *reason_code,
+			  long *exit_data_length,
+			  unsigned char *exit_data,
+			  long *rule_array_count,
+			  unsigned char *rule_array,
+			  long *ressource_name_length,
+			  unsigned char *ressource_name);
+
+typedef void (*t_CSUACRD)(long *return_code,
+			  long *reason_code,
+			  long *exit_data_length,
+			  unsigned char *exit_data,
+			  long *rule_array_count,
+			  unsigned char *rule_array,
+			  long *ressource_name_length,
+			  unsigned char *ressource_name);
+
 struct cca_version {
 	unsigned int ver;
 	unsigned int rel;
@@ -42,6 +69,9 @@ struct cca_lib {
 	void *lib_csulcca;
 	t_CSNBKTC dll_CSNBKTC;
 	t_CSUACFV dll_CSUACFV;
+	t_CSUACFQ dll_CSUACFQ;
+	t_CSUACRA dll_CSUACRA;
+	t_CSUACRD dll_CSUACRD;
 	struct cca_version version;
 };
 
@@ -51,4 +81,6 @@ int key_token_change(struct cca_lib *cca
 		     u8 *secure_key, unsigned int secure_key_size,
 		     char *method, bool verbose);
 
+int select_cca_adapter(struct cca_lib *cca, int card, int domain, bool verbose);
+
 #endif
openSUSE Build Service is sponsored by