162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright IBM Corp. 2019
462306a36Sopenharmony_ci *  Author(s): Harald Freudenberger <freude@linux.ibm.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Collection of EP11 misc functions used by zcrypt and pkey
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define KMSG_COMPONENT "zcrypt"
1062306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/random.h>
1662306a36Sopenharmony_ci#include <asm/zcrypt.h>
1762306a36Sopenharmony_ci#include <asm/pkey.h>
1862306a36Sopenharmony_ci#include <crypto/aes.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "ap_bus.h"
2162306a36Sopenharmony_ci#include "zcrypt_api.h"
2262306a36Sopenharmony_ci#include "zcrypt_debug.h"
2362306a36Sopenharmony_ci#include "zcrypt_msgtype6.h"
2462306a36Sopenharmony_ci#include "zcrypt_ep11misc.h"
2562306a36Sopenharmony_ci#include "zcrypt_ccamisc.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define DEBUG_DBG(...)	ZCRYPT_DBF(DBF_DEBUG, ##__VA_ARGS__)
2862306a36Sopenharmony_ci#define DEBUG_INFO(...) ZCRYPT_DBF(DBF_INFO, ##__VA_ARGS__)
2962306a36Sopenharmony_ci#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__)
3062306a36Sopenharmony_ci#define DEBUG_ERR(...)	ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define EP11_PINBLOB_V1_BYTES 56
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* default iv used here */
3562306a36Sopenharmony_cistatic const u8 def_iv[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
3662306a36Sopenharmony_ci			       0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* ep11 card info cache */
3962306a36Sopenharmony_cistruct card_list_entry {
4062306a36Sopenharmony_ci	struct list_head list;
4162306a36Sopenharmony_ci	u16 cardnr;
4262306a36Sopenharmony_ci	struct ep11_card_info info;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_cistatic LIST_HEAD(card_list);
4562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(card_list_lock);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int card_cache_fetch(u16 cardnr, struct ep11_card_info *ci)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	int rc = -ENOENT;
5062306a36Sopenharmony_ci	struct card_list_entry *ptr;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	spin_lock_bh(&card_list_lock);
5362306a36Sopenharmony_ci	list_for_each_entry(ptr, &card_list, list) {
5462306a36Sopenharmony_ci		if (ptr->cardnr == cardnr) {
5562306a36Sopenharmony_ci			memcpy(ci, &ptr->info, sizeof(*ci));
5662306a36Sopenharmony_ci			rc = 0;
5762306a36Sopenharmony_ci			break;
5862306a36Sopenharmony_ci		}
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci	spin_unlock_bh(&card_list_lock);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	return rc;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void card_cache_update(u16 cardnr, const struct ep11_card_info *ci)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	int found = 0;
6862306a36Sopenharmony_ci	struct card_list_entry *ptr;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	spin_lock_bh(&card_list_lock);
7162306a36Sopenharmony_ci	list_for_each_entry(ptr, &card_list, list) {
7262306a36Sopenharmony_ci		if (ptr->cardnr == cardnr) {
7362306a36Sopenharmony_ci			memcpy(&ptr->info, ci, sizeof(*ci));
7462306a36Sopenharmony_ci			found = 1;
7562306a36Sopenharmony_ci			break;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	if (!found) {
7962306a36Sopenharmony_ci		ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC);
8062306a36Sopenharmony_ci		if (!ptr) {
8162306a36Sopenharmony_ci			spin_unlock_bh(&card_list_lock);
8262306a36Sopenharmony_ci			return;
8362306a36Sopenharmony_ci		}
8462306a36Sopenharmony_ci		ptr->cardnr = cardnr;
8562306a36Sopenharmony_ci		memcpy(&ptr->info, ci, sizeof(*ci));
8662306a36Sopenharmony_ci		list_add(&ptr->list, &card_list);
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci	spin_unlock_bh(&card_list_lock);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic void card_cache_scrub(u16 cardnr)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct card_list_entry *ptr;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	spin_lock_bh(&card_list_lock);
9662306a36Sopenharmony_ci	list_for_each_entry(ptr, &card_list, list) {
9762306a36Sopenharmony_ci		if (ptr->cardnr == cardnr) {
9862306a36Sopenharmony_ci			list_del(&ptr->list);
9962306a36Sopenharmony_ci			kfree(ptr);
10062306a36Sopenharmony_ci			break;
10162306a36Sopenharmony_ci		}
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci	spin_unlock_bh(&card_list_lock);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void __exit card_cache_free(void)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	struct card_list_entry *ptr, *pnext;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	spin_lock_bh(&card_list_lock);
11162306a36Sopenharmony_ci	list_for_each_entry_safe(ptr, pnext, &card_list, list) {
11262306a36Sopenharmony_ci		list_del(&ptr->list);
11362306a36Sopenharmony_ci		kfree(ptr);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	spin_unlock_bh(&card_list_lock);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic int ep11_kb_split(const u8 *kb, size_t kblen, u32 kbver,
11962306a36Sopenharmony_ci			 struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
12062306a36Sopenharmony_ci			 u8 **kbpl, size_t *kbplsize)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct ep11kblob_header *hdr = NULL;
12362306a36Sopenharmony_ci	size_t hdrsize, plsize = 0;
12462306a36Sopenharmony_ci	int rc = -EINVAL;
12562306a36Sopenharmony_ci	u8 *pl = NULL;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (kblen < sizeof(struct ep11kblob_header))
12862306a36Sopenharmony_ci		goto out;
12962306a36Sopenharmony_ci	hdr = (struct ep11kblob_header *)kb;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	switch (kbver) {
13262306a36Sopenharmony_ci	case TOKVER_EP11_AES:
13362306a36Sopenharmony_ci		/* header overlays the payload */
13462306a36Sopenharmony_ci		hdrsize = 0;
13562306a36Sopenharmony_ci		break;
13662306a36Sopenharmony_ci	case TOKVER_EP11_ECC_WITH_HEADER:
13762306a36Sopenharmony_ci	case TOKVER_EP11_AES_WITH_HEADER:
13862306a36Sopenharmony_ci		/* payload starts after the header */
13962306a36Sopenharmony_ci		hdrsize = sizeof(struct ep11kblob_header);
14062306a36Sopenharmony_ci		break;
14162306a36Sopenharmony_ci	default:
14262306a36Sopenharmony_ci		goto out;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	plsize = kblen - hdrsize;
14662306a36Sopenharmony_ci	pl = (u8 *)kb + hdrsize;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (kbhdr)
14962306a36Sopenharmony_ci		*kbhdr = hdr;
15062306a36Sopenharmony_ci	if (kbhdrsize)
15162306a36Sopenharmony_ci		*kbhdrsize = hdrsize;
15262306a36Sopenharmony_ci	if (kbpl)
15362306a36Sopenharmony_ci		*kbpl = pl;
15462306a36Sopenharmony_ci	if (kbplsize)
15562306a36Sopenharmony_ci		*kbplsize = plsize;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	rc = 0;
15862306a36Sopenharmony_ciout:
15962306a36Sopenharmony_ci	return rc;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int ep11_kb_decode(const u8 *kb, size_t kblen,
16362306a36Sopenharmony_ci			  struct ep11kblob_header **kbhdr, size_t *kbhdrsize,
16462306a36Sopenharmony_ci			  struct ep11keyblob **kbpl, size_t *kbplsize)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct ep11kblob_header *tmph, *hdr = NULL;
16762306a36Sopenharmony_ci	size_t hdrsize = 0, plsize = 0;
16862306a36Sopenharmony_ci	struct ep11keyblob *pl = NULL;
16962306a36Sopenharmony_ci	int rc = -EINVAL;
17062306a36Sopenharmony_ci	u8 *tmpp;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (kblen < sizeof(struct ep11kblob_header))
17362306a36Sopenharmony_ci		goto out;
17462306a36Sopenharmony_ci	tmph = (struct ep11kblob_header *)kb;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (tmph->type != TOKTYPE_NON_CCA &&
17762306a36Sopenharmony_ci	    tmph->len > kblen)
17862306a36Sopenharmony_ci		goto out;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (ep11_kb_split(kb, kblen, tmph->version,
18162306a36Sopenharmony_ci			  &hdr, &hdrsize, &tmpp, &plsize))
18262306a36Sopenharmony_ci		goto out;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (plsize < sizeof(struct ep11keyblob))
18562306a36Sopenharmony_ci		goto out;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	if (!is_ep11_keyblob(tmpp))
18862306a36Sopenharmony_ci		goto out;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	pl = (struct ep11keyblob *)tmpp;
19162306a36Sopenharmony_ci	plsize = hdr->len - hdrsize;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (kbhdr)
19462306a36Sopenharmony_ci		*kbhdr = hdr;
19562306a36Sopenharmony_ci	if (kbhdrsize)
19662306a36Sopenharmony_ci		*kbhdrsize = hdrsize;
19762306a36Sopenharmony_ci	if (kbpl)
19862306a36Sopenharmony_ci		*kbpl = pl;
19962306a36Sopenharmony_ci	if (kbplsize)
20062306a36Sopenharmony_ci		*kbplsize = plsize;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	rc = 0;
20362306a36Sopenharmony_ciout:
20462306a36Sopenharmony_ci	return rc;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/*
20862306a36Sopenharmony_ci * For valid ep11 keyblobs, returns a reference to the wrappingkey verification
20962306a36Sopenharmony_ci * pattern. Otherwise NULL.
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_ciconst u8 *ep11_kb_wkvp(const u8 *keyblob, size_t keybloblen)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct ep11keyblob *kb;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (ep11_kb_decode(keyblob, keybloblen, NULL, NULL, &kb, NULL))
21662306a36Sopenharmony_ci		return NULL;
21762306a36Sopenharmony_ci	return kb->wkvp;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_kb_wkvp);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/*
22262306a36Sopenharmony_ci * Simple check if the key blob is a valid EP11 AES key blob with header.
22362306a36Sopenharmony_ci */
22462306a36Sopenharmony_ciint ep11_check_aes_key_with_hdr(debug_info_t *dbg, int dbflvl,
22562306a36Sopenharmony_ci				const u8 *key, size_t keylen, int checkcpacfexp)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct ep11kblob_header *hdr = (struct ep11kblob_header *)key;
22862306a36Sopenharmony_ci	struct ep11keyblob *kb = (struct ep11keyblob *)(key + sizeof(*hdr));
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (keylen < sizeof(*hdr) + sizeof(*kb)) {
23362306a36Sopenharmony_ci		DBF("%s key check failed, keylen %zu < %zu\n",
23462306a36Sopenharmony_ci		    __func__, keylen, sizeof(*hdr) + sizeof(*kb));
23562306a36Sopenharmony_ci		return -EINVAL;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (hdr->type != TOKTYPE_NON_CCA) {
23962306a36Sopenharmony_ci		if (dbg)
24062306a36Sopenharmony_ci			DBF("%s key check failed, type 0x%02x != 0x%02x\n",
24162306a36Sopenharmony_ci			    __func__, (int)hdr->type, TOKTYPE_NON_CCA);
24262306a36Sopenharmony_ci		return -EINVAL;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci	if (hdr->hver != 0x00) {
24562306a36Sopenharmony_ci		if (dbg)
24662306a36Sopenharmony_ci			DBF("%s key check failed, header version 0x%02x != 0x00\n",
24762306a36Sopenharmony_ci			    __func__, (int)hdr->hver);
24862306a36Sopenharmony_ci		return -EINVAL;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	if (hdr->version != TOKVER_EP11_AES_WITH_HEADER) {
25162306a36Sopenharmony_ci		if (dbg)
25262306a36Sopenharmony_ci			DBF("%s key check failed, version 0x%02x != 0x%02x\n",
25362306a36Sopenharmony_ci			    __func__, (int)hdr->version, TOKVER_EP11_AES_WITH_HEADER);
25462306a36Sopenharmony_ci		return -EINVAL;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	if (hdr->len > keylen) {
25762306a36Sopenharmony_ci		if (dbg)
25862306a36Sopenharmony_ci			DBF("%s key check failed, header len %d keylen %zu mismatch\n",
25962306a36Sopenharmony_ci			    __func__, (int)hdr->len, keylen);
26062306a36Sopenharmony_ci		return -EINVAL;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	if (hdr->len < sizeof(*hdr) + sizeof(*kb)) {
26362306a36Sopenharmony_ci		if (dbg)
26462306a36Sopenharmony_ci			DBF("%s key check failed, header len %d < %zu\n",
26562306a36Sopenharmony_ci			    __func__, (int)hdr->len, sizeof(*hdr) + sizeof(*kb));
26662306a36Sopenharmony_ci		return -EINVAL;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (kb->version != EP11_STRUCT_MAGIC) {
27062306a36Sopenharmony_ci		if (dbg)
27162306a36Sopenharmony_ci			DBF("%s key check failed, blob magic 0x%04x != 0x%04x\n",
27262306a36Sopenharmony_ci			    __func__, (int)kb->version, EP11_STRUCT_MAGIC);
27362306a36Sopenharmony_ci		return -EINVAL;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci	if (checkcpacfexp && !(kb->attr & EP11_BLOB_PKEY_EXTRACTABLE)) {
27662306a36Sopenharmony_ci		if (dbg)
27762306a36Sopenharmony_ci			DBF("%s key check failed, PKEY_EXTRACTABLE is off\n",
27862306a36Sopenharmony_ci			    __func__);
27962306a36Sopenharmony_ci		return -EINVAL;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci#undef DBF
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return 0;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_check_aes_key_with_hdr);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci/*
28962306a36Sopenharmony_ci * Simple check if the key blob is a valid EP11 ECC key blob with header.
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_ciint ep11_check_ecc_key_with_hdr(debug_info_t *dbg, int dbflvl,
29262306a36Sopenharmony_ci				const u8 *key, size_t keylen, int checkcpacfexp)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct ep11kblob_header *hdr = (struct ep11kblob_header *)key;
29562306a36Sopenharmony_ci	struct ep11keyblob *kb = (struct ep11keyblob *)(key + sizeof(*hdr));
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (keylen < sizeof(*hdr) + sizeof(*kb)) {
30062306a36Sopenharmony_ci		DBF("%s key check failed, keylen %zu < %zu\n",
30162306a36Sopenharmony_ci		    __func__, keylen, sizeof(*hdr) + sizeof(*kb));
30262306a36Sopenharmony_ci		return -EINVAL;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (hdr->type != TOKTYPE_NON_CCA) {
30662306a36Sopenharmony_ci		if (dbg)
30762306a36Sopenharmony_ci			DBF("%s key check failed, type 0x%02x != 0x%02x\n",
30862306a36Sopenharmony_ci			    __func__, (int)hdr->type, TOKTYPE_NON_CCA);
30962306a36Sopenharmony_ci		return -EINVAL;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci	if (hdr->hver != 0x00) {
31262306a36Sopenharmony_ci		if (dbg)
31362306a36Sopenharmony_ci			DBF("%s key check failed, header version 0x%02x != 0x00\n",
31462306a36Sopenharmony_ci			    __func__, (int)hdr->hver);
31562306a36Sopenharmony_ci		return -EINVAL;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci	if (hdr->version != TOKVER_EP11_ECC_WITH_HEADER) {
31862306a36Sopenharmony_ci		if (dbg)
31962306a36Sopenharmony_ci			DBF("%s key check failed, version 0x%02x != 0x%02x\n",
32062306a36Sopenharmony_ci			    __func__, (int)hdr->version, TOKVER_EP11_ECC_WITH_HEADER);
32162306a36Sopenharmony_ci		return -EINVAL;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci	if (hdr->len > keylen) {
32462306a36Sopenharmony_ci		if (dbg)
32562306a36Sopenharmony_ci			DBF("%s key check failed, header len %d keylen %zu mismatch\n",
32662306a36Sopenharmony_ci			    __func__, (int)hdr->len, keylen);
32762306a36Sopenharmony_ci		return -EINVAL;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci	if (hdr->len < sizeof(*hdr) + sizeof(*kb)) {
33062306a36Sopenharmony_ci		if (dbg)
33162306a36Sopenharmony_ci			DBF("%s key check failed, header len %d < %zu\n",
33262306a36Sopenharmony_ci			    __func__, (int)hdr->len, sizeof(*hdr) + sizeof(*kb));
33362306a36Sopenharmony_ci		return -EINVAL;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (kb->version != EP11_STRUCT_MAGIC) {
33762306a36Sopenharmony_ci		if (dbg)
33862306a36Sopenharmony_ci			DBF("%s key check failed, blob magic 0x%04x != 0x%04x\n",
33962306a36Sopenharmony_ci			    __func__, (int)kb->version, EP11_STRUCT_MAGIC);
34062306a36Sopenharmony_ci		return -EINVAL;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	if (checkcpacfexp && !(kb->attr & EP11_BLOB_PKEY_EXTRACTABLE)) {
34362306a36Sopenharmony_ci		if (dbg)
34462306a36Sopenharmony_ci			DBF("%s key check failed, PKEY_EXTRACTABLE is off\n",
34562306a36Sopenharmony_ci			    __func__);
34662306a36Sopenharmony_ci		return -EINVAL;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci#undef DBF
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return 0;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_check_ecc_key_with_hdr);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci/*
35662306a36Sopenharmony_ci * Simple check if the key blob is a valid EP11 AES key blob with
35762306a36Sopenharmony_ci * the header in the session field (old style EP11 AES key).
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_ciint ep11_check_aes_key(debug_info_t *dbg, int dbflvl,
36062306a36Sopenharmony_ci		       const u8 *key, size_t keylen, int checkcpacfexp)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct ep11keyblob *kb = (struct ep11keyblob *)key;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (keylen < sizeof(*kb)) {
36762306a36Sopenharmony_ci		DBF("%s key check failed, keylen %zu < %zu\n",
36862306a36Sopenharmony_ci		    __func__, keylen, sizeof(*kb));
36962306a36Sopenharmony_ci		return -EINVAL;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (kb->head.type != TOKTYPE_NON_CCA) {
37362306a36Sopenharmony_ci		if (dbg)
37462306a36Sopenharmony_ci			DBF("%s key check failed, type 0x%02x != 0x%02x\n",
37562306a36Sopenharmony_ci			    __func__, (int)kb->head.type, TOKTYPE_NON_CCA);
37662306a36Sopenharmony_ci		return -EINVAL;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	if (kb->head.version != TOKVER_EP11_AES) {
37962306a36Sopenharmony_ci		if (dbg)
38062306a36Sopenharmony_ci			DBF("%s key check failed, version 0x%02x != 0x%02x\n",
38162306a36Sopenharmony_ci			    __func__, (int)kb->head.version, TOKVER_EP11_AES);
38262306a36Sopenharmony_ci		return -EINVAL;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	if (kb->head.len > keylen) {
38562306a36Sopenharmony_ci		if (dbg)
38662306a36Sopenharmony_ci			DBF("%s key check failed, header len %d keylen %zu mismatch\n",
38762306a36Sopenharmony_ci			    __func__, (int)kb->head.len, keylen);
38862306a36Sopenharmony_ci		return -EINVAL;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci	if (kb->head.len < sizeof(*kb)) {
39162306a36Sopenharmony_ci		if (dbg)
39262306a36Sopenharmony_ci			DBF("%s key check failed, header len %d < %zu\n",
39362306a36Sopenharmony_ci			    __func__, (int)kb->head.len, sizeof(*kb));
39462306a36Sopenharmony_ci		return -EINVAL;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (kb->version != EP11_STRUCT_MAGIC) {
39862306a36Sopenharmony_ci		if (dbg)
39962306a36Sopenharmony_ci			DBF("%s key check failed, blob magic 0x%04x != 0x%04x\n",
40062306a36Sopenharmony_ci			    __func__, (int)kb->version, EP11_STRUCT_MAGIC);
40162306a36Sopenharmony_ci		return -EINVAL;
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci	if (checkcpacfexp && !(kb->attr & EP11_BLOB_PKEY_EXTRACTABLE)) {
40462306a36Sopenharmony_ci		if (dbg)
40562306a36Sopenharmony_ci			DBF("%s key check failed, PKEY_EXTRACTABLE is off\n",
40662306a36Sopenharmony_ci			    __func__);
40762306a36Sopenharmony_ci		return -EINVAL;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci#undef DBF
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return 0;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_check_aes_key);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/*
41762306a36Sopenharmony_ci * Allocate and prepare ep11 cprb plus additional payload.
41862306a36Sopenharmony_ci */
41962306a36Sopenharmony_cistatic inline struct ep11_cprb *alloc_cprb(size_t payload_len)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	size_t len = sizeof(struct ep11_cprb) + payload_len;
42262306a36Sopenharmony_ci	struct ep11_cprb *cprb;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	cprb = kzalloc(len, GFP_KERNEL);
42562306a36Sopenharmony_ci	if (!cprb)
42662306a36Sopenharmony_ci		return NULL;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	cprb->cprb_len = sizeof(struct ep11_cprb);
42962306a36Sopenharmony_ci	cprb->cprb_ver_id = 0x04;
43062306a36Sopenharmony_ci	memcpy(cprb->func_id, "T4", 2);
43162306a36Sopenharmony_ci	cprb->ret_code = 0xFFFFFFFF;
43262306a36Sopenharmony_ci	cprb->payload_len = payload_len;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return cprb;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/*
43862306a36Sopenharmony_ci * Some helper functions related to ASN1 encoding.
43962306a36Sopenharmony_ci * Limited to length info <= 2 byte.
44062306a36Sopenharmony_ci */
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci#define ASN1TAGLEN(x) (2 + (x) + ((x) > 127 ? 1 : 0) + ((x) > 255 ? 1 : 0))
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic int asn1tag_write(u8 *ptr, u8 tag, const u8 *pvalue, u16 valuelen)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	ptr[0] = tag;
44762306a36Sopenharmony_ci	if (valuelen > 255) {
44862306a36Sopenharmony_ci		ptr[1] = 0x82;
44962306a36Sopenharmony_ci		*((u16 *)(ptr + 2)) = valuelen;
45062306a36Sopenharmony_ci		memcpy(ptr + 4, pvalue, valuelen);
45162306a36Sopenharmony_ci		return 4 + valuelen;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci	if (valuelen > 127) {
45462306a36Sopenharmony_ci		ptr[1] = 0x81;
45562306a36Sopenharmony_ci		ptr[2] = (u8)valuelen;
45662306a36Sopenharmony_ci		memcpy(ptr + 3, pvalue, valuelen);
45762306a36Sopenharmony_ci		return 3 + valuelen;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	ptr[1] = (u8)valuelen;
46062306a36Sopenharmony_ci	memcpy(ptr + 2, pvalue, valuelen);
46162306a36Sopenharmony_ci	return 2 + valuelen;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci/* EP11 payload > 127 bytes starts with this struct */
46562306a36Sopenharmony_cistruct pl_head {
46662306a36Sopenharmony_ci	u8  tag;
46762306a36Sopenharmony_ci	u8  lenfmt;
46862306a36Sopenharmony_ci	u16 len;
46962306a36Sopenharmony_ci	u8  func_tag;
47062306a36Sopenharmony_ci	u8  func_len;
47162306a36Sopenharmony_ci	u32 func;
47262306a36Sopenharmony_ci	u8  dom_tag;
47362306a36Sopenharmony_ci	u8  dom_len;
47462306a36Sopenharmony_ci	u32 dom;
47562306a36Sopenharmony_ci} __packed;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci/* prep ep11 payload head helper function */
47862306a36Sopenharmony_cistatic inline void prep_head(struct pl_head *h,
47962306a36Sopenharmony_ci			     size_t pl_size, int api, int func)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	h->tag = 0x30;
48262306a36Sopenharmony_ci	h->lenfmt = 0x82;
48362306a36Sopenharmony_ci	h->len = pl_size - 4;
48462306a36Sopenharmony_ci	h->func_tag = 0x04;
48562306a36Sopenharmony_ci	h->func_len = sizeof(u32);
48662306a36Sopenharmony_ci	h->func = (api << 16) + func;
48762306a36Sopenharmony_ci	h->dom_tag = 0x04;
48862306a36Sopenharmony_ci	h->dom_len = sizeof(u32);
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci/* prep urb helper function */
49262306a36Sopenharmony_cistatic inline void prep_urb(struct ep11_urb *u,
49362306a36Sopenharmony_ci			    struct ep11_target_dev *t, int nt,
49462306a36Sopenharmony_ci			    struct ep11_cprb *req, size_t req_len,
49562306a36Sopenharmony_ci			    struct ep11_cprb *rep, size_t rep_len)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	u->targets = (u8 __user *)t;
49862306a36Sopenharmony_ci	u->targets_num = nt;
49962306a36Sopenharmony_ci	u->req = (u8 __user *)req;
50062306a36Sopenharmony_ci	u->req_len = req_len;
50162306a36Sopenharmony_ci	u->resp = (u8 __user *)rep;
50262306a36Sopenharmony_ci	u->resp_len = rep_len;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci/* Check ep11 reply payload, return 0 or suggested errno value. */
50662306a36Sopenharmony_cistatic int check_reply_pl(const u8 *pl, const char *func)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	int len;
50962306a36Sopenharmony_ci	u32 ret;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* start tag */
51262306a36Sopenharmony_ci	if (*pl++ != 0x30) {
51362306a36Sopenharmony_ci		DEBUG_ERR("%s reply start tag mismatch\n", func);
51462306a36Sopenharmony_ci		return -EIO;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* payload length format */
51862306a36Sopenharmony_ci	if (*pl < 127) {
51962306a36Sopenharmony_ci		len = *pl;
52062306a36Sopenharmony_ci		pl++;
52162306a36Sopenharmony_ci	} else if (*pl == 0x81) {
52262306a36Sopenharmony_ci		pl++;
52362306a36Sopenharmony_ci		len = *pl;
52462306a36Sopenharmony_ci		pl++;
52562306a36Sopenharmony_ci	} else if (*pl == 0x82) {
52662306a36Sopenharmony_ci		pl++;
52762306a36Sopenharmony_ci		len = *((u16 *)pl);
52862306a36Sopenharmony_ci		pl += 2;
52962306a36Sopenharmony_ci	} else {
53062306a36Sopenharmony_ci		DEBUG_ERR("%s reply start tag lenfmt mismatch 0x%02hhx\n",
53162306a36Sopenharmony_ci			  func, *pl);
53262306a36Sopenharmony_ci		return -EIO;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/* len should cover at least 3 fields with 32 bit value each */
53662306a36Sopenharmony_ci	if (len < 3 * 6) {
53762306a36Sopenharmony_ci		DEBUG_ERR("%s reply length %d too small\n", func, len);
53862306a36Sopenharmony_ci		return -EIO;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	/* function tag, length and value */
54262306a36Sopenharmony_ci	if (pl[0] != 0x04 || pl[1] != 0x04) {
54362306a36Sopenharmony_ci		DEBUG_ERR("%s function tag or length mismatch\n", func);
54462306a36Sopenharmony_ci		return -EIO;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci	pl += 6;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	/* dom tag, length and value */
54962306a36Sopenharmony_ci	if (pl[0] != 0x04 || pl[1] != 0x04) {
55062306a36Sopenharmony_ci		DEBUG_ERR("%s dom tag or length mismatch\n", func);
55162306a36Sopenharmony_ci		return -EIO;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci	pl += 6;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* return value tag, length and value */
55662306a36Sopenharmony_ci	if (pl[0] != 0x04 || pl[1] != 0x04) {
55762306a36Sopenharmony_ci		DEBUG_ERR("%s return value tag or length mismatch\n", func);
55862306a36Sopenharmony_ci		return -EIO;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci	pl += 2;
56162306a36Sopenharmony_ci	ret = *((u32 *)pl);
56262306a36Sopenharmony_ci	if (ret != 0) {
56362306a36Sopenharmony_ci		DEBUG_ERR("%s return value 0x%04x != 0\n", func, ret);
56462306a36Sopenharmony_ci		return -EIO;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return 0;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci/*
57162306a36Sopenharmony_ci * Helper function which does an ep11 query with given query type.
57262306a36Sopenharmony_ci */
57362306a36Sopenharmony_cistatic int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
57462306a36Sopenharmony_ci			   size_t buflen, u8 *buf)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	struct ep11_info_req_pl {
57762306a36Sopenharmony_ci		struct pl_head head;
57862306a36Sopenharmony_ci		u8  query_type_tag;
57962306a36Sopenharmony_ci		u8  query_type_len;
58062306a36Sopenharmony_ci		u32 query_type;
58162306a36Sopenharmony_ci		u8  query_subtype_tag;
58262306a36Sopenharmony_ci		u8  query_subtype_len;
58362306a36Sopenharmony_ci		u32 query_subtype;
58462306a36Sopenharmony_ci	} __packed * req_pl;
58562306a36Sopenharmony_ci	struct ep11_info_rep_pl {
58662306a36Sopenharmony_ci		struct pl_head head;
58762306a36Sopenharmony_ci		u8  rc_tag;
58862306a36Sopenharmony_ci		u8  rc_len;
58962306a36Sopenharmony_ci		u32 rc;
59062306a36Sopenharmony_ci		u8  data_tag;
59162306a36Sopenharmony_ci		u8  data_lenfmt;
59262306a36Sopenharmony_ci		u16 data_len;
59362306a36Sopenharmony_ci	} __packed * rep_pl;
59462306a36Sopenharmony_ci	struct ep11_cprb *req = NULL, *rep = NULL;
59562306a36Sopenharmony_ci	struct ep11_target_dev target;
59662306a36Sopenharmony_ci	struct ep11_urb *urb = NULL;
59762306a36Sopenharmony_ci	int api = EP11_API_V1, rc = -ENOMEM;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/* request cprb and payload */
60062306a36Sopenharmony_ci	req = alloc_cprb(sizeof(struct ep11_info_req_pl));
60162306a36Sopenharmony_ci	if (!req)
60262306a36Sopenharmony_ci		goto out;
60362306a36Sopenharmony_ci	req_pl = (struct ep11_info_req_pl *)(((u8 *)req) + sizeof(*req));
60462306a36Sopenharmony_ci	prep_head(&req_pl->head, sizeof(*req_pl), api, 38); /* get xcp info */
60562306a36Sopenharmony_ci	req_pl->query_type_tag = 0x04;
60662306a36Sopenharmony_ci	req_pl->query_type_len = sizeof(u32);
60762306a36Sopenharmony_ci	req_pl->query_type = query_type;
60862306a36Sopenharmony_ci	req_pl->query_subtype_tag = 0x04;
60962306a36Sopenharmony_ci	req_pl->query_subtype_len = sizeof(u32);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/* reply cprb and payload */
61262306a36Sopenharmony_ci	rep = alloc_cprb(sizeof(struct ep11_info_rep_pl) + buflen);
61362306a36Sopenharmony_ci	if (!rep)
61462306a36Sopenharmony_ci		goto out;
61562306a36Sopenharmony_ci	rep_pl = (struct ep11_info_rep_pl *)(((u8 *)rep) + sizeof(*rep));
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	/* urb and target */
61862306a36Sopenharmony_ci	urb = kmalloc(sizeof(*urb), GFP_KERNEL);
61962306a36Sopenharmony_ci	if (!urb)
62062306a36Sopenharmony_ci		goto out;
62162306a36Sopenharmony_ci	target.ap_id = cardnr;
62262306a36Sopenharmony_ci	target.dom_id = domain;
62362306a36Sopenharmony_ci	prep_urb(urb, &target, 1,
62462306a36Sopenharmony_ci		 req, sizeof(*req) + sizeof(*req_pl),
62562306a36Sopenharmony_ci		 rep, sizeof(*rep) + sizeof(*rep_pl) + buflen);
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	rc = zcrypt_send_ep11_cprb(urb);
62862306a36Sopenharmony_ci	if (rc) {
62962306a36Sopenharmony_ci		DEBUG_ERR(
63062306a36Sopenharmony_ci			"%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
63162306a36Sopenharmony_ci			__func__, (int)cardnr, (int)domain, rc);
63262306a36Sopenharmony_ci		goto out;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	rc = check_reply_pl((u8 *)rep_pl, __func__);
63662306a36Sopenharmony_ci	if (rc)
63762306a36Sopenharmony_ci		goto out;
63862306a36Sopenharmony_ci	if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
63962306a36Sopenharmony_ci		DEBUG_ERR("%s unknown reply data format\n", __func__);
64062306a36Sopenharmony_ci		rc = -EIO;
64162306a36Sopenharmony_ci		goto out;
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci	if (rep_pl->data_len > buflen) {
64462306a36Sopenharmony_ci		DEBUG_ERR("%s mismatch between reply data len and buffer len\n",
64562306a36Sopenharmony_ci			  __func__);
64662306a36Sopenharmony_ci		rc = -ENOSPC;
64762306a36Sopenharmony_ci		goto out;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	memcpy(buf, ((u8 *)rep_pl) + sizeof(*rep_pl), rep_pl->data_len);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ciout:
65362306a36Sopenharmony_ci	kfree(req);
65462306a36Sopenharmony_ci	kfree(rep);
65562306a36Sopenharmony_ci	kfree(urb);
65662306a36Sopenharmony_ci	return rc;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/*
66062306a36Sopenharmony_ci * Provide information about an EP11 card.
66162306a36Sopenharmony_ci */
66262306a36Sopenharmony_ciint ep11_get_card_info(u16 card, struct ep11_card_info *info, int verify)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	int rc;
66562306a36Sopenharmony_ci	struct ep11_module_query_info {
66662306a36Sopenharmony_ci		u32 API_ord_nr;
66762306a36Sopenharmony_ci		u32 firmware_id;
66862306a36Sopenharmony_ci		u8  FW_major_vers;
66962306a36Sopenharmony_ci		u8  FW_minor_vers;
67062306a36Sopenharmony_ci		u8  CSP_major_vers;
67162306a36Sopenharmony_ci		u8  CSP_minor_vers;
67262306a36Sopenharmony_ci		u8  fwid[32];
67362306a36Sopenharmony_ci		u8  xcp_config_hash[32];
67462306a36Sopenharmony_ci		u8  CSP_config_hash[32];
67562306a36Sopenharmony_ci		u8  serial[16];
67662306a36Sopenharmony_ci		u8  module_date_time[16];
67762306a36Sopenharmony_ci		u64 op_mode;
67862306a36Sopenharmony_ci		u32 PKCS11_flags;
67962306a36Sopenharmony_ci		u32 ext_flags;
68062306a36Sopenharmony_ci		u32 domains;
68162306a36Sopenharmony_ci		u32 sym_state_bytes;
68262306a36Sopenharmony_ci		u32 digest_state_bytes;
68362306a36Sopenharmony_ci		u32 pin_blob_bytes;
68462306a36Sopenharmony_ci		u32 SPKI_bytes;
68562306a36Sopenharmony_ci		u32 priv_key_blob_bytes;
68662306a36Sopenharmony_ci		u32 sym_blob_bytes;
68762306a36Sopenharmony_ci		u32 max_payload_bytes;
68862306a36Sopenharmony_ci		u32 CP_profile_bytes;
68962306a36Sopenharmony_ci		u32 max_CP_index;
69062306a36Sopenharmony_ci	} __packed * pmqi = NULL;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	rc = card_cache_fetch(card, info);
69362306a36Sopenharmony_ci	if (rc || verify) {
69462306a36Sopenharmony_ci		pmqi = kmalloc(sizeof(*pmqi), GFP_KERNEL);
69562306a36Sopenharmony_ci		if (!pmqi)
69662306a36Sopenharmony_ci			return -ENOMEM;
69762306a36Sopenharmony_ci		rc = ep11_query_info(card, AUTOSEL_DOM,
69862306a36Sopenharmony_ci				     0x01 /* module info query */,
69962306a36Sopenharmony_ci				     sizeof(*pmqi), (u8 *)pmqi);
70062306a36Sopenharmony_ci		if (rc) {
70162306a36Sopenharmony_ci			if (rc == -ENODEV)
70262306a36Sopenharmony_ci				card_cache_scrub(card);
70362306a36Sopenharmony_ci			goto out;
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci		memset(info, 0, sizeof(*info));
70662306a36Sopenharmony_ci		info->API_ord_nr = pmqi->API_ord_nr;
70762306a36Sopenharmony_ci		info->FW_version =
70862306a36Sopenharmony_ci			(pmqi->FW_major_vers << 8) + pmqi->FW_minor_vers;
70962306a36Sopenharmony_ci		memcpy(info->serial, pmqi->serial, sizeof(info->serial));
71062306a36Sopenharmony_ci		info->op_mode = pmqi->op_mode;
71162306a36Sopenharmony_ci		card_cache_update(card, info);
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ciout:
71562306a36Sopenharmony_ci	kfree(pmqi);
71662306a36Sopenharmony_ci	return rc;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_get_card_info);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci/*
72162306a36Sopenharmony_ci * Provide information about a domain within an EP11 card.
72262306a36Sopenharmony_ci */
72362306a36Sopenharmony_ciint ep11_get_domain_info(u16 card, u16 domain, struct ep11_domain_info *info)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	int rc;
72662306a36Sopenharmony_ci	struct ep11_domain_query_info {
72762306a36Sopenharmony_ci		u32 dom_index;
72862306a36Sopenharmony_ci		u8  cur_WK_VP[32];
72962306a36Sopenharmony_ci		u8  new_WK_VP[32];
73062306a36Sopenharmony_ci		u32 dom_flags;
73162306a36Sopenharmony_ci		u64 op_mode;
73262306a36Sopenharmony_ci	} __packed * p_dom_info;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	p_dom_info = kmalloc(sizeof(*p_dom_info), GFP_KERNEL);
73562306a36Sopenharmony_ci	if (!p_dom_info)
73662306a36Sopenharmony_ci		return -ENOMEM;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	rc = ep11_query_info(card, domain, 0x03 /* domain info query */,
73962306a36Sopenharmony_ci			     sizeof(*p_dom_info), (u8 *)p_dom_info);
74062306a36Sopenharmony_ci	if (rc)
74162306a36Sopenharmony_ci		goto out;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	memset(info, 0, sizeof(*info));
74462306a36Sopenharmony_ci	info->cur_wk_state = '0';
74562306a36Sopenharmony_ci	info->new_wk_state = '0';
74662306a36Sopenharmony_ci	if (p_dom_info->dom_flags & 0x10 /* left imprint mode */) {
74762306a36Sopenharmony_ci		if (p_dom_info->dom_flags & 0x02 /* cur wk valid */) {
74862306a36Sopenharmony_ci			info->cur_wk_state = '1';
74962306a36Sopenharmony_ci			memcpy(info->cur_wkvp, p_dom_info->cur_WK_VP, 32);
75062306a36Sopenharmony_ci		}
75162306a36Sopenharmony_ci		if (p_dom_info->dom_flags & 0x04 || /* new wk present */
75262306a36Sopenharmony_ci		    p_dom_info->dom_flags & 0x08 /* new wk committed */) {
75362306a36Sopenharmony_ci			info->new_wk_state =
75462306a36Sopenharmony_ci				p_dom_info->dom_flags & 0x08 ? '2' : '1';
75562306a36Sopenharmony_ci			memcpy(info->new_wkvp, p_dom_info->new_WK_VP, 32);
75662306a36Sopenharmony_ci		}
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci	info->op_mode = p_dom_info->op_mode;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ciout:
76162306a36Sopenharmony_ci	kfree(p_dom_info);
76262306a36Sopenharmony_ci	return rc;
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_get_domain_info);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci/*
76762306a36Sopenharmony_ci * Default EP11 AES key generate attributes, used when no keygenflags given:
76862306a36Sopenharmony_ci * XCP_BLOB_ENCRYPT | XCP_BLOB_DECRYPT | XCP_BLOB_PROTKEY_EXTRACTABLE
76962306a36Sopenharmony_ci */
77062306a36Sopenharmony_ci#define KEY_ATTR_DEFAULTS 0x00200c00
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_cistatic int _ep11_genaeskey(u16 card, u16 domain,
77362306a36Sopenharmony_ci			   u32 keybitsize, u32 keygenflags,
77462306a36Sopenharmony_ci			   u8 *keybuf, size_t *keybufsize)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	struct keygen_req_pl {
77762306a36Sopenharmony_ci		struct pl_head head;
77862306a36Sopenharmony_ci		u8  var_tag;
77962306a36Sopenharmony_ci		u8  var_len;
78062306a36Sopenharmony_ci		u32 var;
78162306a36Sopenharmony_ci		u8  keybytes_tag;
78262306a36Sopenharmony_ci		u8  keybytes_len;
78362306a36Sopenharmony_ci		u32 keybytes;
78462306a36Sopenharmony_ci		u8  mech_tag;
78562306a36Sopenharmony_ci		u8  mech_len;
78662306a36Sopenharmony_ci		u32 mech;
78762306a36Sopenharmony_ci		u8  attr_tag;
78862306a36Sopenharmony_ci		u8  attr_len;
78962306a36Sopenharmony_ci		u32 attr_header;
79062306a36Sopenharmony_ci		u32 attr_bool_mask;
79162306a36Sopenharmony_ci		u32 attr_bool_bits;
79262306a36Sopenharmony_ci		u32 attr_val_len_type;
79362306a36Sopenharmony_ci		u32 attr_val_len_value;
79462306a36Sopenharmony_ci		/* followed by empty pin tag or empty pinblob tag */
79562306a36Sopenharmony_ci	} __packed * req_pl;
79662306a36Sopenharmony_ci	struct keygen_rep_pl {
79762306a36Sopenharmony_ci		struct pl_head head;
79862306a36Sopenharmony_ci		u8  rc_tag;
79962306a36Sopenharmony_ci		u8  rc_len;
80062306a36Sopenharmony_ci		u32 rc;
80162306a36Sopenharmony_ci		u8  data_tag;
80262306a36Sopenharmony_ci		u8  data_lenfmt;
80362306a36Sopenharmony_ci		u16 data_len;
80462306a36Sopenharmony_ci		u8  data[512];
80562306a36Sopenharmony_ci	} __packed * rep_pl;
80662306a36Sopenharmony_ci	struct ep11_cprb *req = NULL, *rep = NULL;
80762306a36Sopenharmony_ci	size_t req_pl_size, pinblob_size = 0;
80862306a36Sopenharmony_ci	struct ep11_target_dev target;
80962306a36Sopenharmony_ci	struct ep11_urb *urb = NULL;
81062306a36Sopenharmony_ci	int api, rc = -ENOMEM;
81162306a36Sopenharmony_ci	u8 *p;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci	switch (keybitsize) {
81462306a36Sopenharmony_ci	case 128:
81562306a36Sopenharmony_ci	case 192:
81662306a36Sopenharmony_ci	case 256:
81762306a36Sopenharmony_ci		break;
81862306a36Sopenharmony_ci	default:
81962306a36Sopenharmony_ci		DEBUG_ERR(
82062306a36Sopenharmony_ci			"%s unknown/unsupported keybitsize %d\n",
82162306a36Sopenharmony_ci			__func__, keybitsize);
82262306a36Sopenharmony_ci		rc = -EINVAL;
82362306a36Sopenharmony_ci		goto out;
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	/* request cprb and payload */
82762306a36Sopenharmony_ci	api = (!keygenflags || keygenflags & 0x00200000) ?
82862306a36Sopenharmony_ci		EP11_API_V4 : EP11_API_V1;
82962306a36Sopenharmony_ci	if (ap_is_se_guest()) {
83062306a36Sopenharmony_ci		/*
83162306a36Sopenharmony_ci		 * genkey within SE environment requires API ordinal 6
83262306a36Sopenharmony_ci		 * with empty pinblob
83362306a36Sopenharmony_ci		 */
83462306a36Sopenharmony_ci		api = EP11_API_V6;
83562306a36Sopenharmony_ci		pinblob_size = EP11_PINBLOB_V1_BYTES;
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci	req_pl_size = sizeof(struct keygen_req_pl) + ASN1TAGLEN(pinblob_size);
83862306a36Sopenharmony_ci	req = alloc_cprb(req_pl_size);
83962306a36Sopenharmony_ci	if (!req)
84062306a36Sopenharmony_ci		goto out;
84162306a36Sopenharmony_ci	req_pl = (struct keygen_req_pl *)(((u8 *)req) + sizeof(*req));
84262306a36Sopenharmony_ci	prep_head(&req_pl->head, req_pl_size, api, 21); /* GenerateKey */
84362306a36Sopenharmony_ci	req_pl->var_tag = 0x04;
84462306a36Sopenharmony_ci	req_pl->var_len = sizeof(u32);
84562306a36Sopenharmony_ci	req_pl->keybytes_tag = 0x04;
84662306a36Sopenharmony_ci	req_pl->keybytes_len = sizeof(u32);
84762306a36Sopenharmony_ci	req_pl->keybytes = keybitsize / 8;
84862306a36Sopenharmony_ci	req_pl->mech_tag = 0x04;
84962306a36Sopenharmony_ci	req_pl->mech_len = sizeof(u32);
85062306a36Sopenharmony_ci	req_pl->mech = 0x00001080; /* CKM_AES_KEY_GEN */
85162306a36Sopenharmony_ci	req_pl->attr_tag = 0x04;
85262306a36Sopenharmony_ci	req_pl->attr_len = 5 * sizeof(u32);
85362306a36Sopenharmony_ci	req_pl->attr_header = 0x10010000;
85462306a36Sopenharmony_ci	req_pl->attr_bool_mask = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS;
85562306a36Sopenharmony_ci	req_pl->attr_bool_bits = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS;
85662306a36Sopenharmony_ci	req_pl->attr_val_len_type = 0x00000161; /* CKA_VALUE_LEN */
85762306a36Sopenharmony_ci	req_pl->attr_val_len_value = keybitsize / 8;
85862306a36Sopenharmony_ci	p = ((u8 *)req_pl) + sizeof(*req_pl);
85962306a36Sopenharmony_ci	/* pin tag */
86062306a36Sopenharmony_ci	*p++ = 0x04;
86162306a36Sopenharmony_ci	*p++ = pinblob_size;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* reply cprb and payload */
86462306a36Sopenharmony_ci	rep = alloc_cprb(sizeof(struct keygen_rep_pl));
86562306a36Sopenharmony_ci	if (!rep)
86662306a36Sopenharmony_ci		goto out;
86762306a36Sopenharmony_ci	rep_pl = (struct keygen_rep_pl *)(((u8 *)rep) + sizeof(*rep));
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	/* urb and target */
87062306a36Sopenharmony_ci	urb = kmalloc(sizeof(*urb), GFP_KERNEL);
87162306a36Sopenharmony_ci	if (!urb)
87262306a36Sopenharmony_ci		goto out;
87362306a36Sopenharmony_ci	target.ap_id = card;
87462306a36Sopenharmony_ci	target.dom_id = domain;
87562306a36Sopenharmony_ci	prep_urb(urb, &target, 1,
87662306a36Sopenharmony_ci		 req, sizeof(*req) + req_pl_size,
87762306a36Sopenharmony_ci		 rep, sizeof(*rep) + sizeof(*rep_pl));
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	rc = zcrypt_send_ep11_cprb(urb);
88062306a36Sopenharmony_ci	if (rc) {
88162306a36Sopenharmony_ci		DEBUG_ERR(
88262306a36Sopenharmony_ci			"%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
88362306a36Sopenharmony_ci			__func__, (int)card, (int)domain, rc);
88462306a36Sopenharmony_ci		goto out;
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	rc = check_reply_pl((u8 *)rep_pl, __func__);
88862306a36Sopenharmony_ci	if (rc)
88962306a36Sopenharmony_ci		goto out;
89062306a36Sopenharmony_ci	if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
89162306a36Sopenharmony_ci		DEBUG_ERR("%s unknown reply data format\n", __func__);
89262306a36Sopenharmony_ci		rc = -EIO;
89362306a36Sopenharmony_ci		goto out;
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci	if (rep_pl->data_len > *keybufsize) {
89662306a36Sopenharmony_ci		DEBUG_ERR("%s mismatch reply data len / key buffer len\n",
89762306a36Sopenharmony_ci			  __func__);
89862306a36Sopenharmony_ci		rc = -ENOSPC;
89962306a36Sopenharmony_ci		goto out;
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	/* copy key blob */
90362306a36Sopenharmony_ci	memcpy(keybuf, rep_pl->data, rep_pl->data_len);
90462306a36Sopenharmony_ci	*keybufsize = rep_pl->data_len;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ciout:
90762306a36Sopenharmony_ci	kfree(req);
90862306a36Sopenharmony_ci	kfree(rep);
90962306a36Sopenharmony_ci	kfree(urb);
91062306a36Sopenharmony_ci	return rc;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ciint ep11_genaeskey(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
91462306a36Sopenharmony_ci		   u8 *keybuf, size_t *keybufsize, u32 keybufver)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	struct ep11kblob_header *hdr;
91762306a36Sopenharmony_ci	size_t hdr_size, pl_size;
91862306a36Sopenharmony_ci	u8 *pl;
91962306a36Sopenharmony_ci	int rc;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	switch (keybufver) {
92262306a36Sopenharmony_ci	case TOKVER_EP11_AES:
92362306a36Sopenharmony_ci	case TOKVER_EP11_AES_WITH_HEADER:
92462306a36Sopenharmony_ci		break;
92562306a36Sopenharmony_ci	default:
92662306a36Sopenharmony_ci		return -EINVAL;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	rc = ep11_kb_split(keybuf, *keybufsize, keybufver,
93062306a36Sopenharmony_ci			   &hdr, &hdr_size, &pl, &pl_size);
93162306a36Sopenharmony_ci	if (rc)
93262306a36Sopenharmony_ci		return rc;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	rc = _ep11_genaeskey(card, domain, keybitsize, keygenflags,
93562306a36Sopenharmony_ci			     pl, &pl_size);
93662306a36Sopenharmony_ci	if (rc)
93762306a36Sopenharmony_ci		return rc;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	*keybufsize = hdr_size + pl_size;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	/* update header information */
94262306a36Sopenharmony_ci	hdr->type = TOKTYPE_NON_CCA;
94362306a36Sopenharmony_ci	hdr->len = *keybufsize;
94462306a36Sopenharmony_ci	hdr->version = keybufver;
94562306a36Sopenharmony_ci	hdr->bitlen = keybitsize;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return 0;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_genaeskey);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic int ep11_cryptsingle(u16 card, u16 domain,
95262306a36Sopenharmony_ci			    u16 mode, u32 mech, const u8 *iv,
95362306a36Sopenharmony_ci			    const u8 *key, size_t keysize,
95462306a36Sopenharmony_ci			    const u8 *inbuf, size_t inbufsize,
95562306a36Sopenharmony_ci			    u8 *outbuf, size_t *outbufsize)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	struct crypt_req_pl {
95862306a36Sopenharmony_ci		struct pl_head head;
95962306a36Sopenharmony_ci		u8  var_tag;
96062306a36Sopenharmony_ci		u8  var_len;
96162306a36Sopenharmony_ci		u32 var;
96262306a36Sopenharmony_ci		u8  mech_tag;
96362306a36Sopenharmony_ci		u8  mech_len;
96462306a36Sopenharmony_ci		u32 mech;
96562306a36Sopenharmony_ci		/*
96662306a36Sopenharmony_ci		 * maybe followed by iv data
96762306a36Sopenharmony_ci		 * followed by key tag + key blob
96862306a36Sopenharmony_ci		 * followed by plaintext tag + plaintext
96962306a36Sopenharmony_ci		 */
97062306a36Sopenharmony_ci	} __packed * req_pl;
97162306a36Sopenharmony_ci	struct crypt_rep_pl {
97262306a36Sopenharmony_ci		struct pl_head head;
97362306a36Sopenharmony_ci		u8  rc_tag;
97462306a36Sopenharmony_ci		u8  rc_len;
97562306a36Sopenharmony_ci		u32 rc;
97662306a36Sopenharmony_ci		u8  data_tag;
97762306a36Sopenharmony_ci		u8  data_lenfmt;
97862306a36Sopenharmony_ci		/* data follows */
97962306a36Sopenharmony_ci	} __packed * rep_pl;
98062306a36Sopenharmony_ci	struct ep11_cprb *req = NULL, *rep = NULL;
98162306a36Sopenharmony_ci	struct ep11_target_dev target;
98262306a36Sopenharmony_ci	struct ep11_urb *urb = NULL;
98362306a36Sopenharmony_ci	size_t req_pl_size, rep_pl_size;
98462306a36Sopenharmony_ci	int n, api = EP11_API_V1, rc = -ENOMEM;
98562306a36Sopenharmony_ci	u8 *p;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* the simple asn1 coding used has length limits */
98862306a36Sopenharmony_ci	if (keysize > 0xFFFF || inbufsize > 0xFFFF)
98962306a36Sopenharmony_ci		return -EINVAL;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	/* request cprb and payload */
99262306a36Sopenharmony_ci	req_pl_size = sizeof(struct crypt_req_pl) + (iv ? 16 : 0)
99362306a36Sopenharmony_ci		+ ASN1TAGLEN(keysize) + ASN1TAGLEN(inbufsize);
99462306a36Sopenharmony_ci	req = alloc_cprb(req_pl_size);
99562306a36Sopenharmony_ci	if (!req)
99662306a36Sopenharmony_ci		goto out;
99762306a36Sopenharmony_ci	req_pl = (struct crypt_req_pl *)(((u8 *)req) + sizeof(*req));
99862306a36Sopenharmony_ci	prep_head(&req_pl->head, req_pl_size, api, (mode ? 20 : 19));
99962306a36Sopenharmony_ci	req_pl->var_tag = 0x04;
100062306a36Sopenharmony_ci	req_pl->var_len = sizeof(u32);
100162306a36Sopenharmony_ci	/* mech is mech + mech params (iv here) */
100262306a36Sopenharmony_ci	req_pl->mech_tag = 0x04;
100362306a36Sopenharmony_ci	req_pl->mech_len = sizeof(u32) + (iv ? 16 : 0);
100462306a36Sopenharmony_ci	req_pl->mech = (mech ? mech : 0x00001085); /* CKM_AES_CBC_PAD */
100562306a36Sopenharmony_ci	p = ((u8 *)req_pl) + sizeof(*req_pl);
100662306a36Sopenharmony_ci	if (iv) {
100762306a36Sopenharmony_ci		memcpy(p, iv, 16);
100862306a36Sopenharmony_ci		p += 16;
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci	/* key and input data */
101162306a36Sopenharmony_ci	p += asn1tag_write(p, 0x04, key, keysize);
101262306a36Sopenharmony_ci	p += asn1tag_write(p, 0x04, inbuf, inbufsize);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/* reply cprb and payload, assume out data size <= in data size + 32 */
101562306a36Sopenharmony_ci	rep_pl_size = sizeof(struct crypt_rep_pl) + ASN1TAGLEN(inbufsize + 32);
101662306a36Sopenharmony_ci	rep = alloc_cprb(rep_pl_size);
101762306a36Sopenharmony_ci	if (!rep)
101862306a36Sopenharmony_ci		goto out;
101962306a36Sopenharmony_ci	rep_pl = (struct crypt_rep_pl *)(((u8 *)rep) + sizeof(*rep));
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	/* urb and target */
102262306a36Sopenharmony_ci	urb = kmalloc(sizeof(*urb), GFP_KERNEL);
102362306a36Sopenharmony_ci	if (!urb)
102462306a36Sopenharmony_ci		goto out;
102562306a36Sopenharmony_ci	target.ap_id = card;
102662306a36Sopenharmony_ci	target.dom_id = domain;
102762306a36Sopenharmony_ci	prep_urb(urb, &target, 1,
102862306a36Sopenharmony_ci		 req, sizeof(*req) + req_pl_size,
102962306a36Sopenharmony_ci		 rep, sizeof(*rep) + rep_pl_size);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	rc = zcrypt_send_ep11_cprb(urb);
103262306a36Sopenharmony_ci	if (rc) {
103362306a36Sopenharmony_ci		DEBUG_ERR(
103462306a36Sopenharmony_ci			"%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
103562306a36Sopenharmony_ci			__func__, (int)card, (int)domain, rc);
103662306a36Sopenharmony_ci		goto out;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	rc = check_reply_pl((u8 *)rep_pl, __func__);
104062306a36Sopenharmony_ci	if (rc)
104162306a36Sopenharmony_ci		goto out;
104262306a36Sopenharmony_ci	if (rep_pl->data_tag != 0x04) {
104362306a36Sopenharmony_ci		DEBUG_ERR("%s unknown reply data format\n", __func__);
104462306a36Sopenharmony_ci		rc = -EIO;
104562306a36Sopenharmony_ci		goto out;
104662306a36Sopenharmony_ci	}
104762306a36Sopenharmony_ci	p = ((u8 *)rep_pl) + sizeof(*rep_pl);
104862306a36Sopenharmony_ci	if (rep_pl->data_lenfmt <= 127) {
104962306a36Sopenharmony_ci		n = rep_pl->data_lenfmt;
105062306a36Sopenharmony_ci	} else if (rep_pl->data_lenfmt == 0x81) {
105162306a36Sopenharmony_ci		n = *p++;
105262306a36Sopenharmony_ci	} else if (rep_pl->data_lenfmt == 0x82) {
105362306a36Sopenharmony_ci		n = *((u16 *)p);
105462306a36Sopenharmony_ci		p += 2;
105562306a36Sopenharmony_ci	} else {
105662306a36Sopenharmony_ci		DEBUG_ERR("%s unknown reply data length format 0x%02hhx\n",
105762306a36Sopenharmony_ci			  __func__, rep_pl->data_lenfmt);
105862306a36Sopenharmony_ci		rc = -EIO;
105962306a36Sopenharmony_ci		goto out;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci	if (n > *outbufsize) {
106262306a36Sopenharmony_ci		DEBUG_ERR("%s mismatch reply data len %d / output buffer %zu\n",
106362306a36Sopenharmony_ci			  __func__, n, *outbufsize);
106462306a36Sopenharmony_ci		rc = -ENOSPC;
106562306a36Sopenharmony_ci		goto out;
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	memcpy(outbuf, p, n);
106962306a36Sopenharmony_ci	*outbufsize = n;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ciout:
107262306a36Sopenharmony_ci	kfree(req);
107362306a36Sopenharmony_ci	kfree(rep);
107462306a36Sopenharmony_ci	kfree(urb);
107562306a36Sopenharmony_ci	return rc;
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic int _ep11_unwrapkey(u16 card, u16 domain,
107962306a36Sopenharmony_ci			   const u8 *kek, size_t keksize,
108062306a36Sopenharmony_ci			   const u8 *enckey, size_t enckeysize,
108162306a36Sopenharmony_ci			   u32 mech, const u8 *iv,
108262306a36Sopenharmony_ci			   u32 keybitsize, u32 keygenflags,
108362306a36Sopenharmony_ci			   u8 *keybuf, size_t *keybufsize)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	struct uw_req_pl {
108662306a36Sopenharmony_ci		struct pl_head head;
108762306a36Sopenharmony_ci		u8  attr_tag;
108862306a36Sopenharmony_ci		u8  attr_len;
108962306a36Sopenharmony_ci		u32 attr_header;
109062306a36Sopenharmony_ci		u32 attr_bool_mask;
109162306a36Sopenharmony_ci		u32 attr_bool_bits;
109262306a36Sopenharmony_ci		u32 attr_key_type;
109362306a36Sopenharmony_ci		u32 attr_key_type_value;
109462306a36Sopenharmony_ci		u32 attr_val_len;
109562306a36Sopenharmony_ci		u32 attr_val_len_value;
109662306a36Sopenharmony_ci		u8  mech_tag;
109762306a36Sopenharmony_ci		u8  mech_len;
109862306a36Sopenharmony_ci		u32 mech;
109962306a36Sopenharmony_ci		/*
110062306a36Sopenharmony_ci		 * maybe followed by iv data
110162306a36Sopenharmony_ci		 * followed by kek tag + kek blob
110262306a36Sopenharmony_ci		 * followed by empty mac tag
110362306a36Sopenharmony_ci		 * followed by empty pin tag or empty pinblob tag
110462306a36Sopenharmony_ci		 * followed by encryted key tag + bytes
110562306a36Sopenharmony_ci		 */
110662306a36Sopenharmony_ci	} __packed * req_pl;
110762306a36Sopenharmony_ci	struct uw_rep_pl {
110862306a36Sopenharmony_ci		struct pl_head head;
110962306a36Sopenharmony_ci		u8  rc_tag;
111062306a36Sopenharmony_ci		u8  rc_len;
111162306a36Sopenharmony_ci		u32 rc;
111262306a36Sopenharmony_ci		u8  data_tag;
111362306a36Sopenharmony_ci		u8  data_lenfmt;
111462306a36Sopenharmony_ci		u16 data_len;
111562306a36Sopenharmony_ci		u8  data[512];
111662306a36Sopenharmony_ci	} __packed * rep_pl;
111762306a36Sopenharmony_ci	struct ep11_cprb *req = NULL, *rep = NULL;
111862306a36Sopenharmony_ci	size_t req_pl_size, pinblob_size = 0;
111962306a36Sopenharmony_ci	struct ep11_target_dev target;
112062306a36Sopenharmony_ci	struct ep11_urb *urb = NULL;
112162306a36Sopenharmony_ci	int api, rc = -ENOMEM;
112262306a36Sopenharmony_ci	u8 *p;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	/* request cprb and payload */
112562306a36Sopenharmony_ci	api = (!keygenflags || keygenflags & 0x00200000) ?
112662306a36Sopenharmony_ci		EP11_API_V4 : EP11_API_V1;
112762306a36Sopenharmony_ci	if (ap_is_se_guest()) {
112862306a36Sopenharmony_ci		/*
112962306a36Sopenharmony_ci		 * unwrap within SE environment requires API ordinal 6
113062306a36Sopenharmony_ci		 * with empty pinblob
113162306a36Sopenharmony_ci		 */
113262306a36Sopenharmony_ci		api = EP11_API_V6;
113362306a36Sopenharmony_ci		pinblob_size = EP11_PINBLOB_V1_BYTES;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci	req_pl_size = sizeof(struct uw_req_pl) + (iv ? 16 : 0)
113662306a36Sopenharmony_ci		+ ASN1TAGLEN(keksize) + ASN1TAGLEN(0)
113762306a36Sopenharmony_ci		+ ASN1TAGLEN(pinblob_size) + ASN1TAGLEN(enckeysize);
113862306a36Sopenharmony_ci	req = alloc_cprb(req_pl_size);
113962306a36Sopenharmony_ci	if (!req)
114062306a36Sopenharmony_ci		goto out;
114162306a36Sopenharmony_ci	req_pl = (struct uw_req_pl *)(((u8 *)req) + sizeof(*req));
114262306a36Sopenharmony_ci	prep_head(&req_pl->head, req_pl_size, api, 34); /* UnwrapKey */
114362306a36Sopenharmony_ci	req_pl->attr_tag = 0x04;
114462306a36Sopenharmony_ci	req_pl->attr_len = 7 * sizeof(u32);
114562306a36Sopenharmony_ci	req_pl->attr_header = 0x10020000;
114662306a36Sopenharmony_ci	req_pl->attr_bool_mask = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS;
114762306a36Sopenharmony_ci	req_pl->attr_bool_bits = keygenflags ? keygenflags : KEY_ATTR_DEFAULTS;
114862306a36Sopenharmony_ci	req_pl->attr_key_type = 0x00000100; /* CKA_KEY_TYPE */
114962306a36Sopenharmony_ci	req_pl->attr_key_type_value = 0x0000001f; /* CKK_AES */
115062306a36Sopenharmony_ci	req_pl->attr_val_len = 0x00000161; /* CKA_VALUE_LEN */
115162306a36Sopenharmony_ci	req_pl->attr_val_len_value = keybitsize / 8;
115262306a36Sopenharmony_ci	/* mech is mech + mech params (iv here) */
115362306a36Sopenharmony_ci	req_pl->mech_tag = 0x04;
115462306a36Sopenharmony_ci	req_pl->mech_len = sizeof(u32) + (iv ? 16 : 0);
115562306a36Sopenharmony_ci	req_pl->mech = (mech ? mech : 0x00001085); /* CKM_AES_CBC_PAD */
115662306a36Sopenharmony_ci	p = ((u8 *)req_pl) + sizeof(*req_pl);
115762306a36Sopenharmony_ci	if (iv) {
115862306a36Sopenharmony_ci		memcpy(p, iv, 16);
115962306a36Sopenharmony_ci		p += 16;
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci	/* kek */
116262306a36Sopenharmony_ci	p += asn1tag_write(p, 0x04, kek, keksize);
116362306a36Sopenharmony_ci	/* empty mac key tag */
116462306a36Sopenharmony_ci	*p++ = 0x04;
116562306a36Sopenharmony_ci	*p++ = 0;
116662306a36Sopenharmony_ci	/* pin tag */
116762306a36Sopenharmony_ci	*p++ = 0x04;
116862306a36Sopenharmony_ci	*p++ = pinblob_size;
116962306a36Sopenharmony_ci	p += pinblob_size;
117062306a36Sopenharmony_ci	/* encrypted key value tag and bytes */
117162306a36Sopenharmony_ci	p += asn1tag_write(p, 0x04, enckey, enckeysize);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	/* reply cprb and payload */
117462306a36Sopenharmony_ci	rep = alloc_cprb(sizeof(struct uw_rep_pl));
117562306a36Sopenharmony_ci	if (!rep)
117662306a36Sopenharmony_ci		goto out;
117762306a36Sopenharmony_ci	rep_pl = (struct uw_rep_pl *)(((u8 *)rep) + sizeof(*rep));
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/* urb and target */
118062306a36Sopenharmony_ci	urb = kmalloc(sizeof(*urb), GFP_KERNEL);
118162306a36Sopenharmony_ci	if (!urb)
118262306a36Sopenharmony_ci		goto out;
118362306a36Sopenharmony_ci	target.ap_id = card;
118462306a36Sopenharmony_ci	target.dom_id = domain;
118562306a36Sopenharmony_ci	prep_urb(urb, &target, 1,
118662306a36Sopenharmony_ci		 req, sizeof(*req) + req_pl_size,
118762306a36Sopenharmony_ci		 rep, sizeof(*rep) + sizeof(*rep_pl));
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	rc = zcrypt_send_ep11_cprb(urb);
119062306a36Sopenharmony_ci	if (rc) {
119162306a36Sopenharmony_ci		DEBUG_ERR(
119262306a36Sopenharmony_ci			"%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
119362306a36Sopenharmony_ci			__func__, (int)card, (int)domain, rc);
119462306a36Sopenharmony_ci		goto out;
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	rc = check_reply_pl((u8 *)rep_pl, __func__);
119862306a36Sopenharmony_ci	if (rc)
119962306a36Sopenharmony_ci		goto out;
120062306a36Sopenharmony_ci	if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
120162306a36Sopenharmony_ci		DEBUG_ERR("%s unknown reply data format\n", __func__);
120262306a36Sopenharmony_ci		rc = -EIO;
120362306a36Sopenharmony_ci		goto out;
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci	if (rep_pl->data_len > *keybufsize) {
120662306a36Sopenharmony_ci		DEBUG_ERR("%s mismatch reply data len / key buffer len\n",
120762306a36Sopenharmony_ci			  __func__);
120862306a36Sopenharmony_ci		rc = -ENOSPC;
120962306a36Sopenharmony_ci		goto out;
121062306a36Sopenharmony_ci	}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/* copy key blob */
121362306a36Sopenharmony_ci	memcpy(keybuf, rep_pl->data, rep_pl->data_len);
121462306a36Sopenharmony_ci	*keybufsize = rep_pl->data_len;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ciout:
121762306a36Sopenharmony_ci	kfree(req);
121862306a36Sopenharmony_ci	kfree(rep);
121962306a36Sopenharmony_ci	kfree(urb);
122062306a36Sopenharmony_ci	return rc;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic int ep11_unwrapkey(u16 card, u16 domain,
122462306a36Sopenharmony_ci			  const u8 *kek, size_t keksize,
122562306a36Sopenharmony_ci			  const u8 *enckey, size_t enckeysize,
122662306a36Sopenharmony_ci			  u32 mech, const u8 *iv,
122762306a36Sopenharmony_ci			  u32 keybitsize, u32 keygenflags,
122862306a36Sopenharmony_ci			  u8 *keybuf, size_t *keybufsize,
122962306a36Sopenharmony_ci			  u8 keybufver)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct ep11kblob_header *hdr;
123262306a36Sopenharmony_ci	size_t hdr_size, pl_size;
123362306a36Sopenharmony_ci	u8 *pl;
123462306a36Sopenharmony_ci	int rc;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	rc = ep11_kb_split(keybuf, *keybufsize, keybufver,
123762306a36Sopenharmony_ci			   &hdr, &hdr_size, &pl, &pl_size);
123862306a36Sopenharmony_ci	if (rc)
123962306a36Sopenharmony_ci		return rc;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	rc = _ep11_unwrapkey(card, domain, kek, keksize, enckey, enckeysize,
124262306a36Sopenharmony_ci			     mech, iv, keybitsize, keygenflags,
124362306a36Sopenharmony_ci			     pl, &pl_size);
124462306a36Sopenharmony_ci	if (rc)
124562306a36Sopenharmony_ci		return rc;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	*keybufsize = hdr_size + pl_size;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	/* update header information */
125062306a36Sopenharmony_ci	hdr = (struct ep11kblob_header *)keybuf;
125162306a36Sopenharmony_ci	hdr->type = TOKTYPE_NON_CCA;
125262306a36Sopenharmony_ci	hdr->len = *keybufsize;
125362306a36Sopenharmony_ci	hdr->version = keybufver;
125462306a36Sopenharmony_ci	hdr->bitlen = keybitsize;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	return 0;
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic int _ep11_wrapkey(u16 card, u16 domain,
126062306a36Sopenharmony_ci			 const u8 *key, size_t keysize,
126162306a36Sopenharmony_ci			 u32 mech, const u8 *iv,
126262306a36Sopenharmony_ci			 u8 *databuf, size_t *datasize)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	struct wk_req_pl {
126562306a36Sopenharmony_ci		struct pl_head head;
126662306a36Sopenharmony_ci		u8  var_tag;
126762306a36Sopenharmony_ci		u8  var_len;
126862306a36Sopenharmony_ci		u32 var;
126962306a36Sopenharmony_ci		u8  mech_tag;
127062306a36Sopenharmony_ci		u8  mech_len;
127162306a36Sopenharmony_ci		u32 mech;
127262306a36Sopenharmony_ci		/*
127362306a36Sopenharmony_ci		 * followed by iv data
127462306a36Sopenharmony_ci		 * followed by key tag + key blob
127562306a36Sopenharmony_ci		 * followed by dummy kek param
127662306a36Sopenharmony_ci		 * followed by dummy mac param
127762306a36Sopenharmony_ci		 */
127862306a36Sopenharmony_ci	} __packed * req_pl;
127962306a36Sopenharmony_ci	struct wk_rep_pl {
128062306a36Sopenharmony_ci		struct pl_head head;
128162306a36Sopenharmony_ci		u8  rc_tag;
128262306a36Sopenharmony_ci		u8  rc_len;
128362306a36Sopenharmony_ci		u32 rc;
128462306a36Sopenharmony_ci		u8  data_tag;
128562306a36Sopenharmony_ci		u8  data_lenfmt;
128662306a36Sopenharmony_ci		u16 data_len;
128762306a36Sopenharmony_ci		u8  data[1024];
128862306a36Sopenharmony_ci	} __packed * rep_pl;
128962306a36Sopenharmony_ci	struct ep11_cprb *req = NULL, *rep = NULL;
129062306a36Sopenharmony_ci	struct ep11_target_dev target;
129162306a36Sopenharmony_ci	struct ep11_urb *urb = NULL;
129262306a36Sopenharmony_ci	size_t req_pl_size;
129362306a36Sopenharmony_ci	int api, rc = -ENOMEM;
129462306a36Sopenharmony_ci	u8 *p;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	/* request cprb and payload */
129762306a36Sopenharmony_ci	req_pl_size = sizeof(struct wk_req_pl) + (iv ? 16 : 0)
129862306a36Sopenharmony_ci		+ ASN1TAGLEN(keysize) + 4;
129962306a36Sopenharmony_ci	req = alloc_cprb(req_pl_size);
130062306a36Sopenharmony_ci	if (!req)
130162306a36Sopenharmony_ci		goto out;
130262306a36Sopenharmony_ci	if (!mech || mech == 0x80060001)
130362306a36Sopenharmony_ci		req->flags |= 0x20; /* CPACF_WRAP needs special bit */
130462306a36Sopenharmony_ci	req_pl = (struct wk_req_pl *)(((u8 *)req) + sizeof(*req));
130562306a36Sopenharmony_ci	api = (!mech || mech == 0x80060001) ? /* CKM_IBM_CPACF_WRAP */
130662306a36Sopenharmony_ci		EP11_API_V4 : EP11_API_V1;
130762306a36Sopenharmony_ci	prep_head(&req_pl->head, req_pl_size, api, 33); /* WrapKey */
130862306a36Sopenharmony_ci	req_pl->var_tag = 0x04;
130962306a36Sopenharmony_ci	req_pl->var_len = sizeof(u32);
131062306a36Sopenharmony_ci	/* mech is mech + mech params (iv here) */
131162306a36Sopenharmony_ci	req_pl->mech_tag = 0x04;
131262306a36Sopenharmony_ci	req_pl->mech_len = sizeof(u32) + (iv ? 16 : 0);
131362306a36Sopenharmony_ci	req_pl->mech = (mech ? mech : 0x80060001); /* CKM_IBM_CPACF_WRAP */
131462306a36Sopenharmony_ci	p = ((u8 *)req_pl) + sizeof(*req_pl);
131562306a36Sopenharmony_ci	if (iv) {
131662306a36Sopenharmony_ci		memcpy(p, iv, 16);
131762306a36Sopenharmony_ci		p += 16;
131862306a36Sopenharmony_ci	}
131962306a36Sopenharmony_ci	/* key blob */
132062306a36Sopenharmony_ci	p += asn1tag_write(p, 0x04, key, keysize);
132162306a36Sopenharmony_ci	/* empty kek tag */
132262306a36Sopenharmony_ci	*p++ = 0x04;
132362306a36Sopenharmony_ci	*p++ = 0;
132462306a36Sopenharmony_ci	/* empty mac tag */
132562306a36Sopenharmony_ci	*p++ = 0x04;
132662306a36Sopenharmony_ci	*p++ = 0;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	/* reply cprb and payload */
132962306a36Sopenharmony_ci	rep = alloc_cprb(sizeof(struct wk_rep_pl));
133062306a36Sopenharmony_ci	if (!rep)
133162306a36Sopenharmony_ci		goto out;
133262306a36Sopenharmony_ci	rep_pl = (struct wk_rep_pl *)(((u8 *)rep) + sizeof(*rep));
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	/* urb and target */
133562306a36Sopenharmony_ci	urb = kmalloc(sizeof(*urb), GFP_KERNEL);
133662306a36Sopenharmony_ci	if (!urb)
133762306a36Sopenharmony_ci		goto out;
133862306a36Sopenharmony_ci	target.ap_id = card;
133962306a36Sopenharmony_ci	target.dom_id = domain;
134062306a36Sopenharmony_ci	prep_urb(urb, &target, 1,
134162306a36Sopenharmony_ci		 req, sizeof(*req) + req_pl_size,
134262306a36Sopenharmony_ci		 rep, sizeof(*rep) + sizeof(*rep_pl));
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	rc = zcrypt_send_ep11_cprb(urb);
134562306a36Sopenharmony_ci	if (rc) {
134662306a36Sopenharmony_ci		DEBUG_ERR(
134762306a36Sopenharmony_ci			"%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
134862306a36Sopenharmony_ci			__func__, (int)card, (int)domain, rc);
134962306a36Sopenharmony_ci		goto out;
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	rc = check_reply_pl((u8 *)rep_pl, __func__);
135362306a36Sopenharmony_ci	if (rc)
135462306a36Sopenharmony_ci		goto out;
135562306a36Sopenharmony_ci	if (rep_pl->data_tag != 0x04 || rep_pl->data_lenfmt != 0x82) {
135662306a36Sopenharmony_ci		DEBUG_ERR("%s unknown reply data format\n", __func__);
135762306a36Sopenharmony_ci		rc = -EIO;
135862306a36Sopenharmony_ci		goto out;
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci	if (rep_pl->data_len > *datasize) {
136162306a36Sopenharmony_ci		DEBUG_ERR("%s mismatch reply data len / data buffer len\n",
136262306a36Sopenharmony_ci			  __func__);
136362306a36Sopenharmony_ci		rc = -ENOSPC;
136462306a36Sopenharmony_ci		goto out;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	/* copy the data from the cprb to the data buffer */
136862306a36Sopenharmony_ci	memcpy(databuf, rep_pl->data, rep_pl->data_len);
136962306a36Sopenharmony_ci	*datasize = rep_pl->data_len;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ciout:
137262306a36Sopenharmony_ci	kfree(req);
137362306a36Sopenharmony_ci	kfree(rep);
137462306a36Sopenharmony_ci	kfree(urb);
137562306a36Sopenharmony_ci	return rc;
137662306a36Sopenharmony_ci}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ciint ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
137962306a36Sopenharmony_ci		     const u8 *clrkey, u8 *keybuf, size_t *keybufsize,
138062306a36Sopenharmony_ci		     u32 keytype)
138162306a36Sopenharmony_ci{
138262306a36Sopenharmony_ci	int rc;
138362306a36Sopenharmony_ci	u8 encbuf[64], *kek = NULL;
138462306a36Sopenharmony_ci	size_t clrkeylen, keklen, encbuflen = sizeof(encbuf);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (keybitsize == 128 || keybitsize == 192 || keybitsize == 256) {
138762306a36Sopenharmony_ci		clrkeylen = keybitsize / 8;
138862306a36Sopenharmony_ci	} else {
138962306a36Sopenharmony_ci		DEBUG_ERR(
139062306a36Sopenharmony_ci			"%s unknown/unsupported keybitsize %d\n",
139162306a36Sopenharmony_ci			__func__, keybitsize);
139262306a36Sopenharmony_ci		return -EINVAL;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/* allocate memory for the temp kek */
139662306a36Sopenharmony_ci	keklen = MAXEP11AESKEYBLOBSIZE;
139762306a36Sopenharmony_ci	kek = kmalloc(keklen, GFP_ATOMIC);
139862306a36Sopenharmony_ci	if (!kek) {
139962306a36Sopenharmony_ci		rc = -ENOMEM;
140062306a36Sopenharmony_ci		goto out;
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	/* Step 1: generate AES 256 bit random kek key */
140462306a36Sopenharmony_ci	rc = _ep11_genaeskey(card, domain, 256,
140562306a36Sopenharmony_ci			     0x00006c00, /* EN/DECRYPT, WRAP/UNWRAP */
140662306a36Sopenharmony_ci			     kek, &keklen);
140762306a36Sopenharmony_ci	if (rc) {
140862306a36Sopenharmony_ci		DEBUG_ERR(
140962306a36Sopenharmony_ci			"%s generate kek key failed, rc=%d\n",
141062306a36Sopenharmony_ci			__func__, rc);
141162306a36Sopenharmony_ci		goto out;
141262306a36Sopenharmony_ci	}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	/* Step 2: encrypt clear key value with the kek key */
141562306a36Sopenharmony_ci	rc = ep11_cryptsingle(card, domain, 0, 0, def_iv, kek, keklen,
141662306a36Sopenharmony_ci			      clrkey, clrkeylen, encbuf, &encbuflen);
141762306a36Sopenharmony_ci	if (rc) {
141862306a36Sopenharmony_ci		DEBUG_ERR(
141962306a36Sopenharmony_ci			"%s encrypting key value with kek key failed, rc=%d\n",
142062306a36Sopenharmony_ci			__func__, rc);
142162306a36Sopenharmony_ci		goto out;
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	/* Step 3: import the encrypted key value as a new key */
142562306a36Sopenharmony_ci	rc = ep11_unwrapkey(card, domain, kek, keklen,
142662306a36Sopenharmony_ci			    encbuf, encbuflen, 0, def_iv,
142762306a36Sopenharmony_ci			    keybitsize, 0, keybuf, keybufsize, keytype);
142862306a36Sopenharmony_ci	if (rc) {
142962306a36Sopenharmony_ci		DEBUG_ERR(
143062306a36Sopenharmony_ci			"%s importing key value as new key failed,, rc=%d\n",
143162306a36Sopenharmony_ci			__func__, rc);
143262306a36Sopenharmony_ci		goto out;
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ciout:
143662306a36Sopenharmony_ci	kfree(kek);
143762306a36Sopenharmony_ci	return rc;
143862306a36Sopenharmony_ci}
143962306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_clr2keyblob);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ciint ep11_kblob2protkey(u16 card, u16 dom,
144262306a36Sopenharmony_ci		       const u8 *keyblob, size_t keybloblen,
144362306a36Sopenharmony_ci		       u8 *protkey, u32 *protkeylen, u32 *protkeytype)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	struct ep11kblob_header *hdr;
144662306a36Sopenharmony_ci	struct ep11keyblob *key;
144762306a36Sopenharmony_ci	size_t wkbuflen, keylen;
144862306a36Sopenharmony_ci	struct wk_info {
144962306a36Sopenharmony_ci		u16 version;
145062306a36Sopenharmony_ci		u8  res1[16];
145162306a36Sopenharmony_ci		u32 pkeytype;
145262306a36Sopenharmony_ci		u32 pkeybitsize;
145362306a36Sopenharmony_ci		u64 pkeysize;
145462306a36Sopenharmony_ci		u8  res2[8];
145562306a36Sopenharmony_ci		u8  pkey[];
145662306a36Sopenharmony_ci	} __packed * wki;
145762306a36Sopenharmony_ci	u8 *wkbuf = NULL;
145862306a36Sopenharmony_ci	int rc = -EIO;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	if (ep11_kb_decode((u8 *)keyblob, keybloblen, &hdr, NULL, &key, &keylen))
146162306a36Sopenharmony_ci		return -EINVAL;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	if (hdr->version == TOKVER_EP11_AES) {
146462306a36Sopenharmony_ci		/* wipe overlayed header */
146562306a36Sopenharmony_ci		memset(hdr, 0, sizeof(*hdr));
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci	/* !!! hdr is no longer a valid header !!! */
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	/* alloc temp working buffer */
147062306a36Sopenharmony_ci	wkbuflen = (keylen + AES_BLOCK_SIZE) & (~(AES_BLOCK_SIZE - 1));
147162306a36Sopenharmony_ci	wkbuf = kmalloc(wkbuflen, GFP_ATOMIC);
147262306a36Sopenharmony_ci	if (!wkbuf)
147362306a36Sopenharmony_ci		return -ENOMEM;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	/* ep11 secure key -> protected key + info */
147662306a36Sopenharmony_ci	rc = _ep11_wrapkey(card, dom, (u8 *)key, keylen,
147762306a36Sopenharmony_ci			   0, def_iv, wkbuf, &wkbuflen);
147862306a36Sopenharmony_ci	if (rc) {
147962306a36Sopenharmony_ci		DEBUG_ERR(
148062306a36Sopenharmony_ci			"%s rewrapping ep11 key to pkey failed, rc=%d\n",
148162306a36Sopenharmony_ci			__func__, rc);
148262306a36Sopenharmony_ci		goto out;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci	wki = (struct wk_info *)wkbuf;
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	/* check struct version and pkey type */
148762306a36Sopenharmony_ci	if (wki->version != 1 || wki->pkeytype < 1 || wki->pkeytype > 5) {
148862306a36Sopenharmony_ci		DEBUG_ERR("%s wk info version %d or pkeytype %d mismatch.\n",
148962306a36Sopenharmony_ci			  __func__, (int)wki->version, (int)wki->pkeytype);
149062306a36Sopenharmony_ci		rc = -EIO;
149162306a36Sopenharmony_ci		goto out;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/* check protected key type field */
149562306a36Sopenharmony_ci	switch (wki->pkeytype) {
149662306a36Sopenharmony_ci	case 1: /* AES */
149762306a36Sopenharmony_ci		switch (wki->pkeysize) {
149862306a36Sopenharmony_ci		case 16 + 32:
149962306a36Sopenharmony_ci			/* AES 128 protected key */
150062306a36Sopenharmony_ci			if (protkeytype)
150162306a36Sopenharmony_ci				*protkeytype = PKEY_KEYTYPE_AES_128;
150262306a36Sopenharmony_ci			break;
150362306a36Sopenharmony_ci		case 24 + 32:
150462306a36Sopenharmony_ci			/* AES 192 protected key */
150562306a36Sopenharmony_ci			if (protkeytype)
150662306a36Sopenharmony_ci				*protkeytype = PKEY_KEYTYPE_AES_192;
150762306a36Sopenharmony_ci			break;
150862306a36Sopenharmony_ci		case 32 + 32:
150962306a36Sopenharmony_ci			/* AES 256 protected key */
151062306a36Sopenharmony_ci			if (protkeytype)
151162306a36Sopenharmony_ci				*protkeytype = PKEY_KEYTYPE_AES_256;
151262306a36Sopenharmony_ci			break;
151362306a36Sopenharmony_ci		default:
151462306a36Sopenharmony_ci			DEBUG_ERR("%s unknown/unsupported AES pkeysize %d\n",
151562306a36Sopenharmony_ci				  __func__, (int)wki->pkeysize);
151662306a36Sopenharmony_ci			rc = -EIO;
151762306a36Sopenharmony_ci			goto out;
151862306a36Sopenharmony_ci		}
151962306a36Sopenharmony_ci		break;
152062306a36Sopenharmony_ci	case 3: /* EC-P */
152162306a36Sopenharmony_ci	case 4: /* EC-ED */
152262306a36Sopenharmony_ci	case 5: /* EC-BP */
152362306a36Sopenharmony_ci		if (protkeytype)
152462306a36Sopenharmony_ci			*protkeytype = PKEY_KEYTYPE_ECC;
152562306a36Sopenharmony_ci		break;
152662306a36Sopenharmony_ci	case 2: /* TDES */
152762306a36Sopenharmony_ci	default:
152862306a36Sopenharmony_ci		DEBUG_ERR("%s unknown/unsupported key type %d\n",
152962306a36Sopenharmony_ci			  __func__, (int)wki->pkeytype);
153062306a36Sopenharmony_ci		rc = -EIO;
153162306a36Sopenharmony_ci		goto out;
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	/* copy the translated protected key */
153562306a36Sopenharmony_ci	if (wki->pkeysize > *protkeylen) {
153662306a36Sopenharmony_ci		DEBUG_ERR("%s wk info pkeysize %llu > protkeysize %u\n",
153762306a36Sopenharmony_ci			  __func__, wki->pkeysize, *protkeylen);
153862306a36Sopenharmony_ci		rc = -EINVAL;
153962306a36Sopenharmony_ci		goto out;
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci	memcpy(protkey, wki->pkey, wki->pkeysize);
154262306a36Sopenharmony_ci	*protkeylen = wki->pkeysize;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ciout:
154562306a36Sopenharmony_ci	kfree(wkbuf);
154662306a36Sopenharmony_ci	return rc;
154762306a36Sopenharmony_ci}
154862306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_kblob2protkey);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ciint ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
155162306a36Sopenharmony_ci		   int minhwtype, int minapi, const u8 *wkvp)
155262306a36Sopenharmony_ci{
155362306a36Sopenharmony_ci	struct zcrypt_device_status_ext *device_status;
155462306a36Sopenharmony_ci	u32 *_apqns = NULL, _nr_apqns = 0;
155562306a36Sopenharmony_ci	int i, card, dom, rc = -ENOMEM;
155662306a36Sopenharmony_ci	struct ep11_domain_info edi;
155762306a36Sopenharmony_ci	struct ep11_card_info eci;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	/* fetch status of all crypto cards */
156062306a36Sopenharmony_ci	device_status = kvmalloc_array(MAX_ZDEV_ENTRIES_EXT,
156162306a36Sopenharmony_ci				       sizeof(struct zcrypt_device_status_ext),
156262306a36Sopenharmony_ci				       GFP_KERNEL);
156362306a36Sopenharmony_ci	if (!device_status)
156462306a36Sopenharmony_ci		return -ENOMEM;
156562306a36Sopenharmony_ci	zcrypt_device_status_mask_ext(device_status);
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	/* allocate 1k space for up to 256 apqns */
156862306a36Sopenharmony_ci	_apqns = kmalloc_array(256, sizeof(u32), GFP_KERNEL);
156962306a36Sopenharmony_ci	if (!_apqns) {
157062306a36Sopenharmony_ci		kvfree(device_status);
157162306a36Sopenharmony_ci		return -ENOMEM;
157262306a36Sopenharmony_ci	}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	/* walk through all the crypto apqnss */
157562306a36Sopenharmony_ci	for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) {
157662306a36Sopenharmony_ci		card = AP_QID_CARD(device_status[i].qid);
157762306a36Sopenharmony_ci		dom = AP_QID_QUEUE(device_status[i].qid);
157862306a36Sopenharmony_ci		/* check online state */
157962306a36Sopenharmony_ci		if (!device_status[i].online)
158062306a36Sopenharmony_ci			continue;
158162306a36Sopenharmony_ci		/* check for ep11 functions */
158262306a36Sopenharmony_ci		if (!(device_status[i].functions & 0x01))
158362306a36Sopenharmony_ci			continue;
158462306a36Sopenharmony_ci		/* check cardnr */
158562306a36Sopenharmony_ci		if (cardnr != 0xFFFF && card != cardnr)
158662306a36Sopenharmony_ci			continue;
158762306a36Sopenharmony_ci		/* check domain */
158862306a36Sopenharmony_ci		if (domain != 0xFFFF && dom != domain)
158962306a36Sopenharmony_ci			continue;
159062306a36Sopenharmony_ci		/* check min hardware type */
159162306a36Sopenharmony_ci		if (minhwtype && device_status[i].hwtype < minhwtype)
159262306a36Sopenharmony_ci			continue;
159362306a36Sopenharmony_ci		/* check min api version if given */
159462306a36Sopenharmony_ci		if (minapi > 0) {
159562306a36Sopenharmony_ci			if (ep11_get_card_info(card, &eci, 0))
159662306a36Sopenharmony_ci				continue;
159762306a36Sopenharmony_ci			if (minapi > eci.API_ord_nr)
159862306a36Sopenharmony_ci				continue;
159962306a36Sopenharmony_ci		}
160062306a36Sopenharmony_ci		/* check wkvp if given */
160162306a36Sopenharmony_ci		if (wkvp) {
160262306a36Sopenharmony_ci			if (ep11_get_domain_info(card, dom, &edi))
160362306a36Sopenharmony_ci				continue;
160462306a36Sopenharmony_ci			if (edi.cur_wk_state != '1')
160562306a36Sopenharmony_ci				continue;
160662306a36Sopenharmony_ci			if (memcmp(wkvp, edi.cur_wkvp, 16))
160762306a36Sopenharmony_ci				continue;
160862306a36Sopenharmony_ci		}
160962306a36Sopenharmony_ci		/* apqn passed all filtering criterons, add to the array */
161062306a36Sopenharmony_ci		if (_nr_apqns < 256)
161162306a36Sopenharmony_ci			_apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom);
161262306a36Sopenharmony_ci	}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	/* nothing found ? */
161562306a36Sopenharmony_ci	if (!_nr_apqns) {
161662306a36Sopenharmony_ci		kfree(_apqns);
161762306a36Sopenharmony_ci		rc = -ENODEV;
161862306a36Sopenharmony_ci	} else {
161962306a36Sopenharmony_ci		/* no re-allocation, simple return the _apqns array */
162062306a36Sopenharmony_ci		*apqns = _apqns;
162162306a36Sopenharmony_ci		*nr_apqns = _nr_apqns;
162262306a36Sopenharmony_ci		rc = 0;
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	kvfree(device_status);
162662306a36Sopenharmony_ci	return rc;
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ciEXPORT_SYMBOL(ep11_findcard2);
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_civoid __exit zcrypt_ep11misc_exit(void)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	card_cache_free();
163362306a36Sopenharmony_ci}
1634