Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:FrontRunner
s390-tools.19914
s390-tools-sles15sp2-24-zkey-Add-helper-functio...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File s390-tools-sles15sp2-24-zkey-Add-helper-functions-to-build-lists-of-APQNs.patch of Package s390-tools.19914
Subject: zkey: Add helper functions to build lists of APQNs From: Ingo Franzki <ifranzki@linux.ibm.com> Summary: zkey: Add support for CCA AES CIPHER keys Description: With CCA 5 there is a new secure key type, the so called variable length symmetric cipher key token. This token format can hold AES keys with size 128, 192 and 256 bits together with additional attributes cryptographic bound to the key token. The attributes may limit the usage of the key, for example restrict export or usability scope. So this key type is considered to be even more secure than the traditional secure key token. This key token type is also called "CCA AES CIPHER key", where the formerly used key token is called "CCA AES DATA key". The zkey as well as the zkey-cryptsetup tools are enhanced to support AES CIPHER keys. That is, zkey can manage AES DATA keys, as well as AES CIPHER keys. The key type must be specified at key generation time, the default is to generate AED DATA keys. Upstream-ID: 663d362ff3b1036476bfce9e2563272bab087013 Problem-ID: SEC1717 Upstream-Description: zkey: Add helper functions to build lists of APQNs The new IOCTLs are based on list of APQNs that they try to send the request to. Add some helper functions to build such lists of APQNs based on the key type, and optionally a given mkvp. 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/pkey.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) --- a/zkey/pkey.c +++ b/zkey/pkey.c @@ -46,6 +46,8 @@ #define DEFAULT_KEYBITS 256 +#define INITIAL_APQN_ENTRIES 16 + /** * Opens the pkey device and returns its file descriptor. * @@ -498,6 +500,387 @@ static int pkey_verifyseck2(int pkey_fd, } /** + * Print a list of APQNs if verbose is set + */ +static void pr_verbose_apqn_list(bool verbose, struct pkey_apqn *list, u32 num) +{ + u32 i; + + if (!verbose) + return; + + for (i = 0; i < num ; i++) + warnx(" APQN: %02x.%04x", list[i].card, list[i].domain); +} + +/** + * Filter a n array list of APQNs (struct pkey_apqn) by a list of APQN strings. + * + * @param[in] apqn_list a zero terminated array of pointers to C-strings + * @param[in/out] apqns A list of APQNs as array of struct pkey_apqn to + * filter. The list is modified during filtering. + * @param[in/out] apqn_entries Number of entries in the list of APQNs. The + * number is modified during filtering. + * + * @returns 0 on success, a negative errno in case of an error + */ +static int filter_apqn_list(const char **apqn_list, struct pkey_apqn **apqns, + u32 *apqn_entries) +{ + unsigned int count, i, k, card, domain; + struct pkey_apqn *list = *apqns; + bool found; + + if (apqn_list == NULL) + return 0; + + for (count = 0; apqn_list[count] != NULL; count++) + ; + if (count == 0) + return 0; + + for (i = 0; i < *apqn_entries; i++) { + found = false; + for (k = 0; apqn_list[k] != NULL; k++) { + if (sscanf(apqn_list[k], "%x.%x", &card, &domain) != 2) + return -EINVAL; + + if (list[i].card == card && list[i].domain == domain) { + found = true; + break; + } + } + + if (!found) { + if (i < *apqn_entries - 1) + memmove(&list[i], &list[i+1], + (*apqn_entries - i - 1) * + sizeof(struct pkey_apqn)); + (*apqn_entries)--; + i--; + } + } + + return 0; +} + +/** + * Build a list of APQNs in the form accepted by the pkey IOCTLs from the + * List of APQNs as zero terminated array of pointers to C-strings that + * are usable for the CCA-AESDATA key type. + * + * @param[in] apqn_list a zero terminated array of pointers to C-strings + * @param[out] apqns A list of APQNs as array of struct pkey_apqn. The + * list must be freed by the caller using free(). + * @param[out] apqn_entries Number of entries in the list of APQNs + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 on success, a negative errno in case of an error + */ +static int build_apqn_list_for_aes_data(const char **apqn_list, + struct pkey_apqn **apqns, + u32 *apqn_entries, bool verbose) +{ + unsigned int card, domain, count = 0; + struct pkey_apqn *list = NULL; + u32 list_entries = 0; + int i; + + pr_verbose(verbose, "Build a list of APQNs for CCA-AESDATA"); + + if (apqn_list != NULL) + for (count = 0; apqn_list[count] != NULL; count++) + ; + + if (count > 0) { + list = util_malloc(count * sizeof(struct pkey_apqn)); + list_entries = count; + + for (i = 0; apqn_list[i] != NULL; i++) { + if (sscanf(apqn_list[i], "%x.%x", &card, &domain) != 2) + return -EINVAL; + + list[i].card = card; + list[i].domain = domain; + } + + } else { + /* + * Although the new pkey IOCTLs do not support APQN entries + * with ANY indication, build an ANY-list here. If we get here, + * then the new IOCTLs are not available, and it will fall back + * to the old IOCTL which do support ANY specifications. + */ + list = util_malloc(sizeof(struct pkey_apqn)); + list_entries = 1; + + list[0].card = AUTOSELECT; + list[0].domain = AUTOSELECT; + } + + *apqns = list; + *apqn_entries = list_entries; + + pr_verbose(verbose, "%u APQNs found", list_entries); + pr_verbose_apqn_list(verbose, list, list_entries); + return 0; +} + +/** + * Build a list of APQNs in the form accepted by the pkey IOCTLs from the + * List of APQNs as zero terminated array of pointers to C-strings that + * are usable for the specified key type. + * + * @param[in] pkey_fd the pkey file descriptor + * @param[in] type the key type + * @param[in] apqn_list a zero terminated array of pointers to C-strings + * @param[out] apqns A list of APQNs as array of struct pkey_apqn. The + * list must be freed by the caller using free(). + * @param[out] apqn_entries Number of entries in the list of APQNs + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 on success, a negative errno in case of an error + */ +static int build_apqn_list_for_key_type(int pkey_fd, enum pkey_key_type type, + const char **apqn_list, + struct pkey_apqn **apqns, + u32 *apqn_entries, bool verbose) +{ + struct pkey_apqns4keytype apqns4keytype; + int rc; + + util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); + util_assert(apqns != NULL, "Internal error: apqns is NULL"); + util_assert(apqn_entries != NULL, + "Internal error: apqn_entries is NULL"); + + pr_verbose(verbose, "Build a list of APQNs for key type %d", type); + + memset(&apqns4keytype, 0, sizeof(apqns4keytype)); + apqns4keytype.type = type; + apqns4keytype.apqn_entries = INITIAL_APQN_ENTRIES; + apqns4keytype.apqns = (struct pkey_apqn *)util_malloc( + apqns4keytype.apqn_entries * sizeof(struct pkey_apqn)); + + do { + rc = ioctl(pkey_fd, PKEY_APQNS4KT, &apqns4keytype); + if (rc == 0) + break; + rc = -errno; + pr_verbose(verbose, "ioctl PKEY_APQNS4KT rc: %s", + strerror(-rc)); + + switch (rc) { + case -ENOSPC: + free(apqns4keytype.apqns); + apqns4keytype.apqns = (struct pkey_apqn *) + util_malloc(apqns4keytype.apqn_entries * + sizeof(struct pkey_apqn)); + continue; + case -ENOTTY: + /* + * New IOCTL is not available: build the list + * manually (Key type CCA-AESDATA only) + */ + free(apqns4keytype.apqns); + + if (type != PKEY_TYPE_CCA_DATA) + return -ENOTSUP; + + rc = build_apqn_list_for_aes_data(apqn_list, apqns, + apqn_entries, + verbose); + return rc; + default: + goto out; + } + } while (rc != 0); + + if (apqns4keytype.apqn_entries == 0) { + pr_verbose(verbose, "No APQN available for key type %d", type); + rc = -ENODEV; + goto out; + } + + rc = filter_apqn_list(apqn_list, &apqns4keytype.apqns, + &apqns4keytype.apqn_entries); + if (rc != 0) + goto out; + + if (apqns4keytype.apqn_entries == 0) { + pr_verbose(verbose, "No APQN available for key type %d", type); + rc = -ENODEV; + goto out; + } + + pr_verbose(verbose, "%u APQNs found", apqns4keytype.apqn_entries); + pr_verbose_apqn_list(verbose, apqns4keytype.apqns, + apqns4keytype.apqn_entries); + +out: + if (rc == 0) { + *apqns = apqns4keytype.apqns; + *apqn_entries = apqns4keytype.apqn_entries; + } else { + *apqns = NULL; + *apqn_entries = 0; + free(apqns4keytype.apqns); + } + + return rc; +} + +/** + * Build a list of APQNs in the form accepted by the pkey IOCTLs from the + * List of APQNs as zero terminated array of pointers to C-strings that are + * usable for the specufied key. + * + * @param[in] pkey_fd the pkey file descriptor + * @param[in] key the key + * @param[in] keylen the length of the key + * @param[in] flags PKEY_FLAGS_MATCH_xxx flags + * @param[in] apqn_list a zero terminated array of pointers to C-strings + * @param[out] apqns A list of APQNs as array of struct pkey_apqn. The + * list must be freed by the caller using free(). + * @param[out] apqn_entries Number of entries in the list of APQNs + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 on success, a negative errno in case of an error + */ +static int build_apqn_list_for_key(int pkey_fd, u8 *key, u32 keylen, u32 flags, + const char **apqn_list, + struct pkey_apqn **apqns, + u32 *apqn_entries, bool verbose) +{ + struct pkey_apqns4key apqns4key; + u64 mkvp; + int rc; + + util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); + util_assert(key != NULL, "Internal error: key is NULL"); + util_assert(apqns != NULL, "Internal error: apqns is NULL"); + util_assert(apqn_entries != NULL, + "Internal error: apqn_entries is NULL"); + + pr_verbose(verbose, "Build a list of APQNs for the key"); + + memset(&apqns4key, 0, sizeof(apqns4key)); + apqns4key.key = key; + apqns4key.keylen = keylen; + apqns4key.flags = flags; + apqns4key.apqn_entries = INITIAL_APQN_ENTRIES; + apqns4key.apqns = (struct pkey_apqn *)util_malloc( + apqns4key.apqn_entries * sizeof(struct pkey_apqn)); + + do { + rc = ioctl(pkey_fd, PKEY_APQNS4K, &apqns4key); + if (rc == 0) + break; + rc = -errno; + pr_verbose(verbose, "ioctl PKEY_APQNS4K rc: %s", strerror(-rc)); + + switch (rc) { + case -ENOSPC: + free(apqns4key.apqns); + apqns4key.apqns = (struct pkey_apqn *) + util_malloc(apqns4key.apqn_entries * + sizeof(struct pkey_apqn)); + continue; + case -ENOTTY: + /* + * New IOCTL is not available: build the list manually + * (Key type CCA-AESDATA only) + */ + free(apqns4key.apqns); + + if (!is_cca_aes_data_key(key, keylen)) + return -ENOTSUP; + + rc = get_master_key_verification_pattern(key, keylen, + &mkvp, + verbose); + if (rc != 0) + return rc; + + rc = build_apqn_list_for_aes_data(apqn_list, apqns, + apqn_entries, + verbose); + return rc; + default: + goto out; + } + } while (rc != 0); + + if (apqns4key.apqn_entries == 0) { + pr_verbose(verbose, "No APQN available for the key"); + rc = -ENODEV; + goto out; + } + + rc = filter_apqn_list(apqn_list, &apqns4key.apqns, + &apqns4key.apqn_entries); + if (rc != 0) + goto out; + + if (apqns4key.apqn_entries == 0) { + pr_verbose(verbose, "No APQN available for the key"); + rc = -ENODEV; + goto out; + } + + pr_verbose(verbose, "%u APQNs found", apqns4key.apqn_entries); + pr_verbose_apqn_list(verbose, apqns4key.apqns, apqns4key.apqn_entries); + +out: + if (rc == 0) { + *apqns = apqns4key.apqns; + *apqn_entries = apqns4key.apqn_entries; + } else { + *apqns = NULL; + *apqn_entries = 0; + free(apqns4key.apqns); + } + + return rc; +} + +/** + * Convert the key type string into the pkey enumeration + * + * @param[in] key_type the type of the key + * + * @returns the pkey key type or 0 for an u known key type + */ +static enum pkey_key_type key_type_to_pkey_type(const char *key_type) +{ + if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0) + return PKEY_TYPE_CCA_DATA; + if (strcasecmp(key_type, KEY_TYPE_CCA_AESCIPHER) == 0) + return PKEY_TYPE_CCA_CIPHER; + + return 0; +} + +/** + * Return the size of a key blob for a specific type + * + * @param[in] type the type of the key + * + * @returns the size of the key or 0 for an invalid key type + */ +static size_t key_size_for_type(enum pkey_key_type type) +{ + switch (type) { + case PKEY_TYPE_CCA_DATA: + return AESDATA_KEY_SIZE; + case PKEY_TYPE_CCA_CIPHER: + return AESCIPHER_KEY_SIZE; + default: + return 0; + } +} + +/** * Generate a secure key by random * * @param[in] pkey_fd the pkey file descriptor
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor