456 lines
15 KiB
Diff
456 lines
15 KiB
Diff
|
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
|