zkey: Check crypto card level during APQN cross checking

Secure keys of type CCA-AESCIPHER require a CEX6C or newer crypto
card. Also check for the minimum required card level during cross
checking of APQNs. Also display the card level in the APQN report.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2019-07-26 11:18:58 +02:00
committed by Jan Höppner
parent 560b672bfa
commit b7bb90c552
6 changed files with 126 additions and 15 deletions

View File

@@ -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;
}
/**

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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) {