zkey: Support EP11 AES keys with prepended header to retain EP11 session

The pkey kernel module supports two key blob formats for EP11 AES keys.
The first one (PKEY_TYPE_EP11) contains a 16 bytes header that overlays
the first 32 bytes of the key blob which usually contain the ID of the
EP11 session to which the key is bound. For zkey/dm-crypt that session
ID used to be all zeros. The second blob format (PKEY_TYPE_EP11_AES)
prepends the 16 bytes header to the blob, an thus does not overlay the
blob. This format can be used for key blobs that are session-bound, i.e.
have a non-zero session ID in the first 32 bytes.

Change zkey to generate EP11 keys using the new format (i.e. pkey type
PKEY_TYPE_EP11_AES), but existing key blobs using the old format can
still be used.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Joerg Schmidbauer <jschmidb@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Ingo Franzki
2023-07-21 14:06:18 +02:00
committed by Steffen Eiden
parent f46f6d34d3
commit 1b044b8a40
8 changed files with 294 additions and 50 deletions

View File

@@ -5278,9 +5278,11 @@ static int _ep11_unwrap_key_rsa(struct plugin_handle *ph,
m_UnwrapKey_t dll_m_UnwrapKey;
const unsigned char *key_blob;
struct ep11keytoken *ep11key;
struct ep11kblob_header *hdr;
CK_MECHANISM mech = { 0 };
CK_BYTE csum[7] = { 0 };
CK_BBOOL ck_true = true;
int pkey_fd, rc;
CK_RV rv;
CK_ATTRIBUTE template[] = {
@@ -5306,7 +5308,8 @@ static int _ep11_unwrap_key_rsa(struct plugin_handle *ph,
pr_verbose(&ph->pd, "Wrap hashing algorithm: %d",
ph->profile->wrap_hashing_algo);
if (*unwrapped_key_len < sizeof(struct ep11keytoken)) {
if (*unwrapped_key_len < sizeof(struct ep11kblob_header) +
sizeof(struct ep11keytoken)) {
_set_error(ph, "Key buffer is too small");
return -EINVAL;
}
@@ -5381,19 +5384,68 @@ static int _ep11_unwrap_key_rsa(struct plugin_handle *ph,
256 * 256 * csum[csum_len - 3] +
256 * 256 * 256 * csum[csum_len - 4];
/* Setup the EP11 token header */
ep11key = (struct ep11keytoken *)unwrapped_key;
memset(&ep11key->session, 0, sizeof(ep11key->session));
ep11key->head.type = TOKEN_TYPE_NON_CCA;
ep11key->head.length = *unwrapped_key_len;
ep11key->head.version = TOKEN_VERSION_EP11_AES;
ep11key->head.keybitlen = bit_len;
/* Prepend and setup the EP11 token header */
hdr = (struct ep11kblob_header *)unwrapped_key;
ep11key = (struct ep11keytoken *)
(unwrapped_key + sizeof(struct ep11kblob_header));
memmove(ep11key, unwrapped_key, *unwrapped_key_len);
*unwrapped_key_len += sizeof(struct ep11kblob_header);
memset(hdr, 0, sizeof(struct ep11kblob_header));
hdr->type = TOKEN_TYPE_NON_CCA;
hdr->hver = 0;
hdr->len = *unwrapped_key_len;
hdr->version = TOKEN_VERSION_EP11_AES_WITH_HEADER;
hdr->bitlen = bit_len;
pr_verbose(&ph->pd, "unwrapped bit length: %u",
ep11key->head.keybitlen);
pr_verbose(&ph->pd, "unwrapped bit length: %u", hdr->bitlen);
/* return full length, blob is already zero padded */
*unwrapped_key_len = sizeof(struct ep11keytoken);
*unwrapped_key_len =
sizeof(struct ep11kblob_header) + sizeof(struct ep11keytoken);
/*
* Check if the pkey module supports keys of type
* TOKEN_VERSION_EP11_AES_WITH_HEADER, older kernels may not support
* such keys. If it does not support such keys, convert the key to
* TOKEN_VERSION_EP11_AES type, if its session field is all zero
* (i.e. the key is not session bound).
*/
pkey_fd = open_pkey_device(ph->pd.verbose);
if (pkey_fd < 0) {
_set_error(ph, "Failed to open pkey device");
return -EIO;
}
rc = validate_secure_key(pkey_fd, unwrapped_key, *unwrapped_key_len,
NULL, NULL, NULL, ph->pd.verbose);
close(pkey_fd);
if (rc == -EINVAL || rc == -ENODEV) {
pr_verbose(&ph->pd, "The pkey kernel module does not support "
"PKEY_TYPE_EP11_AES, fall back to PKEY_TYPE_EP11");
if (is_ep11_key_session_bound(unwrapped_key,
*unwrapped_key_len)) {
_set_error(ph, "The unwrapped key is session bound. "
"Kernel support is required for such keys");
return -EIO;
}
key_blob_len = hdr->len;
*unwrapped_key_len -= sizeof(struct ep11kblob_header);
memmove(unwrapped_key,
unwrapped_key + sizeof(struct ep11kblob_header),
*unwrapped_key_len);
ep11key = (struct ep11keytoken *)unwrapped_key;
memset(&ep11key->session, 0, sizeof(ep11key->session));
ep11key->head.type = TOKEN_TYPE_NON_CCA;
ep11key->head.len = key_blob_len -
sizeof(struct ep11kblob_header);
ep11key->head.version = TOKEN_VERSION_EP11_AES;
ep11key->head.bitlen = bit_len;
} else if (rc != 0) {
_set_error(ph, "Failed to validate unwrapped key");
return rc;
}
return 0;
}