Skip to content

Commit

Permalink
s390/pkey: fix PKEY_TYPE_EP11_AES handling in PKEY_GENSECK2 IOCTL
Browse files Browse the repository at this point in the history
[ Upstream commit fb249ce ]

Commit 'fa6999e326fe ("s390/pkey: support CCA and EP11 secure ECC
private keys")' introduced PKEY_TYPE_EP11_AES for the PKEY_GENSECK2
IOCTL, to enable userspace to generate securekey blobs of this
type. Unfortunately, all PKEY_GENSECK2 IOCTL requests for
PKEY_TYPE_EP11_AES return with an error (-EINVAL). Fix the handling
for PKEY_TYPE_EP11_AES in PKEY_GENSECK2 IOCTL, so that userspace can
generate securekey blobs of this type.

The start of the header and the keyblob, as well as the length need
special handling, depending on the internal keyversion. Add a helper
function that splits an uninitialized buffer into start and size of
the header as well as start and size of the payload, depending on the
requested keyversion.

Do the header-related calculations and the raw genkey request handling
in separate functions. Use the raw genkey request function for
internal purposes.

Fixes: fa6999e ("s390/pkey: support CCA and EP11 secure ECC private keys")
Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
holger-dengler authored and gregkh committed Sep 13, 2023
1 parent 87d452a commit f98ea9a
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 21 deletions.
18 changes: 13 additions & 5 deletions drivers/s390/crypto/pkey_api.c
Expand Up @@ -565,6 +565,11 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
if (*keybufsize < MINEP11AESKEYBLOBSIZE)
return -EINVAL;
break;
case PKEY_TYPE_EP11_AES:
if (*keybufsize < (sizeof(struct ep11kblob_header) +
MINEP11AESKEYBLOBSIZE))
return -EINVAL;
break;
default:
return -EINVAL;
}
Expand All @@ -581,9 +586,10 @@ static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i].card;
dom = apqns[i].domain;
if (ktype == PKEY_TYPE_EP11) {
if (ktype == PKEY_TYPE_EP11 ||
ktype == PKEY_TYPE_EP11_AES) {
rc = ep11_genaeskey(card, dom, ksize, kflags,
keybuf, keybufsize);
keybuf, keybufsize, ktype);
} else if (ktype == PKEY_TYPE_CCA_DATA) {
rc = cca_genseckey(card, dom, ksize, keybuf);
*keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
Expand Down Expand Up @@ -1313,7 +1319,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries);
if (IS_ERR(apqns))
return PTR_ERR(apqns);
kkey = kmalloc(klen, GFP_KERNEL);
kkey = kzalloc(klen, GFP_KERNEL);
if (!kkey) {
kfree(apqns);
return -ENOMEM;
Expand Down Expand Up @@ -1969,7 +1975,8 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits,
for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
card = apqns[i] >> 16;
dom = apqns[i] & 0xFFFF;
rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize);
rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize,
PKEY_TYPE_EP11);
if (rc == 0)
break;
}
Expand All @@ -1979,7 +1986,8 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits,
if (is_xts) {
keysize = MAXEP11AESKEYBLOBSIZE;
buf += MAXEP11AESKEYBLOBSIZE;
rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize);
rc = ep11_genaeskey(card, dom, keybits, 0, buf, &keysize,
PKEY_TYPE_EP11);
if (rc == 0)
return 2 * MAXEP11AESKEYBLOBSIZE;
}
Expand Down
103 changes: 88 additions & 15 deletions drivers/s390/crypto/zcrypt_ep11misc.c
Expand Up @@ -113,6 +113,50 @@ static void __exit card_cache_free(void)
spin_unlock_bh(&card_list_lock);
}

static int ep11_kb_split(const u8 *kb, size_t kblen, u32 kbver,
struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
u8 **kbpl, size_t *kbplsize)
{
struct ep11kblob_header *hdr = NULL;
size_t hdrsize, plsize = 0;
int rc = -EINVAL;
u8 *pl = NULL;

if (kblen < sizeof(struct ep11kblob_header))
goto out;
hdr = (struct ep11kblob_header *)kb;

switch (kbver) {
case TOKVER_EP11_AES:
/* header overlays the payload */
hdrsize = 0;
break;
case TOKVER_EP11_ECC_WITH_HEADER:
case TOKVER_EP11_AES_WITH_HEADER:
/* payload starts after the header */
hdrsize = sizeof(struct ep11kblob_header);
break;
default:
goto out;
}

plsize = kblen - hdrsize;
pl = (u8 *)kb + hdrsize;

if (kbhdr)
*kbhdr = hdr;
if (kbhdrsize)
*kbhdrsize = hdrsize;
if (kbpl)
*kbpl = pl;
if (kbplsize)
*kbplsize = plsize;

rc = 0;
out:
return rc;
}

/*
* Simple check if the key blob is a valid EP11 AES key blob with header.
*/
Expand Down Expand Up @@ -664,8 +708,9 @@ EXPORT_SYMBOL(ep11_get_domain_info);
*/
#define KEY_ATTR_DEFAULTS 0x00200c00

int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
u8 *keybuf, size_t *keybufsize)
static int _ep11_genaeskey(u16 card, u16 domain,
u32 keybitsize, u32 keygenflags,
u8 *keybuf, size_t *keybufsize)
{
struct keygen_req_pl {
struct pl_head head;
Expand Down Expand Up @@ -701,7 +746,6 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
struct ep11_cprb *req = NULL, *rep = NULL;
struct ep11_target_dev target;
struct ep11_urb *urb = NULL;
struct ep11keyblob *kb;
int api, rc = -ENOMEM;

switch (keybitsize) {
Expand Down Expand Up @@ -780,21 +824,53 @@ int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
goto out;
}

/* copy key blob and set header values */
/* copy key blob */
memcpy(keybuf, rep_pl->data, rep_pl->data_len);
*keybufsize = rep_pl->data_len;
kb = (struct ep11keyblob *)keybuf;
kb->head.type = TOKTYPE_NON_CCA;
kb->head.len = rep_pl->data_len;
kb->head.version = TOKVER_EP11_AES;
kb->head.bitlen = keybitsize;

out:
kfree(req);
kfree(rep);
kfree(urb);
return rc;
}

int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
u8 *keybuf, size_t *keybufsize, u32 keybufver)
{
struct ep11kblob_header *hdr;
size_t hdr_size, pl_size;
u8 *pl;
int rc;

switch (keybufver) {
case TOKVER_EP11_AES:
case TOKVER_EP11_AES_WITH_HEADER:
break;
default:
return -EINVAL;
}

rc = ep11_kb_split(keybuf, *keybufsize, keybufver,
&hdr, &hdr_size, &pl, &pl_size);
if (rc)
return rc;

rc = _ep11_genaeskey(card, domain, keybitsize, keygenflags,
pl, &pl_size);
if (rc)
return rc;

*keybufsize = hdr_size + pl_size;

/* update header information */
hdr->type = TOKTYPE_NON_CCA;
hdr->len = *keybufsize;
hdr->version = keybufver;
hdr->bitlen = keybitsize;

return 0;
}
EXPORT_SYMBOL(ep11_genaeskey);

static int ep11_cryptsingle(u16 card, u16 domain,
Expand Down Expand Up @@ -1201,7 +1277,6 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
const u8 *clrkey, u8 *keybuf, size_t *keybufsize)
{
int rc;
struct ep11keyblob *kb;
u8 encbuf[64], *kek = NULL;
size_t clrkeylen, keklen, encbuflen = sizeof(encbuf);

Expand All @@ -1223,17 +1298,15 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
}

/* Step 1: generate AES 256 bit random kek key */
rc = ep11_genaeskey(card, domain, 256,
0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */
kek, &keklen);
rc = _ep11_genaeskey(card, domain, 256,
0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */
kek, &keklen);
if (rc) {
DEBUG_ERR(
"%s generate kek key failed, rc=%d\n",
__func__, rc);
goto out;
}
kb = (struct ep11keyblob *)kek;
memset(&kb->head, 0, sizeof(kb->head));

/* Step 2: encrypt clear key value with the kek key */
rc = ep11_cryptsingle(card, domain, 0, 0, def_iv, kek, keklen,
Expand Down
2 changes: 1 addition & 1 deletion drivers/s390/crypto/zcrypt_ep11misc.h
Expand Up @@ -107,7 +107,7 @@ int ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info);
* Generate (random) EP11 AES secure key.
*/
int ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
u8 *keybuf, size_t *keybufsize);
u8 *keybuf, size_t *keybufsize, u32 keybufver);

/*
* Generate EP11 AES secure key with given clear key value.
Expand Down

0 comments on commit f98ea9a

Please sign in to comment.