diff --git a/zkey/Makefile b/zkey/Makefile index 0e51d803..f92de4ff 100644 --- 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 keystore.o utils.o $(libs) $(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: diff --git a/zkey/cca.c b/zkey/cca.c index 09ac9fed..8c03ad87 100644 --- a/zkey/cca.c +++ b/zkey/cca.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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, bool verbose) /* 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; +} diff --git a/zkey/cca.h b/zkey/cca.h index 18816c31..41d5bcac 100644 --- a/zkey/cca.h +++ b/zkey/cca.h @@ -32,6 +32,33 @@ typedef void (*t_CSUACFV)(long *return_code, 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