diff --git a/zkey/keystore.c b/zkey/keystore.c index 2b0c30f1..63819a7d 100644 --- a/zkey/keystore.c +++ b/zkey/keystore.c @@ -1722,7 +1722,9 @@ int keystore_generate_key(struct keystore *keystore, const char *name, if (rc != 0) goto out_free_key_filenames; - rc = cross_check_apqns(apqns, 0, true, keystore->verbose); + rc = cross_check_apqns(apqns, 0, + get_min_card_level_for_keytype(key_type), true, + keystore->verbose); if (rc == -EINVAL) goto out_free_key_filenames; if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) { @@ -1850,7 +1852,9 @@ int keystore_import_key(struct keystore *keystore, const char *name, goto out_free_key; } - rc = cross_check_apqns(apqns, mkvp, true, keystore->verbose); + rc = cross_check_apqns(apqns, mkvp, + get_min_card_level_for_keytype(key_type), true, + keystore->verbose); if (rc == -EINVAL) goto out_free_key; if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) { @@ -1937,8 +1941,8 @@ int keystore_change_key(struct keystore *keystore, const char *name, .nomsg = 0 }; struct key_filenames file_names = { NULL, NULL, NULL }; struct properties *key_props = NULL; + char *apqns_prop, *key_type; size_t secure_key_size; - char *apqns_prop; u8 *secure_key; char temp[30]; u64 mkvp; @@ -2005,9 +2009,12 @@ int keystore_change_key(struct keystore *keystore, const char *name, goto out; apqns_prop = properties_get(key_props, PROP_NAME_APQNS); - rc = cross_check_apqns(apqns_prop, mkvp, true, - keystore->verbose); + key_type = properties_get(key_props, PROP_NAME_KEY_TYPE); + rc = cross_check_apqns(apqns_prop, mkvp, + get_min_card_level_for_keytype(key_type), + true, keystore->verbose); free(apqns_prop); + free(key_type); if (rc == -ENOTSUP) rc = 0; if (rc != 0 && noapqncheck == 0) { @@ -2373,12 +2380,17 @@ static int _keystore_display_apqn_status(struct keystore *keystore, { int rc, warning = 0; char *apqns; + char *key_type; apqns = properties_get(properties, PROP_NAME_APQNS); if (apqns == NULL) return 0; - rc = cross_check_apqns(apqns, mkvp, true, keystore->verbose); + apqns = properties_get(properties, PROP_NAME_APQNS); + key_type = properties_get(properties, PROP_NAME_KEY_TYPE); + rc = cross_check_apqns(apqns, mkvp, + get_min_card_level_for_keytype(key_type), true, + keystore->verbose); if (rc != 0 && rc != -ENOTSUP) warning = 1; @@ -2386,6 +2398,7 @@ static int _keystore_display_apqn_status(struct keystore *keystore, printf("\n"); free(apqns); + free(key_type); return warning; } /** diff --git a/zkey/pkey.c b/zkey/pkey.c index 0efb0c23..fcc8faff 100644 --- a/zkey/pkey.c +++ b/zkey/pkey.c @@ -1630,3 +1630,23 @@ const char *get_key_type(const u8 *key, size_t key_size) return NULL; } + +/** + * Returns the minimum card level for a specific key type + * + * @param[in] key_type the type of the key + * + * @returns the minimum card level, or -1 for unknown key types + */ +int get_min_card_level_for_keytype(const char *key_type) +{ + if (key_type == NULL) + return -1; + + if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0) + return 3; + if (strcasecmp(key_type, KEY_TYPE_CCA_AESCIPHER) == 0) + return 6; + + return -1; +} diff --git a/zkey/pkey.h b/zkey/pkey.h index 34af5462..7a838db1 100644 --- a/zkey/pkey.h +++ b/zkey/pkey.h @@ -264,5 +264,6 @@ bool is_cca_aes_cipher_key(const u8 *key, size_t key_size); bool is_xts_key(const u8 *key, size_t key_size); int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize); const char *get_key_type(const u8 *key, size_t key_size); +int get_min_card_level_for_keytype(const char *key_type); #endif diff --git a/zkey/utils.c b/zkey/utils.c index 9dc4af7b..9b29c751 100644 --- a/zkey/utils.c +++ b/zkey/utils.c @@ -118,6 +118,49 @@ out: return rc; } +/** + * Returns the level of the card. For a CEX3C 3 is returned, for a CEX4C 4, + * and so on. + * + * @param[in] card card number + * + * @returns The card level, or -1 of the level can not be determined. + */ +int sysfs_get_card_level(int card) +{ + char *dev_path; + char type[20]; + int rc; + + dev_path = util_path_sysfs("bus/ap/devices/card%02x", card); + if (!util_path_is_dir(dev_path)) { + rc = -1; + goto out; + } + if (util_file_read_line(type, sizeof(type), "%s/type", dev_path) != 0) { + rc = -1; + goto out; + } + if (strncmp(type, "CEX", 3) != 0 || strlen(type) < 5) { + rc = -1; + goto out; + } + if (type[4] != 'C') { + rc = -1; + goto out; + } + if (type[3] < '1' || type[3] > '9') { + rc = -1; + goto out; + } + + rc = type[3] - '0'; + +out: + free(dev_path); + return rc; +} + /** * Gets the 8 character ASCII serial number string of an card from the sysfs. * @@ -436,12 +479,14 @@ static int print_apqn_mk_info(int card, int domain, void *handler_data) { struct print_apqn_info *info = (struct print_apqn_info *)handler_data; struct mk_info mk_info; - int rc; + int rc, level; rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose); if (rc == -ENOTSUP) return rc; + level = sysfs_get_card_level(card); + util_rec_set(info->rec, "APQN", "%02x.%04x", card, domain); if (rc == 0) { @@ -470,6 +515,11 @@ static int print_apqn_mk_info(int card, int domain, void *handler_data) util_rec_set(info->rec, "OLD", "?"); } + if (level > 0) + util_rec_set(info->rec, "TYPE", "CEX%dC", level); + else + util_rec_set(info->rec, "TYPE", "?"); + util_rec_print(info->rec); return 0; @@ -499,6 +549,7 @@ int print_mk_info(const char *apqns, bool verbose) util_rec_def(info.rec, "NEW", UTIL_REC_ALIGN_LEFT, 16, "NEW MK"); util_rec_def(info.rec, "CUR", UTIL_REC_ALIGN_LEFT, 16, "CURRENT MK"); util_rec_def(info.rec, "OLD", UTIL_REC_ALIGN_LEFT, 16, "OLD MK"); + util_rec_def(info.rec, "TYPE", UTIL_REC_ALIGN_LEFT, 6, "TYPE"); util_rec_print_hdr(info.rec); rc = handle_apqns(apqns, print_apqn_mk_info, &info, verbose); @@ -511,6 +562,7 @@ struct cross_check_info { u64 mkvp; u64 new_mkvp; bool key_mkvp; + int min_level; u32 num_cur_match; u32 num_old_match; u32 num_new_match; @@ -525,7 +577,7 @@ static int cross_check_mk_info(int card, int domain, void *handler_data) struct cross_check_info *info = (struct cross_check_info *)handler_data; struct mk_info mk_info; char temp[200]; - int rc; + int rc, level; rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose); if (rc == -ENODEV) { @@ -539,6 +591,19 @@ static int cross_check_mk_info(int card, int domain, void *handler_data) info->num_checked++; + if (info->min_level >= 0) { + level = sysfs_get_card_level(card); + + if (level < info->min_level) { + info->print_mks = 1; + info->mismatch = 1; + sprintf(temp, "WARNING: APQN %02x.%04x: The card level " + "is less than CEX%dC.", card, domain, + info->min_level); + util_print_indented(temp, 0); + } + } + if (mk_info.new_mk.mk_state == MK_STATE_PARTIAL) { info->print_mks = 1; sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key " @@ -662,6 +727,8 @@ static int cross_check_mk_info(int card, int domain, void *handler_data) * @param[in] mkvp The master key verification pattern of a secure key. * If this is all zero, then the master keys are not * matched against it. + * @param[in] min_level The minimum card level required. If min_level is -1 then + * the card level is not checked. * @param[in] print_mks if true, then a the full master key info of all * specified APQns is printed, in case of a mismatch. * @param[in] verbose if true, verbose messages are printed @@ -671,7 +738,8 @@ static int cross_check_mk_info(int card, int domain, void *handler_data) * -ENOTSUP is returned when the mkvps sysfs attribute is not * available, because the zcrypt kernel module is on an older level. */ -int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks, bool verbose) +int cross_check_apqns(const char *apqns, u64 mkvp, int min_level, + bool print_mks, bool verbose) { struct cross_check_info info; char temp[200]; @@ -680,10 +748,12 @@ int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks, bool verbose) memset(&info, 0, sizeof(info)); info.key_mkvp = mkvp != 0; info.mkvp = mkvp; + info.min_level = min_level; info.verbose = verbose; - pr_verbose(verbose, "Cross checking APQNs with mkvp 0x%016llx: %s", - mkvp, apqns != NULL ? apqns : "ANY"); + pr_verbose(verbose, "Cross checking APQNs with mkvp 0x%016llx and " + "min-level %d: %s", mkvp, min_level, + apqns != NULL ? apqns : "ANY"); rc = handle_apqns(apqns, cross_check_mk_info, &info, verbose); if (rc != 0) diff --git a/zkey/utils.h b/zkey/utils.h index c4dfb2bd..74c44c1e 100644 --- a/zkey/utils.h +++ b/zkey/utils.h @@ -18,6 +18,8 @@ int sysfs_is_card_online(int card); int sysfs_is_apqn_online(int card, int domain); +int sysfs_get_card_level(int card); + int sysfs_get_serialnr(int card, char serialnr[9], bool verbose); #define MK_STATE_EMPTY 0 @@ -48,7 +50,7 @@ int handle_apqns(const char *apqns, apqn_handler_t handler, void *handler_data, int print_mk_info(const char *apqns, bool verbose); -int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks, - bool verbose); +int cross_check_apqns(const char *apqns, u64 mkvp, int min_level, + bool print_mks, bool verbose); #endif diff --git a/zkey/zkey.c b/zkey/zkey.c index d4995281..c7509c78 100644 --- a/zkey/zkey.c +++ b/zkey/zkey.c @@ -1122,7 +1122,9 @@ static int command_generate(void) return EXIT_FAILURE; } - rc = cross_check_apqns(NULL, 0, true, g.verbose); + rc = cross_check_apqns(NULL, 0, + get_min_card_level_for_keytype(g.key_type), + true, g.verbose); if (rc == -EINVAL) return EXIT_FAILURE; if (rc != 0 && rc != -ENOTSUP) { @@ -1447,7 +1449,10 @@ static int command_validate_file(void) printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2, &vp[VERIFICATION_PATTERN_LEN / 2]); - rc = cross_check_apqns(NULL, mkvp, true, g.verbose); + rc = cross_check_apqns(NULL, mkvp, + get_min_card_level_for_keytype( + get_key_type(secure_key, secure_key_size)), + true, g.verbose); if (rc == -EINVAL) return EXIT_FAILURE; if (rc != 0 && rc != -ENOTSUP) {