// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright IBM Corp. 2019
* Author(s): Harald Freudenberger <freude@linux.ibm.com>
*
* Collection of EP11 misc functions used by zcrypt and pkey
*/
#define KMSG_COMPONENT "zcrypt"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/export.h>
#include <linux/init.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <asm/zcrypt.h>
#include <asm/pkey.h>
#include <crypto/aes.h>
#include "ap_bus.h"
#include "zcrypt_api.h"
#include "zcrypt_debug.h"
#include "zcrypt_msgtype6.h"
#include "zcrypt_ep11misc.h"
#include "zcrypt_ccamisc.h"
#define EP11_PINBLOB_V1_BYTES 56
/* default iv used here */
static const u8 def_iv[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
/*
* Cprb memory pool held for urgent cases where no memory
* can be allocated via kmalloc. This pool is only used when
* alloc_cprbmem() is called with the xflag ZCRYPT_XFLAG_NOMEMALLOC.
*/
#define CPRB_MEMPOOL_ITEM_SIZE (8 * 1024)
static mempool_t *cprb_mempool;
/*
* This is a pre-allocated memory for the device status array
* used within the ep11_findcard2() function. It is currently
* 128 * 128 * 4 bytes = 64 KB big. Usage of this memory is
* controlled via dev_status_mem_mutex. Needs adaption if more
* than 128 cards or domains to be are supported.
*/
#define ZCRYPT_DEV_STATUS_CARD_MAX 128
#define ZCRYPT_DEV_STATUS_QUEUE_MAX 128
#define ZCRYPT_DEV_STATUS_ENTRIES (ZCRYPT_DEV_STATUS_CARD_MAX * \
ZCRYPT_DEV_STATUS_QUEUE_MAX)
#define ZCRYPT_DEV_STATUS_EXT_SIZE (ZCRYPT_DEV_STATUS_ENTRIES * \
sizeof(struct zcrypt_device_status_ext))
static void *dev_status_mem;
static DEFINE_MUTEX(dev_status_mem_mutex);
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;
}
static int ep11_kb_decode(const u8 *kb, size_t kblen,
struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
struct ep11keyblob **kbpl, size_t *kbplsize)
{
struct ep11kblob_header *tmph, *hdr = NULL;
size_t hdrsize = 0, plsize = 0;
struct ep11keyblob *pl = NULL;
int rc = -EINVAL;
u8 *tmpp;
if (kblen < sizeof(struct ep11kblob_header))
goto out;
tmph = (struct ep11kblob_header *)kb;
if (tmph->type != TOKTYPE_NON_CCA &&
tmph->len > kblen)
goto out;
if (ep11_kb_split(kb, kblen, tmph->version,
&hdr, &hdrsize, &tmpp, &plsize))
goto out;
if (plsize < sizeof(struct ep11keyblob))
goto out;
if (!is_ep11_keyblob(tmpp))
goto out;
pl = (struct ep11keyblob *)tmpp;
plsize = hdr->len - hdrsize;
if (kbhdr)
*kbhdr = hdr;
if (kbhdrsize)
*kbhdrsize = hdrsize;
if (kbpl)
*kbpl = pl;
if (kbplsize)
*kbplsize = plsize;
rc = 0;
out:
return rc;
}
/*
* For valid ep11 keyblobs, returns a reference to the wrappingkey verification
* pattern. Otherwise NULL.
*/
const u8 *ep11_kb_wkvp(const u8 *keyblob, u32 keybloblen)
{
struct ep11keyblob *kb;
if (ep11_kb_deco
|