zkey: Support validation of key of type PVSECRET-AES

Keys of type PVSECRET-AES can also be verified via the pkey IOCTL
PKEY_VERIFYKEY2, but the card and domain fields must be zero, because such
a key does not use a crypto card. Also XTS keys of type PVSRCRET-AES are
not represented by 2 concatenated keys but by just one key of type
PVSECRET-AES. Thus, special handling is required for XTS keys.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jorg Schmidbauer <jschmidb@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2024-02-19 10:25:54 +01:00
committed by Steffen Eiden
parent a8eb2bd4e7
commit 833a8e7309
6 changed files with 126 additions and 84 deletions

View File

@@ -3055,19 +3055,25 @@ static void _keystore_print_record(struct util_rec *rec,
util_rec_set(rec, REC_XTS, is_xts ? "Yes" : "No");
util_rec_set(rec, REC_KEY_TYPE, key_type);
if (validation) {
if (valid)
util_rec_set(rec, REC_MASTERKEY,
"%s master key (MKVP: %s)",
is_old_mk ? "OLD" : "CURRENT",
printable_mkvp(
get_card_type_for_keytype(key_type),
mkvp));
else
util_rec_set(rec, REC_MASTERKEY,
"(unknown, MKVP: %s)",
printable_mkvp(
get_card_type_for_keytype(key_type),
mkvp));
if (mkvp != NULL) {
if (valid)
util_rec_set(rec, REC_MASTERKEY,
"%s master key (MKVP: %s)",
is_old_mk ? "OLD" : "CURRENT",
printable_mkvp(
get_card_type_for_keytype(
key_type),
mkvp));
else
util_rec_set(rec, REC_MASTERKEY,
"(unknown, MKVP: %s)",
printable_mkvp(
get_card_type_for_keytype(
key_type),
mkvp));
} else {
util_rec_set(rec, REC_MASTERKEY, "(none)");
}
}
if (volumes_argz != NULL)
util_rec_set_argz(rec, REC_VOLUMES, volumes_argz,
@@ -3294,17 +3300,22 @@ static int _keystore_process_validate(struct keystore *keystore,
valid = 1;
}
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
mkvp, keystore->verbose);
if (rc != 0)
goto out;
if (is_secure_key(secure_key, secure_key_size)) {
rc = get_master_key_verification_pattern(secure_key,
secure_key_size,
mkvp,
keystore->verbose);
if (rc != 0)
goto out;
}
_keystore_print_record(info->rec, name, properties, 1,
file_names->skey_filename, secure_key_size,
is_xts_key(secure_key, secure_key_size),
clear_key_bitsize, valid, is_old_mk,
_keystore_reencipher_key_exists(file_names),
mkvp,
is_secure_key(secure_key, secure_key_size) ?
mkvp : NULL,
_keystore_passphrase_file_exists(file_names) ?
file_names->pass_filename : NULL);
@@ -3316,7 +3327,8 @@ static int _keystore_process_validate(struct keystore *keystore,
"master key\n", 0);
info->num_warnings++;
}
if (info->noapqncheck == 0)
if (info->noapqncheck == 0 &&
is_secure_key(secure_key, secure_key_size))
if (_keystore_display_apqn_status(keystore, properties,
mkvp) != 0)
info->num_warnings++;

View File

@@ -1287,33 +1287,43 @@ int validate_secure_key(int pkey_fd,
{
struct pkey_verifykey2 verifykey2;
struct pkey_apqn *list = NULL;
bool xts, valid, securekey;
u32 i, list_entries = 0;
bool xts, valid;
u32 flags;
u32 flags = 0;
int rc;
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
xts = is_xts_key(secure_key, secure_key_size);
securekey = is_secure_key(secure_key, secure_key_size);
xts = securekey ? is_xts_key(secure_key, secure_key_size) : false;
flags = PKEY_FLAGS_MATCH_CUR_MKVP;
if (is_cca_aes_data_key(secure_key, secure_key_size) ||
is_cca_aes_cipher_key(secure_key, secure_key_size))
flags |= PKEY_FLAGS_MATCH_ALT_MKVP;
if (securekey) {
flags = PKEY_FLAGS_MATCH_CUR_MKVP;
if (is_cca_aes_data_key(secure_key, secure_key_size) ||
is_cca_aes_cipher_key(secure_key, secure_key_size))
flags |= PKEY_FLAGS_MATCH_ALT_MKVP;
rc = build_apqn_list_for_key(pkey_fd, secure_key,
HALF_KEYSIZE_FOR_XTS(secure_key_size, xts),
flags, apqns, &list, &list_entries,
verbose);
if (rc != 0) {
pr_verbose(verbose, "Failed to build a list of APQNs that can "
"validate this secure key: %s", strerror(-rc));
return rc;
rc = build_apqn_list_for_key(pkey_fd, secure_key,
HALF_KEYSIZE_FOR_XTS(
secure_key_size, xts),
flags, apqns, &list, &list_entries,
verbose);
if (rc != 0) {
pr_verbose(verbose, "Failed to build a list of APQNs "
"that can validate this secure "
"key: %s", strerror(-rc));
return rc;
}
} else {
list = util_malloc(sizeof(struct pkey_apqn));
list[0].card = 0;
list[0].domain = 0;
list_entries = 1;
}
if (is_old_mk != NULL)
*is_old_mk = true;
*is_old_mk = securekey ? true : false;
if (clear_key_bitsize != NULL)
*clear_key_bitsize = 0;
@@ -1333,7 +1343,7 @@ int validate_secure_key(int pkey_fd,
continue;
}
if (is_xts_key(secure_key, secure_key_size)) {
if (xts) {
rc = validate_secure_xts_key(pkey_fd, &list[i],
secure_key,
secure_key_size,
@@ -1358,7 +1368,7 @@ int validate_secure_key(int pkey_fd,
* If at least one of the APQNs have a matching current MK,
* then don't report OLD, even if some match the old MK.
*/
if (is_old_mk &&
if (securekey && is_old_mk &&
(verifykey2.flags & PKEY_FLAGS_MATCH_CUR_MKVP))
*is_old_mk = false;
}

View File

@@ -68,7 +68,9 @@ It also displays the attributes of the secure key, such as key size, whether
it is a secure key that can be used for the XTS cipher mode, and the master key
register (CURRENT or OLD) with which the secure key is enciphered.
For further information about master key registers, see the
\fBreencipher\fP command.
\fBreencipher\fP command. Keys of type \fBPVSECRET\-AES\fP do not use a
cryptographic adapter, thus no master key information is displayed for such
keys.
.PP
To open a key slot contained in the LUKS2 header of the volume, a passphrase is
required. You are prompted for the passphrase, unless option

View File

@@ -1346,8 +1346,7 @@ static int check_keysize_and_cipher_mode(const u8 *key, size_t keysize)
}
if (strncmp(crypt_get_cipher_mode(g.cd), "xts", 3) == 0) {
if (keysize < 2 * MIN_SECURE_KEY_SIZE ||
(key != NULL && !is_xts_key(key, keysize))) {
if (key != NULL && !is_xts_key(key, keysize)) {
warnx("The volume key size %lu is not valid for the "
"cipher mode '%s'", keysize,
crypt_get_cipher_mode(g.cd));
@@ -1539,8 +1538,9 @@ static int validate_keyslot(int keyslot, char **key, size_t *keysize,
rc = -EINVAL;
goto out;
}
pr_verbose("Volume key is currently enciphered with %s master key",
is_old ? "OLD" : "CURRENT");
if (is_secure_key((u8 *)vkey, vkeysize - ikeysize))
pr_verbose("Volume key is currently enciphered with %s "
"master key", is_old ? "OLD" : "CURRENT");
if (key != NULL)
*key = vkey;
@@ -2023,12 +2023,14 @@ static int command_validate(void)
vp_tok_avail = 1;
}
rc = get_master_key_verification_pattern((u8 *)key, seckeysize,
mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
goto out;
if (is_secure_key((u8 *)key, seckeysize)) {
rc = get_master_key_verification_pattern((u8 *)key, seckeysize,
mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification "
"pattern: %s", strerror(-rc));
goto out;
}
}
key_type = get_key_type((u8 *)key, seckeysize);
@@ -2041,15 +2043,19 @@ static int command_validate(void)
printf(" Key type: %s\n", key_type);
if (is_valid) {
printf(" Clear key size: %lu bits\n", clear_keysize);
printf(" Enciphered with: %s master key (MKVP: "
"%s)\n", is_old_mk ? "OLD" : "CURRENT",
printable_mkvp(get_card_type_for_keytype(key_type),
mkvp));
if (is_secure_key((u8 *)key, seckeysize)) {
printf(" Enciphered with: %s master key (MKVP: "
"%s)\n", is_old_mk ? "OLD" : "CURRENT",
printable_mkvp(get_card_type_for_keytype(
key_type), mkvp));
}
} else {
printf(" Clear key size: (unknown)\n");
printf(" Enciphered with: (unknown, MKVP: %s)\n",
printable_mkvp(get_card_type_for_keytype(key_type),
mkvp));
if (is_secure_key((u8 *)key, seckeysize)) {
printf(" Enciphered with: (unknown, MKVP: %s)\n",
printable_mkvp(get_card_type_for_keytype(
key_type), mkvp));
}
}
if (vp_tok_avail)
print_verification_pattern(vp_tok.verification_pattern);
@@ -2065,7 +2071,7 @@ static int command_validate(void)
if (!is_valid)
printf("\nATTENTION: The secure volume key is not valid.\n");
if (is_old_mk)
if (is_secure_key((u8 *)key, seckeysize) && is_old_mk)
util_print_indented("\nWARNING: The secure volume key is "
"currently enciphered with the OLD "
"master key. To mitigate the danger of "
@@ -2195,7 +2201,8 @@ static int command_setkey(void)
goto out;
}
if (is_old_mk) {
if (is_secure_key(newkey, newkey_size - integrity_keysize) &&
is_old_mk) {
util_asprintf(&msg, "The secure key in file '%s' is "
"enciphered with the master key in the OLD "
"master key register. Do you want to set this "

View File

@@ -209,7 +209,9 @@ It also displays the attributes of the secure key, such as key sizes, whether
it is a secure key that can be used for the XTS cipher mode, the master key
register (CURRENT or OLD) with which the secure key is enciphered, and other key
attributes. For further information about master key registers, see the
\fBreencipher\fP command.
\fBreencipher\fP command. Keys of type \fBPVSECRET\-AES\fP do not use a
cryptographic adapter, thus no master key information is displayed for such
keys.
.PP
The secure key can either be contained in a file in the file system, or in a
secure key repository. To validate a secure key contained in a file, specify
@@ -1599,8 +1601,8 @@ This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-K ", " \-\-key\-type\~\fItype\fP
Specifies the key type of the secure key. Possible values are
\fBCCA\-AESDATA\fP, \fBCCA\-AESCIPHER\fP, and \fBEP11\-AES\fP. Only keys with
the specified key type are listed.
\fBCCA\-AESDATA\fP, \fBCCA\-AESCIPHER\fP, \fBEP11\-AES\fP, and
\fBPVSECRET\-AES\fP. Only keys with the specified key type are listed.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-L ", " \-\-local\fP

View File

@@ -558,9 +558,10 @@ static struct util_opt opt_vec[] = {
.option = { "key-type", required_argument, NULL, 'K'},
.argument = "type",
.desc = "The type of the key. Possible values are '"
KEY_TYPE_CCA_AESDATA"', '"KEY_TYPE_CCA_AESCIPHER"' "
"and '"KEY_TYPE_EP11_AES"'. Use this option to list "
"all keys with the specified key type.",
KEY_TYPE_CCA_AESDATA "', '" KEY_TYPE_CCA_AESCIPHER
"', '" KEY_TYPE_EP11_AES "', and '"
KEY_TYPE_PVSECRET_AES "'. Use this option to list all "
"keys with the specified key type.",
.command = COMMAND_LIST,
},
{
@@ -2345,13 +2346,16 @@ static int command_validate_file(void)
goto out;
}
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification pattern: %s",
strerror(-rc));
rc = EXIT_FAILURE;
goto out;
if (is_secure_key(secure_key, secure_key_size)) {
rc = get_master_key_verification_pattern(secure_key,
secure_key_size,
mkvp, g.verbose);
if (rc != 0) {
warnx("Failed to get the master key verification "
"pattern: %s", strerror(-rc));
rc = EXIT_FAILURE;
goto out;
}
}
key_type = get_key_type(secure_key, secure_key_size);
@@ -2363,25 +2367,30 @@ static int command_validate_file(void)
printf(" Clear key size: %lu bits\n", clear_key_size);
printf(" XTS type key: %s\n",
is_xts_key(secure_key, secure_key_size) ? "Yes" : "No");
printf(" Enciphered with: %s master key (MKVP: %s)\n",
is_old_mk ? "OLD" : "CURRENT",
printable_mkvp(get_card_type_for_keytype(key_type), mkvp));
if (is_secure_key(secure_key, secure_key_size)) {
printf(" Enciphered with: %s master key (MKVP: %s)\n",
is_old_mk ? "OLD" : "CURRENT",
printable_mkvp(get_card_type_for_keytype(key_type),
mkvp));
}
printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,
vp);
printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
&vp[VERIFICATION_PATTERN_LEN / 2]);
rc = cross_check_apqns(NULL, mkvp,
get_min_card_level_for_keytype(key_type),
get_min_fw_version_for_keytype(key_type),
get_card_type_for_keytype(key_type),
true, g.verbose);
if (rc == -EINVAL)
return EXIT_FAILURE;
if (rc != 0 && rc != -ENOTSUP) {
warnx("Your master key setup is improper");
rc = EXIT_FAILURE;
goto out;
if (is_secure_key(secure_key, secure_key_size)) {
rc = cross_check_apqns(NULL, mkvp,
get_min_card_level_for_keytype(key_type),
get_min_fw_version_for_keytype(key_type),
get_card_type_for_keytype(key_type),
true, g.verbose);
if (rc == -EINVAL)
return EXIT_FAILURE;
if (rc != 0 && rc != -ENOTSUP) {
warnx("Your master key setup is improper");
rc = EXIT_FAILURE;
goto out;
}
}
out: