zkey: Support generating verification patterns for HMAC keys

Similar as for AES keys, a verification pattern is calculated from an HMAC
key by MACing an all zero message of 64 bytes. The first 32 bytes of the
result is the verification pattern.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2024-03-12 14:16:43 +01:00
committed by Jan Höppner
parent a9059449b9
commit d9eee82ab0
5 changed files with 168 additions and 14 deletions

View File

@@ -1958,8 +1958,10 @@ static int _keystore_create_info_file(struct keystore *keystore,
if (rc != 0) {
warnx("Failed to generate the key verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
warnx("Make sure that kernel module '%s' is loaded and "
"that the '%s' cipher is available",
is_aes_key_type(key_type) ? "paes_s390" : "phmac_s390",
is_aes_key_type(key_type) ? "paes" : "phmac");
remove(filenames->pass_filename);
goto out;
}
@@ -2251,8 +2253,10 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
if (rc != 0) {
warnx("Failed to generate the key verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
warnx("Make sure that kernel module '%s' is loaded and "
"that the '%s' cipher is available",
is_aes_key_type(key_type) ? "paes_s390" : "phmac_s390",
is_aes_key_type(key_type) ? "paes" : "phmac");
goto out_free_props;
}
@@ -3698,8 +3702,12 @@ static int _keystore_process_reencipher(struct keystore *keystore,
warnx("Failed to generate the key verification pattern "
"for key '%s': %s", file_names->skey_filename,
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
warnx("Make sure that kernel module '%s' is loaded and "
"that the '%s' cipher is available",
is_aes_key(secure_key, secure_key_size) ?
"paes_s390" : "phmac_s390",
is_aes_key(secure_key, secure_key_size) ?
"paes" : "phmac");
goto out;
}
@@ -5567,8 +5575,12 @@ prompt_alt_name:
if (rc != 0) {
warnx("Failed to generate the key verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
warnx("Make sure that kernel module '%s' is loaded and "
"that the '%s' cipher is available",
is_aes_key(secure_key, secure_key_size) ?
"paes_s390" : "phmac_s390",
is_aes_key(secure_key, secure_key_size) ?
"paes" : "phmac");
fatal_err = true;
goto out_remove;
}

View File

@@ -3445,8 +3445,12 @@ int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
if (rc != 0) {
warnx("Failed to generate the verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is "
"loaded and that the 'paes' cipher is available");
warnx("Make sure that kernel module '%s' is loaded and "
"that the '%s' cipher is available",
is_aes_key(key_blob, key_blob_size) ?
"paes_s390" : "phmac_s390",
is_aes_key(key_blob, key_blob_size) ?
"paes" : "phmac");
goto out;
}

View File

@@ -1623,6 +1623,128 @@ out:
return rc;
}
/**
* Generate a key verification pattern of a secure HMAC key by MACing the all
* zero message with the secure key using the AF_ALG interface
*
* @param[in] key the secure key token
* @param[in] key_size the size of the secure key
* @param[in] vp buffer where the verification pattern is returned
* @param[in] vp_len the size of the buffer
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error
*/
static int generate_hmac_key_verification_pattern(const u8 *key,
size_t key_size,
char *vp, size_t vp_len,
bool verbose)
{
int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0;
char null_msg[MAC_ZERO_LEN];
char mac_zero[MAC_ZERO_LEN];
size_t i, bitsize;
int len;
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "hash",
};
if (vp_len < VERIFICATION_PATTERN_LEN) {
rc = -EMSGSIZE;
goto out;
}
rc = get_key_bit_size(key, key_size, &bitsize);
if (rc != 0) {
pr_verbose(verbose, "Failed to get the key size");
goto out;
}
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "phmac(sha%lu)",
bitsize / 2);
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (tfmfd < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to open an AF_ALG socket");
goto out;
}
if (bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to bind the AF_ALG socket, "
"salg_name='%s' ", sa.salg_name);
goto out;
}
retry_setkey:
if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key,
key_size) < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to set the key: %s",
strerror(-rc));
/*
* After a master key change, it can happen that the setkey
* operation returns EINVAL or EAGAIN, although the key is
* valid. This is a temporary situation and the operation will
* succeed, once the firmware has completed some internal
* processing related with the master key change.
* Delay 1 second and retry up to 10 times.
*/
if ((rc == -EINVAL || rc == -EAGAIN) && retry_count < 10) {
pr_verbose(verbose, "Retrying after 1 second...");
retry_count++;
sleep(1);
goto retry_setkey;
}
goto out;
}
rc = 0;
opfd = accept(tfmfd, NULL, NULL);
if (opfd < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to accept on the AF_ALG socket");
goto out;
}
memset(null_msg, 0, sizeof(null_msg));
len = send(opfd, &null_msg, sizeof(null_msg), 0);
if (len != MAC_ZERO_LEN) {
rc = -errno;
pr_verbose(verbose, "Failed to send to the AF_ALG socket");
goto out;
}
len = read(opfd, mac_zero, sizeof(mac_zero));
if (len < SHA_256_HASH_SIZE) {
rc = -errno;
pr_verbose(verbose, "Failed to receive from the AF_ALG socket");
goto out;
}
memset(vp, 0, vp_len);
for (i = 0; i < SHA_256_HASH_SIZE; i++)
sprintf(&vp[i * 2], "%02x", mac_zero[i]);
pr_verbose(verbose, "Key verification pattern: %s", vp);
out:
if (opfd != -1)
close(opfd);
if (tfmfd != -1)
close(tfmfd);
if (rc != 0)
pr_verbose(verbose, "Failed to generate the key verification "
"pattern: %s", strerror(-rc));
return rc;
}
/**
* Generate a key verification pattern of a secure key by encrypting the all
* zero message with the secure key using the AF_ALG interface
@@ -1638,8 +1760,17 @@ out:
int generate_key_verification_pattern(const u8 *key, size_t key_size,
char *vp, size_t vp_len, bool verbose)
{
return generate_aes_key_verification_pattern(key, key_size, vp, vp_len,
NULL, verbose);
if (is_aes_key(key, key_size))
return generate_aes_key_verification_pattern(key, key_size,
vp, vp_len,
NULL, verbose);
if (is_hmac_key(key, key_size))
return generate_hmac_key_verification_pattern(key, key_size,
vp, vp_len,
verbose);
pr_verbose(verbose, "Neither an AES nor an HMAC key");
return -EINVAL;
}
int get_master_key_verification_pattern(const u8 *key, size_t key_size,

View File

@@ -307,6 +307,9 @@ struct pkey_apqns4keytype {
#define DEFAULT_KEYBITS 256
#define PAES_BLOCK_SIZE 16
#define ENC_ZERO_LEN (2 * PAES_BLOCK_SIZE)
#define SHA_256_HASH_SIZE 32
#define SHA_512_HASH_SIZE 64
#define MAC_ZERO_LEN SHA_512_HASH_SIZE
#define VERIFICATION_PATTERN_LEN (2 * ENC_ZERO_LEN + 1)
#define MKVP_LENGTH 16

View File

@@ -2405,8 +2405,12 @@ static int command_validate_file(void)
if (rc != 0) {
warnx("Failed to generate the verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
warnx("Make sure that kernel module '%s' is loaded and "
"that the '%s' cipher is available",
is_aes_key(secure_key, secure_key_size) ?
"paes_s390" : "phmac_s390",
is_aes_key(secure_key, secure_key_size) ?
"paes" : "phmac");
rc = EXIT_FAILURE;
goto out;
}