diff --git a/zkey/utils.c b/zkey/utils.c index 1d2ee7cb..f6b0e041 100644 --- a/zkey/utils.c +++ b/zkey/utils.c @@ -159,3 +159,143 @@ out: free(dev_path); return rc; } + +static int parse_mk_info(char *line, struct mk_info *mk_info) +{ + struct mk_info_reg *mk_reg; + char *save; + char *tok; + + tok = strtok_r(line, " ", &save); + if (tok == NULL) + return -EIO; + + if (strcasecmp(tok, "AES") != 0) + return 0; + + tok = strtok_r(NULL, " ", &save); + if (tok == NULL) + return -EIO; + + if (strcasecmp(tok, "NEW:") == 0) + mk_reg = &mk_info->new_mk; + else if (strcasecmp(tok, "CUR:") == 0) + mk_reg = &mk_info->cur_mk; + else if (strcasecmp(tok, "OLD:") == 0) + mk_reg = &mk_info->old_mk; + else + return -EIO; + + tok = strtok_r(NULL, " ", &save); + if (tok == NULL) + return -EIO; + + if (strcasecmp(tok, "empty") == 0) + mk_reg->mk_state = MK_STATE_EMPTY; + else if (strcasecmp(tok, "partial") == 0) + mk_reg->mk_state = MK_STATE_PARTIAL; + else if (strcasecmp(tok, "full") == 0) + mk_reg->mk_state = MK_STATE_FULL; + else if (strcasecmp(tok, "valid") == 0) + mk_reg->mk_state = MK_STATE_VALID; + else if (strcasecmp(tok, "invalid") == 0) + mk_reg->mk_state = MK_STATE_INVALID; + else + mk_reg->mk_state = MK_STATE_UNKNOWN; + + tok = strtok_r(NULL, " ", &save); + if (tok == NULL) + return -EIO; + + if (sscanf(tok, "%llx", &mk_reg->mkvp) != 1) + return -EIO; + + return 0; +} + +/** + * Gets the master key states and verification patterns of an APQN from the + * sysfs. + * + * @param[in] card card number + * @param[in] domain the domain + * @param[out] mk_info structure is filled on return with master key infos + * @param[in] verbose if true, verbose messages are printed + * + * @returns 0 if the master key info was returned. -ENODEV if the APQN is not + * available, or is not a CCA card. -ENOTSUP if the mkvps sysfs + * attribute is not available, because the zcrypt kernel module is + * on an older level. + */ +int sysfs_get_mkvps(int card, int domain, struct mk_info *mk_info, bool verbose) +{ + char *dev_path; + char *p, *end; + char buf[100]; + int rc = 0; + FILE *fp; + + if (mk_info == NULL) + return -EINVAL; + + memset(mk_info, 0, sizeof(struct mk_info)); + mk_info->new_mk.mk_state = MK_STATE_UNKNOWN; + mk_info->cur_mk.mk_state = MK_STATE_UNKNOWN; + mk_info->old_mk.mk_state = MK_STATE_UNKNOWN; + + if (sysfs_is_apqn_online(card, domain) != 1) + return -ENODEV; + + dev_path = util_path_sysfs("bus/ap/devices/card%02x/%02x.%04x/mkvps", + card, card, domain); + if (!util_path_is_reg_file(dev_path)) { + rc = -ENOTSUP; + goto out; + } + + fp = fopen(dev_path, "r"); + if (fp == NULL) { + rc = -ENOTSUP; + goto out; + } + + /* + * Expected contents: + * AES NEW: + * AES CUR: + * AES OLD: + * with + * : 'empty' or 'partial' or 'full' + * , : 'valid' or 'invalid' + * , , new_mk.mk_state == MK_STATE_UNKNOWN && + mk_info->cur_mk.mk_state == MK_STATE_UNKNOWN && + mk_info->old_mk.mk_state == MK_STATE_UNKNOWN) + rc = -EIO; +out: + if (rc != 0) + pr_verbose(verbose, "Failed to get mkvps for %02x.%04x: %s", + card, domain, strerror(-rc)); + + free(dev_path); + return rc; +} diff --git a/zkey/utils.h b/zkey/utils.h index 0659fd64..407789c9 100644 --- a/zkey/utils.h +++ b/zkey/utils.h @@ -20,4 +20,25 @@ int sysfs_is_apqn_online(int card, int domain); int sysfs_get_serialnr(int card, char serialnr[9], bool verbose); +#define MK_STATE_EMPTY 0 +#define MK_STATE_PARTIAL 1 +#define MK_STATE_FULL 2 +#define MK_STATE_VALID 3 +#define MK_STATE_INVALID 4 +#define MK_STATE_UNKNOWN -1 + +struct mk_info_reg { + int mk_state; + u64 mkvp; +}; + +struct mk_info { + struct mk_info_reg new_mk; + struct mk_info_reg cur_mk; + struct mk_info_reg old_mk; +}; + +int sysfs_get_mkvps(int card, int domain, struct mk_info *mk_info, + bool verbose); + #endif