xref: /openbmc/linux/drivers/s390/crypto/pkey_api.c (revision 888edbc48857c7189592fb0be3ab09994247199c)
1812141a9SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2e80d4af0SHarald Freudenberger /*
3e80d4af0SHarald Freudenberger  *  pkey device driver
4e80d4af0SHarald Freudenberger  *
5183cb469SHarald Freudenberger  *  Copyright IBM Corp. 2017,2019
6e80d4af0SHarald Freudenberger  *  Author(s): Harald Freudenberger
7e80d4af0SHarald Freudenberger  */
8e80d4af0SHarald Freudenberger 
9e80d4af0SHarald Freudenberger #define KMSG_COMPONENT "pkey"
10e80d4af0SHarald Freudenberger #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11e80d4af0SHarald Freudenberger 
12e80d4af0SHarald Freudenberger #include <linux/fs.h>
13e80d4af0SHarald Freudenberger #include <linux/init.h>
14e80d4af0SHarald Freudenberger #include <linux/miscdevice.h>
15e80d4af0SHarald Freudenberger #include <linux/module.h>
16e80d4af0SHarald Freudenberger #include <linux/slab.h>
17e80d4af0SHarald Freudenberger #include <linux/kallsyms.h>
18e80d4af0SHarald Freudenberger #include <linux/debugfs.h>
19a45a5c7dSIngo Franzki #include <linux/random.h>
2063c19be0SIngo Franzki #include <linux/cpufeature.h>
21e80d4af0SHarald Freudenberger #include <asm/zcrypt.h>
22e80d4af0SHarald Freudenberger #include <asm/cpacf.h>
23e80d4af0SHarald Freudenberger #include <asm/pkey.h>
24cb26b9ffSIngo Franzki #include <crypto/aes.h>
25e80d4af0SHarald Freudenberger 
26e80d4af0SHarald Freudenberger #include "zcrypt_api.h"
27efc598e6SHarald Freudenberger #include "zcrypt_ccamisc.h"
28e80d4af0SHarald Freudenberger 
29e80d4af0SHarald Freudenberger MODULE_LICENSE("GPL");
30e80d4af0SHarald Freudenberger MODULE_AUTHOR("IBM Corporation");
31e80d4af0SHarald Freudenberger MODULE_DESCRIPTION("s390 protected key interface");
32e80d4af0SHarald Freudenberger 
33f2bbc96eSHarald Freudenberger #define KEYBLOBBUFSIZE 8192  /* key buffer size used for internal processing */
34f2bbc96eSHarald Freudenberger #define MAXAPQNSINLIST 64    /* max 64 apqns within a apqn list */
35f2bbc96eSHarald Freudenberger 
36f822ad2cSHarald Freudenberger /* mask of available pckmo subfunctions, fetched once at module init */
37f822ad2cSHarald Freudenberger static cpacf_mask_t pckmo_functions;
38f822ad2cSHarald Freudenberger 
39e80d4af0SHarald Freudenberger /*
40e80d4af0SHarald Freudenberger  * debug feature data and functions
41e80d4af0SHarald Freudenberger  */
42e80d4af0SHarald Freudenberger 
43e80d4af0SHarald Freudenberger static debug_info_t *debug_info;
44e80d4af0SHarald Freudenberger 
45e80d4af0SHarald Freudenberger #define DEBUG_DBG(...)	debug_sprintf_event(debug_info, 6, ##__VA_ARGS__)
46e80d4af0SHarald Freudenberger #define DEBUG_INFO(...) debug_sprintf_event(debug_info, 5, ##__VA_ARGS__)
47e80d4af0SHarald Freudenberger #define DEBUG_WARN(...) debug_sprintf_event(debug_info, 4, ##__VA_ARGS__)
48e80d4af0SHarald Freudenberger #define DEBUG_ERR(...)	debug_sprintf_event(debug_info, 3, ##__VA_ARGS__)
49e80d4af0SHarald Freudenberger 
50e80d4af0SHarald Freudenberger static void __init pkey_debug_init(void)
51e80d4af0SHarald Freudenberger {
526b1f16baSHarald Freudenberger 	/* 5 arguments per dbf entry (including the format string ptr) */
536b1f16baSHarald Freudenberger 	debug_info = debug_register("pkey", 1, 1, 5 * sizeof(long));
54e80d4af0SHarald Freudenberger 	debug_register_view(debug_info, &debug_sprintf_view);
55e80d4af0SHarald Freudenberger 	debug_set_level(debug_info, 3);
56e80d4af0SHarald Freudenberger }
57e80d4af0SHarald Freudenberger 
58e80d4af0SHarald Freudenberger static void __exit pkey_debug_exit(void)
59e80d4af0SHarald Freudenberger {
60e80d4af0SHarald Freudenberger 	debug_unregister(debug_info);
61e80d4af0SHarald Freudenberger }
62e80d4af0SHarald Freudenberger 
630534bde7SIngo Franzki /* inside view of a protected key token (only type 0x00 version 0x01) */
640534bde7SIngo Franzki struct protaeskeytoken {
650534bde7SIngo Franzki 	u8  type;     /* 0x00 for PAES specific key tokens */
660534bde7SIngo Franzki 	u8  res0[3];
670534bde7SIngo Franzki 	u8  version;  /* should be 0x01 for protected AES key token */
680534bde7SIngo Franzki 	u8  res1[3];
690534bde7SIngo Franzki 	u32 keytype;  /* key type, one of the PKEY_KEYTYPE values */
700534bde7SIngo Franzki 	u32 len;      /* bytes actually stored in protkey[] */
710534bde7SIngo Franzki 	u8  protkey[MAXPROTKEYSIZE]; /* the protected key blob */
720534bde7SIngo Franzki } __packed;
730534bde7SIngo Franzki 
74*888edbc4SHarald Freudenberger /* inside view of a clear key token (type 0x00 version 0x02) */
75*888edbc4SHarald Freudenberger struct clearaeskeytoken {
76*888edbc4SHarald Freudenberger 	u8  type;	 /* 0x00 for PAES specific key tokens */
77*888edbc4SHarald Freudenberger 	u8  res0[3];
78*888edbc4SHarald Freudenberger 	u8  version;	 /* 0x02 for clear AES key token */
79*888edbc4SHarald Freudenberger 	u8  res1[3];
80*888edbc4SHarald Freudenberger 	u32 keytype;	 /* key type, one of the PKEY_KEYTYPE values */
81*888edbc4SHarald Freudenberger 	u32 len;	 /* bytes actually stored in clearkey[] */
82*888edbc4SHarald Freudenberger 	u8  clearkey[0]; /* clear key value */
83*888edbc4SHarald Freudenberger } __packed;
84*888edbc4SHarald Freudenberger 
85e80d4af0SHarald Freudenberger /*
86e80d4af0SHarald Freudenberger  * Create a protected key from a clear key value.
87e80d4af0SHarald Freudenberger  */
88183cb469SHarald Freudenberger static int pkey_clr2protkey(u32 keytype,
89e80d4af0SHarald Freudenberger 			    const struct pkey_clrkey *clrkey,
90e80d4af0SHarald Freudenberger 			    struct pkey_protkey *protkey)
91e80d4af0SHarald Freudenberger {
92e80d4af0SHarald Freudenberger 	long fc;
93e80d4af0SHarald Freudenberger 	int keysize;
94e80d4af0SHarald Freudenberger 	u8 paramblock[64];
95e80d4af0SHarald Freudenberger 
96e80d4af0SHarald Freudenberger 	switch (keytype) {
97e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_128:
98e80d4af0SHarald Freudenberger 		keysize = 16;
99e80d4af0SHarald Freudenberger 		fc = CPACF_PCKMO_ENC_AES_128_KEY;
100e80d4af0SHarald Freudenberger 		break;
101e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_192:
102e80d4af0SHarald Freudenberger 		keysize = 24;
103e80d4af0SHarald Freudenberger 		fc = CPACF_PCKMO_ENC_AES_192_KEY;
104e80d4af0SHarald Freudenberger 		break;
105e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_256:
106e80d4af0SHarald Freudenberger 		keysize = 32;
107e80d4af0SHarald Freudenberger 		fc = CPACF_PCKMO_ENC_AES_256_KEY;
108e80d4af0SHarald Freudenberger 		break;
109e80d4af0SHarald Freudenberger 	default:
110ac2b96f3SHarald Freudenberger 		DEBUG_ERR("%s unknown/unsupported keytype %d\n",
111ac2b96f3SHarald Freudenberger 			  __func__, keytype);
112e80d4af0SHarald Freudenberger 		return -EINVAL;
113e80d4af0SHarald Freudenberger 	}
114e80d4af0SHarald Freudenberger 
115f822ad2cSHarald Freudenberger 	/*
116f822ad2cSHarald Freudenberger 	 * Check if the needed pckmo subfunction is available.
117f822ad2cSHarald Freudenberger 	 * These subfunctions can be enabled/disabled by customers
118f822ad2cSHarald Freudenberger 	 * in the LPAR profile or may even change on the fly.
119f822ad2cSHarald Freudenberger 	 */
120f822ad2cSHarald Freudenberger 	if (!cpacf_test_func(&pckmo_functions, fc)) {
121f822ad2cSHarald Freudenberger 		DEBUG_ERR("%s pckmo functions not available\n", __func__);
12258443b67SDavid Hildenbrand 		return -ENODEV;
123f822ad2cSHarald Freudenberger 	}
124f822ad2cSHarald Freudenberger 
125e80d4af0SHarald Freudenberger 	/* prepare param block */
126e80d4af0SHarald Freudenberger 	memset(paramblock, 0, sizeof(paramblock));
127e80d4af0SHarald Freudenberger 	memcpy(paramblock, clrkey->clrkey, keysize);
128e80d4af0SHarald Freudenberger 
129e80d4af0SHarald Freudenberger 	/* call the pckmo instruction */
130e80d4af0SHarald Freudenberger 	cpacf_pckmo(fc, paramblock);
131e80d4af0SHarald Freudenberger 
132e80d4af0SHarald Freudenberger 	/* copy created protected key */
133e80d4af0SHarald Freudenberger 	protkey->type = keytype;
134e80d4af0SHarald Freudenberger 	protkey->len = keysize + 32;
135e80d4af0SHarald Freudenberger 	memcpy(protkey->protkey, paramblock, keysize + 32);
136e80d4af0SHarald Freudenberger 
137e80d4af0SHarald Freudenberger 	return 0;
138e80d4af0SHarald Freudenberger }
139e80d4af0SHarald Freudenberger 
140e80d4af0SHarald Freudenberger /*
141e80d4af0SHarald Freudenberger  * Find card and transform secure key into protected key.
142e80d4af0SHarald Freudenberger  */
143f2bbc96eSHarald Freudenberger static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey)
144e80d4af0SHarald Freudenberger {
145e80d4af0SHarald Freudenberger 	int rc, verify;
146f2bbc96eSHarald Freudenberger 	u16 cardnr, domain;
147f2bbc96eSHarald Freudenberger 	struct keytoken_header *hdr = (struct keytoken_header *)key;
148e80d4af0SHarald Freudenberger 
149e80d4af0SHarald Freudenberger 	/*
150f2bbc96eSHarald Freudenberger 	 * The cca_xxx2protkey call may fail when a card has been
151e80d4af0SHarald Freudenberger 	 * addressed where the master key was changed after last fetch
152efc598e6SHarald Freudenberger 	 * of the mkvp into the cache. Try 3 times: First witout verify
153efc598e6SHarald Freudenberger 	 * then with verify and last round with verify and old master
154efc598e6SHarald Freudenberger 	 * key verification pattern match not ignored.
155e80d4af0SHarald Freudenberger 	 */
156efc598e6SHarald Freudenberger 	for (verify = 0; verify < 3; verify++) {
157f2bbc96eSHarald Freudenberger 		rc = cca_findcard(key, &cardnr, &domain, verify);
158efc598e6SHarald Freudenberger 		if (rc < 0)
159e80d4af0SHarald Freudenberger 			continue;
160efc598e6SHarald Freudenberger 		if (rc > 0 && verify < 2)
161efc598e6SHarald Freudenberger 			continue;
162f2bbc96eSHarald Freudenberger 		switch (hdr->version) {
163f2bbc96eSHarald Freudenberger 		case TOKVER_CCA_AES:
164f2bbc96eSHarald Freudenberger 			rc = cca_sec2protkey(cardnr, domain,
165f2bbc96eSHarald Freudenberger 					     key, pkey->protkey,
166f2bbc96eSHarald Freudenberger 					     &pkey->len, &pkey->type);
167f2bbc96eSHarald Freudenberger 			break;
168f2bbc96eSHarald Freudenberger 		case TOKVER_CCA_VLSC:
169f2bbc96eSHarald Freudenberger 			rc = cca_cipher2protkey(cardnr, domain,
170f2bbc96eSHarald Freudenberger 						key, pkey->protkey,
171f2bbc96eSHarald Freudenberger 						&pkey->len, &pkey->type);
172f2bbc96eSHarald Freudenberger 			break;
173f2bbc96eSHarald Freudenberger 		default:
174f2bbc96eSHarald Freudenberger 			return -EINVAL;
175f2bbc96eSHarald Freudenberger 		}
176e80d4af0SHarald Freudenberger 		if (rc == 0)
177e80d4af0SHarald Freudenberger 			break;
178e80d4af0SHarald Freudenberger 	}
179e80d4af0SHarald Freudenberger 
180e80d4af0SHarald Freudenberger 	if (rc)
181ac2b96f3SHarald Freudenberger 		DEBUG_DBG("%s failed rc=%d\n", __func__, rc);
182e80d4af0SHarald Freudenberger 
183e80d4af0SHarald Freudenberger 	return rc;
184e80d4af0SHarald Freudenberger }
185e80d4af0SHarald Freudenberger 
186e80d4af0SHarald Freudenberger /*
187e61a6134SHarald Freudenberger  * Verify key and give back some info about the key.
188e61a6134SHarald Freudenberger  */
189183cb469SHarald Freudenberger static int pkey_verifykey(const struct pkey_seckey *seckey,
190e61a6134SHarald Freudenberger 			  u16 *pcardnr, u16 *pdomain,
191e61a6134SHarald Freudenberger 			  u16 *pkeysize, u32 *pattributes)
192e61a6134SHarald Freudenberger {
193e61a6134SHarald Freudenberger 	struct secaeskeytoken *t = (struct secaeskeytoken *) seckey;
194e61a6134SHarald Freudenberger 	u16 cardnr, domain;
195e61a6134SHarald Freudenberger 	int rc;
196e61a6134SHarald Freudenberger 
197e61a6134SHarald Freudenberger 	/* check the secure key for valid AES secure key */
198efc598e6SHarald Freudenberger 	rc = cca_check_secaeskeytoken(debug_info, 3, (u8 *) seckey, 0);
199e61a6134SHarald Freudenberger 	if (rc)
200e61a6134SHarald Freudenberger 		goto out;
201e61a6134SHarald Freudenberger 	if (pattributes)
202e61a6134SHarald Freudenberger 		*pattributes = PKEY_VERIFY_ATTR_AES;
203e61a6134SHarald Freudenberger 	if (pkeysize)
204e61a6134SHarald Freudenberger 		*pkeysize = t->bitsize;
205e61a6134SHarald Freudenberger 
206e61a6134SHarald Freudenberger 	/* try to find a card which can handle this key */
207efc598e6SHarald Freudenberger 	rc = cca_findcard(seckey->seckey, &cardnr, &domain, 1);
208efc598e6SHarald Freudenberger 	if (rc < 0)
209e61a6134SHarald Freudenberger 		goto out;
210e61a6134SHarald Freudenberger 
211efc598e6SHarald Freudenberger 	if (rc > 0) {
212efc598e6SHarald Freudenberger 		/* key mkvp matches to old master key mkvp */
213ac2b96f3SHarald Freudenberger 		DEBUG_DBG("%s secure key has old mkvp\n", __func__);
214e61a6134SHarald Freudenberger 		if (pattributes)
215e61a6134SHarald Freudenberger 			*pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP;
216efc598e6SHarald Freudenberger 		rc = 0;
217e61a6134SHarald Freudenberger 	}
218e61a6134SHarald Freudenberger 
219e61a6134SHarald Freudenberger 	if (pcardnr)
220e61a6134SHarald Freudenberger 		*pcardnr = cardnr;
221e61a6134SHarald Freudenberger 	if (pdomain)
222e61a6134SHarald Freudenberger 		*pdomain = domain;
223e61a6134SHarald Freudenberger 
224e61a6134SHarald Freudenberger out:
225ac2b96f3SHarald Freudenberger 	DEBUG_DBG("%s rc=%d\n", __func__, rc);
226e61a6134SHarald Freudenberger 	return rc;
227e61a6134SHarald Freudenberger }
228e61a6134SHarald Freudenberger 
229e61a6134SHarald Freudenberger /*
230a45a5c7dSIngo Franzki  * Generate a random protected key
231a45a5c7dSIngo Franzki  */
232183cb469SHarald Freudenberger static int pkey_genprotkey(u32 keytype, struct pkey_protkey *protkey)
233a45a5c7dSIngo Franzki {
234a45a5c7dSIngo Franzki 	struct pkey_clrkey clrkey;
235a45a5c7dSIngo Franzki 	int keysize;
236a45a5c7dSIngo Franzki 	int rc;
237a45a5c7dSIngo Franzki 
238a45a5c7dSIngo Franzki 	switch (keytype) {
239a45a5c7dSIngo Franzki 	case PKEY_KEYTYPE_AES_128:
240a45a5c7dSIngo Franzki 		keysize = 16;
241a45a5c7dSIngo Franzki 		break;
242a45a5c7dSIngo Franzki 	case PKEY_KEYTYPE_AES_192:
243a45a5c7dSIngo Franzki 		keysize = 24;
244a45a5c7dSIngo Franzki 		break;
245a45a5c7dSIngo Franzki 	case PKEY_KEYTYPE_AES_256:
246a45a5c7dSIngo Franzki 		keysize = 32;
247a45a5c7dSIngo Franzki 		break;
248a45a5c7dSIngo Franzki 	default:
249a45a5c7dSIngo Franzki 		DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
250a45a5c7dSIngo Franzki 			  keytype);
251a45a5c7dSIngo Franzki 		return -EINVAL;
252a45a5c7dSIngo Franzki 	}
253a45a5c7dSIngo Franzki 
254a45a5c7dSIngo Franzki 	/* generate a dummy random clear key */
255a45a5c7dSIngo Franzki 	get_random_bytes(clrkey.clrkey, keysize);
256a45a5c7dSIngo Franzki 
257a45a5c7dSIngo Franzki 	/* convert it to a dummy protected key */
258a45a5c7dSIngo Franzki 	rc = pkey_clr2protkey(keytype, &clrkey, protkey);
259a45a5c7dSIngo Franzki 	if (rc)
260a45a5c7dSIngo Franzki 		return rc;
261a45a5c7dSIngo Franzki 
262a45a5c7dSIngo Franzki 	/* replace the key part of the protected key with random bytes */
263a45a5c7dSIngo Franzki 	get_random_bytes(protkey->protkey, keysize);
264a45a5c7dSIngo Franzki 
265a45a5c7dSIngo Franzki 	return 0;
266a45a5c7dSIngo Franzki }
267a45a5c7dSIngo Franzki 
268a45a5c7dSIngo Franzki /*
269cb26b9ffSIngo Franzki  * Verify if a protected key is still valid
270cb26b9ffSIngo Franzki  */
271183cb469SHarald Freudenberger static int pkey_verifyprotkey(const struct pkey_protkey *protkey)
272cb26b9ffSIngo Franzki {
273cb26b9ffSIngo Franzki 	unsigned long fc;
274cb26b9ffSIngo Franzki 	struct {
275cb26b9ffSIngo Franzki 		u8 iv[AES_BLOCK_SIZE];
276cb26b9ffSIngo Franzki 		u8 key[MAXPROTKEYSIZE];
277cb26b9ffSIngo Franzki 	} param;
278cb26b9ffSIngo Franzki 	u8 null_msg[AES_BLOCK_SIZE];
279cb26b9ffSIngo Franzki 	u8 dest_buf[AES_BLOCK_SIZE];
280cb26b9ffSIngo Franzki 	unsigned int k;
281cb26b9ffSIngo Franzki 
282cb26b9ffSIngo Franzki 	switch (protkey->type) {
283cb26b9ffSIngo Franzki 	case PKEY_KEYTYPE_AES_128:
284cb26b9ffSIngo Franzki 		fc = CPACF_KMC_PAES_128;
285cb26b9ffSIngo Franzki 		break;
286cb26b9ffSIngo Franzki 	case PKEY_KEYTYPE_AES_192:
287cb26b9ffSIngo Franzki 		fc = CPACF_KMC_PAES_192;
288cb26b9ffSIngo Franzki 		break;
289cb26b9ffSIngo Franzki 	case PKEY_KEYTYPE_AES_256:
290cb26b9ffSIngo Franzki 		fc = CPACF_KMC_PAES_256;
291cb26b9ffSIngo Franzki 		break;
292cb26b9ffSIngo Franzki 	default:
293cb26b9ffSIngo Franzki 		DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
294cb26b9ffSIngo Franzki 			  protkey->type);
295cb26b9ffSIngo Franzki 		return -EINVAL;
296cb26b9ffSIngo Franzki 	}
297cb26b9ffSIngo Franzki 
298cb26b9ffSIngo Franzki 	memset(null_msg, 0, sizeof(null_msg));
299cb26b9ffSIngo Franzki 
300cb26b9ffSIngo Franzki 	memset(param.iv, 0, sizeof(param.iv));
301cb26b9ffSIngo Franzki 	memcpy(param.key, protkey->protkey, sizeof(param.key));
302cb26b9ffSIngo Franzki 
303cb26b9ffSIngo Franzki 	k = cpacf_kmc(fc | CPACF_ENCRYPT, &param, null_msg, dest_buf,
304cb26b9ffSIngo Franzki 		      sizeof(null_msg));
305cb26b9ffSIngo Franzki 	if (k != sizeof(null_msg)) {
306cb26b9ffSIngo Franzki 		DEBUG_ERR("%s protected key is not valid\n", __func__);
307cb26b9ffSIngo Franzki 		return -EKEYREJECTED;
308cb26b9ffSIngo Franzki 	}
309cb26b9ffSIngo Franzki 
310cb26b9ffSIngo Franzki 	return 0;
311cb26b9ffSIngo Franzki }
312cb26b9ffSIngo Franzki 
313cb26b9ffSIngo Franzki /*
314fb1136d6SIngo Franzki  * Transform a non-CCA key token into a protected key
315fb1136d6SIngo Franzki  */
316183cb469SHarald Freudenberger static int pkey_nonccatok2pkey(const u8 *key, u32 keylen,
317fb1136d6SIngo Franzki 			       struct pkey_protkey *protkey)
318fb1136d6SIngo Franzki {
319*888edbc4SHarald Freudenberger 	int rc = -EINVAL;
320fb1136d6SIngo Franzki 	struct keytoken_header *hdr = (struct keytoken_header *)key;
321fb1136d6SIngo Franzki 
322fb1136d6SIngo Franzki 	switch (hdr->version) {
323*888edbc4SHarald Freudenberger 	case TOKVER_PROTECTED_KEY: {
324*888edbc4SHarald Freudenberger 		struct protaeskeytoken *t;
325fb1136d6SIngo Franzki 
326*888edbc4SHarald Freudenberger 		if (keylen != sizeof(struct protaeskeytoken))
327*888edbc4SHarald Freudenberger 			goto out;
328fb1136d6SIngo Franzki 		t = (struct protaeskeytoken *)key;
329fb1136d6SIngo Franzki 		protkey->len = t->len;
330fb1136d6SIngo Franzki 		protkey->type = t->keytype;
331fb1136d6SIngo Franzki 		memcpy(protkey->protkey, t->protkey,
332fb1136d6SIngo Franzki 		       sizeof(protkey->protkey));
333*888edbc4SHarald Freudenberger 		rc = pkey_verifyprotkey(protkey);
334*888edbc4SHarald Freudenberger 		break;
335*888edbc4SHarald Freudenberger 	}
336*888edbc4SHarald Freudenberger 	case TOKVER_CLEAR_KEY: {
337*888edbc4SHarald Freudenberger 		struct clearaeskeytoken *t;
338*888edbc4SHarald Freudenberger 		struct pkey_clrkey ckey;
339*888edbc4SHarald Freudenberger 		struct pkey_seckey skey;
340fb1136d6SIngo Franzki 
341*888edbc4SHarald Freudenberger 		if (keylen < sizeof(struct clearaeskeytoken))
342*888edbc4SHarald Freudenberger 			goto out;
343*888edbc4SHarald Freudenberger 		t = (struct clearaeskeytoken *)key;
344*888edbc4SHarald Freudenberger 		if (keylen != sizeof(*t) + t->len)
345*888edbc4SHarald Freudenberger 			goto out;
346*888edbc4SHarald Freudenberger 		if ((t->keytype == PKEY_KEYTYPE_AES_128 && t->len == 16)
347*888edbc4SHarald Freudenberger 		    || (t->keytype == PKEY_KEYTYPE_AES_192 && t->len == 24)
348*888edbc4SHarald Freudenberger 		    || (t->keytype == PKEY_KEYTYPE_AES_256 && t->len == 32))
349*888edbc4SHarald Freudenberger 			memcpy(ckey.clrkey, t->clearkey, t->len);
350*888edbc4SHarald Freudenberger 		else
351*888edbc4SHarald Freudenberger 			goto out;
352*888edbc4SHarald Freudenberger 		/* try direct way with the PCKMO instruction */
353*888edbc4SHarald Freudenberger 		rc = pkey_clr2protkey(t->keytype, &ckey, protkey);
354*888edbc4SHarald Freudenberger 		if (rc == 0)
355*888edbc4SHarald Freudenberger 			break;
356*888edbc4SHarald Freudenberger 		/* PCKMO failed, so try the CCA secure key way */
357*888edbc4SHarald Freudenberger 		rc = cca_clr2seckey(0xFFFF, 0xFFFF, t->keytype,
358*888edbc4SHarald Freudenberger 				    ckey.clrkey, skey.seckey);
359*888edbc4SHarald Freudenberger 		if (rc == 0)
360*888edbc4SHarald Freudenberger 			rc = pkey_skey2pkey(skey.seckey, protkey);
361*888edbc4SHarald Freudenberger 		/* now we should really have an protected key */
362*888edbc4SHarald Freudenberger 		if (rc == 0)
363*888edbc4SHarald Freudenberger 			break;
364*888edbc4SHarald Freudenberger 		DEBUG_ERR("%s unable to build protected key from clear",
365*888edbc4SHarald Freudenberger 			  __func__);
366*888edbc4SHarald Freudenberger 		break;
367*888edbc4SHarald Freudenberger 	}
368fb1136d6SIngo Franzki 	default:
369fb1136d6SIngo Franzki 		DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
370fb1136d6SIngo Franzki 			  __func__, hdr->version);
371*888edbc4SHarald Freudenberger 		rc = -EINVAL;
372fb1136d6SIngo Franzki 	}
373*888edbc4SHarald Freudenberger 
374*888edbc4SHarald Freudenberger out:
375*888edbc4SHarald Freudenberger 	return rc;
376fb1136d6SIngo Franzki }
377fb1136d6SIngo Franzki 
378fb1136d6SIngo Franzki /*
379fb1136d6SIngo Franzki  * Transform a CCA internal key token into a protected key
380fb1136d6SIngo Franzki  */
381183cb469SHarald Freudenberger static int pkey_ccainttok2pkey(const u8 *key, u32 keylen,
382fb1136d6SIngo Franzki 			       struct pkey_protkey *protkey)
383fb1136d6SIngo Franzki {
384fb1136d6SIngo Franzki 	struct keytoken_header *hdr = (struct keytoken_header *)key;
385fb1136d6SIngo Franzki 
386fb1136d6SIngo Franzki 	switch (hdr->version) {
387fb1136d6SIngo Franzki 	case TOKVER_CCA_AES:
388fb1136d6SIngo Franzki 		if (keylen != sizeof(struct secaeskeytoken))
389fb1136d6SIngo Franzki 			return -EINVAL;
390f2bbc96eSHarald Freudenberger 		break;
391f2bbc96eSHarald Freudenberger 	case TOKVER_CCA_VLSC:
392f2bbc96eSHarald Freudenberger 		if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
393f2bbc96eSHarald Freudenberger 			return -EINVAL;
394f2bbc96eSHarald Freudenberger 		break;
395fb1136d6SIngo Franzki 	default:
396fb1136d6SIngo Franzki 		DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n",
397fb1136d6SIngo Franzki 			  __func__, hdr->version);
398fb1136d6SIngo Franzki 		return -EINVAL;
399fb1136d6SIngo Franzki 	}
400f2bbc96eSHarald Freudenberger 
401f2bbc96eSHarald Freudenberger 	return pkey_skey2pkey(key, protkey);
402fb1136d6SIngo Franzki }
403fb1136d6SIngo Franzki 
404fb1136d6SIngo Franzki /*
405fb1136d6SIngo Franzki  * Transform a key blob (of any type) into a protected key
406fb1136d6SIngo Franzki  */
407183cb469SHarald Freudenberger int pkey_keyblob2pkey(const u8 *key, u32 keylen,
408fb1136d6SIngo Franzki 		      struct pkey_protkey *protkey)
409fb1136d6SIngo Franzki {
410f2bbc96eSHarald Freudenberger 	int rc;
411fb1136d6SIngo Franzki 	struct keytoken_header *hdr = (struct keytoken_header *)key;
412fb1136d6SIngo Franzki 
413f2bbc96eSHarald Freudenberger 	if (keylen < sizeof(struct keytoken_header)) {
414f2bbc96eSHarald Freudenberger 		DEBUG_ERR("%s invalid keylen %d\n", __func__, keylen);
415f2bbc96eSHarald Freudenberger 		return -EINVAL;
416f2bbc96eSHarald Freudenberger 	}
417f2bbc96eSHarald Freudenberger 
418f2bbc96eSHarald Freudenberger 	switch (hdr->type) {
419f2bbc96eSHarald Freudenberger 	case TOKTYPE_NON_CCA:
420f2bbc96eSHarald Freudenberger 		rc = pkey_nonccatok2pkey(key, keylen, protkey);
421f2bbc96eSHarald Freudenberger 		break;
422f2bbc96eSHarald Freudenberger 	case TOKTYPE_CCA_INTERNAL:
423f2bbc96eSHarald Freudenberger 		rc = pkey_ccainttok2pkey(key, keylen, protkey);
424f2bbc96eSHarald Freudenberger 		break;
425f2bbc96eSHarald Freudenberger 	default:
426f2bbc96eSHarald Freudenberger 		DEBUG_ERR("%s unknown/unsupported blob type %d\n",
427f2bbc96eSHarald Freudenberger 			  __func__, hdr->type);
428f2bbc96eSHarald Freudenberger 		return -EINVAL;
429f2bbc96eSHarald Freudenberger 	}
430f2bbc96eSHarald Freudenberger 
431f2bbc96eSHarald Freudenberger 	DEBUG_DBG("%s rc=%d\n", __func__, rc);
432f2bbc96eSHarald Freudenberger 	return rc;
433f2bbc96eSHarald Freudenberger 
434f2bbc96eSHarald Freudenberger }
435f2bbc96eSHarald Freudenberger EXPORT_SYMBOL(pkey_keyblob2pkey);
436f2bbc96eSHarald Freudenberger 
437f2bbc96eSHarald Freudenberger static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
438f2bbc96eSHarald Freudenberger 			   enum pkey_key_type ktype, enum pkey_key_size ksize,
439f2bbc96eSHarald Freudenberger 			   u32 kflags, u8 *keybuf, size_t *keybufsize)
440f2bbc96eSHarald Freudenberger {
441f2bbc96eSHarald Freudenberger 	int i, card, dom, rc;
442f2bbc96eSHarald Freudenberger 
443f2bbc96eSHarald Freudenberger 	/* check for at least one apqn given */
444f2bbc96eSHarald Freudenberger 	if (!apqns || !nr_apqns)
445f2bbc96eSHarald Freudenberger 		return -EINVAL;
446f2bbc96eSHarald Freudenberger 
447f2bbc96eSHarald Freudenberger 	/* check key type and size */
448f2bbc96eSHarald Freudenberger 	switch (ktype) {
449f2bbc96eSHarald Freudenberger 	case PKEY_TYPE_CCA_DATA:
450f2bbc96eSHarald Freudenberger 	case PKEY_TYPE_CCA_CIPHER:
451f2bbc96eSHarald Freudenberger 		if (*keybufsize < SECKEYBLOBSIZE)
452f2bbc96eSHarald Freudenberger 			return -EINVAL;
453f2bbc96eSHarald Freudenberger 		break;
454f2bbc96eSHarald Freudenberger 	default:
455f2bbc96eSHarald Freudenberger 		return -EINVAL;
456f2bbc96eSHarald Freudenberger 	}
457f2bbc96eSHarald Freudenberger 	switch (ksize) {
458f2bbc96eSHarald Freudenberger 	case PKEY_SIZE_AES_128:
459f2bbc96eSHarald Freudenberger 	case PKEY_SIZE_AES_192:
460f2bbc96eSHarald Freudenberger 	case PKEY_SIZE_AES_256:
461f2bbc96eSHarald Freudenberger 		break;
462f2bbc96eSHarald Freudenberger 	default:
463f2bbc96eSHarald Freudenberger 		return -EINVAL;
464f2bbc96eSHarald Freudenberger 	}
465f2bbc96eSHarald Freudenberger 
466f2bbc96eSHarald Freudenberger 	/* simple try all apqns from the list */
467f2bbc96eSHarald Freudenberger 	for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
468f2bbc96eSHarald Freudenberger 		card = apqns[i].card;
469f2bbc96eSHarald Freudenberger 		dom = apqns[i].domain;
470f2bbc96eSHarald Freudenberger 		if (ktype == PKEY_TYPE_CCA_DATA) {
471f2bbc96eSHarald Freudenberger 			rc = cca_genseckey(card, dom, ksize, keybuf);
472f2bbc96eSHarald Freudenberger 			*keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
473f2bbc96eSHarald Freudenberger 		} else /* TOKVER_CCA_VLSC */
474f2bbc96eSHarald Freudenberger 			rc = cca_gencipherkey(card, dom, ksize, kflags,
475f2bbc96eSHarald Freudenberger 					      keybuf, keybufsize);
476f2bbc96eSHarald Freudenberger 		if (rc == 0)
477f2bbc96eSHarald Freudenberger 			break;
478f2bbc96eSHarald Freudenberger 	}
479f2bbc96eSHarald Freudenberger 
480f2bbc96eSHarald Freudenberger 	return rc;
481f2bbc96eSHarald Freudenberger }
482f2bbc96eSHarald Freudenberger 
483f2bbc96eSHarald Freudenberger static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns,
484f2bbc96eSHarald Freudenberger 			    enum pkey_key_type ktype, enum pkey_key_size ksize,
485f2bbc96eSHarald Freudenberger 			    u32 kflags, const u8 *clrkey,
486f2bbc96eSHarald Freudenberger 			    u8 *keybuf, size_t *keybufsize)
487f2bbc96eSHarald Freudenberger {
488f2bbc96eSHarald Freudenberger 	int i, card, dom, rc;
489f2bbc96eSHarald Freudenberger 
490f2bbc96eSHarald Freudenberger 	/* check for at least one apqn given */
491f2bbc96eSHarald Freudenberger 	if (!apqns || !nr_apqns)
492f2bbc96eSHarald Freudenberger 		return -EINVAL;
493f2bbc96eSHarald Freudenberger 
494f2bbc96eSHarald Freudenberger 	/* check key type and size */
495f2bbc96eSHarald Freudenberger 	switch (ktype) {
496f2bbc96eSHarald Freudenberger 	case PKEY_TYPE_CCA_DATA:
497f2bbc96eSHarald Freudenberger 	case PKEY_TYPE_CCA_CIPHER:
498f2bbc96eSHarald Freudenberger 		if (*keybufsize < SECKEYBLOBSIZE)
499f2bbc96eSHarald Freudenberger 			return -EINVAL;
500f2bbc96eSHarald Freudenberger 		break;
501f2bbc96eSHarald Freudenberger 	default:
502f2bbc96eSHarald Freudenberger 		return -EINVAL;
503f2bbc96eSHarald Freudenberger 	}
504f2bbc96eSHarald Freudenberger 	switch (ksize) {
505f2bbc96eSHarald Freudenberger 	case PKEY_SIZE_AES_128:
506f2bbc96eSHarald Freudenberger 	case PKEY_SIZE_AES_192:
507f2bbc96eSHarald Freudenberger 	case PKEY_SIZE_AES_256:
508f2bbc96eSHarald Freudenberger 		break;
509f2bbc96eSHarald Freudenberger 	default:
510f2bbc96eSHarald Freudenberger 		return -EINVAL;
511f2bbc96eSHarald Freudenberger 	}
512f2bbc96eSHarald Freudenberger 
513f2bbc96eSHarald Freudenberger 	/* simple try all apqns from the list */
514f2bbc96eSHarald Freudenberger 	for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
515f2bbc96eSHarald Freudenberger 		card = apqns[i].card;
516f2bbc96eSHarald Freudenberger 		dom = apqns[i].domain;
517f2bbc96eSHarald Freudenberger 		if (ktype == PKEY_TYPE_CCA_DATA) {
518f2bbc96eSHarald Freudenberger 			rc = cca_clr2seckey(card, dom, ksize,
519f2bbc96eSHarald Freudenberger 					    clrkey, keybuf);
520f2bbc96eSHarald Freudenberger 			*keybufsize = (rc ? 0 : SECKEYBLOBSIZE);
521f2bbc96eSHarald Freudenberger 		} else /* TOKVER_CCA_VLSC */
522f2bbc96eSHarald Freudenberger 			rc = cca_clr2cipherkey(card, dom, ksize, kflags,
523f2bbc96eSHarald Freudenberger 					       clrkey, keybuf, keybufsize);
524f2bbc96eSHarald Freudenberger 		if (rc == 0)
525f2bbc96eSHarald Freudenberger 			break;
526f2bbc96eSHarald Freudenberger 	}
527f2bbc96eSHarald Freudenberger 
528f2bbc96eSHarald Freudenberger 	return rc;
529f2bbc96eSHarald Freudenberger }
530f2bbc96eSHarald Freudenberger 
531f2bbc96eSHarald Freudenberger static int pkey_verifykey2(const u8 *key, size_t keylen,
532f2bbc96eSHarald Freudenberger 			   u16 *cardnr, u16 *domain,
533f2bbc96eSHarald Freudenberger 			   enum pkey_key_type *ktype,
534f2bbc96eSHarald Freudenberger 			   enum pkey_key_size *ksize, u32 *flags)
535f2bbc96eSHarald Freudenberger {
536f2bbc96eSHarald Freudenberger 	int rc;
537f2bbc96eSHarald Freudenberger 	u32 _nr_apqns, *_apqns = NULL;
538f2bbc96eSHarald Freudenberger 	struct keytoken_header *hdr = (struct keytoken_header *)key;
539f2bbc96eSHarald Freudenberger 
540f2bbc96eSHarald Freudenberger 	if (keylen < sizeof(struct keytoken_header) ||
541f2bbc96eSHarald Freudenberger 	    hdr->type != TOKTYPE_CCA_INTERNAL)
542f2bbc96eSHarald Freudenberger 		return -EINVAL;
543f2bbc96eSHarald Freudenberger 
544f2bbc96eSHarald Freudenberger 	if (hdr->version == TOKVER_CCA_AES) {
545f2bbc96eSHarald Freudenberger 		struct secaeskeytoken *t = (struct secaeskeytoken *)key;
546f2bbc96eSHarald Freudenberger 
547f2bbc96eSHarald Freudenberger 		rc = cca_check_secaeskeytoken(debug_info, 3, key, 0);
548f2bbc96eSHarald Freudenberger 		if (rc)
549f2bbc96eSHarald Freudenberger 			goto out;
550f2bbc96eSHarald Freudenberger 		if (ktype)
551f2bbc96eSHarald Freudenberger 			*ktype = PKEY_TYPE_CCA_DATA;
552f2bbc96eSHarald Freudenberger 		if (ksize)
553f2bbc96eSHarald Freudenberger 			*ksize = (enum pkey_key_size) t->bitsize;
554f2bbc96eSHarald Freudenberger 
555f2bbc96eSHarald Freudenberger 		rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain,
556f2bbc96eSHarald Freudenberger 				   ZCRYPT_CEX3C, t->mkvp, 0, 1);
557f2bbc96eSHarald Freudenberger 		if (rc == 0 && flags)
558f2bbc96eSHarald Freudenberger 			*flags = PKEY_FLAGS_MATCH_CUR_MKVP;
559f2bbc96eSHarald Freudenberger 		if (rc == -ENODEV) {
560f2bbc96eSHarald Freudenberger 			rc = cca_findcard2(&_apqns, &_nr_apqns,
561f2bbc96eSHarald Freudenberger 					   *cardnr, *domain,
562f2bbc96eSHarald Freudenberger 					   ZCRYPT_CEX3C, 0, t->mkvp, 1);
563f2bbc96eSHarald Freudenberger 			if (rc == 0 && flags)
564f2bbc96eSHarald Freudenberger 				*flags = PKEY_FLAGS_MATCH_ALT_MKVP;
565f2bbc96eSHarald Freudenberger 		}
566f2bbc96eSHarald Freudenberger 		if (rc)
567f2bbc96eSHarald Freudenberger 			goto out;
568f2bbc96eSHarald Freudenberger 
569f2bbc96eSHarald Freudenberger 		*cardnr = ((struct pkey_apqn *)_apqns)->card;
570f2bbc96eSHarald Freudenberger 		*domain = ((struct pkey_apqn *)_apqns)->domain;
571f2bbc96eSHarald Freudenberger 
572f2bbc96eSHarald Freudenberger 	} else if (hdr->version == TOKVER_CCA_VLSC) {
573f2bbc96eSHarald Freudenberger 		struct cipherkeytoken *t = (struct cipherkeytoken *)key;
574f2bbc96eSHarald Freudenberger 
575f2bbc96eSHarald Freudenberger 		rc = cca_check_secaescipherkey(debug_info, 3, key, 0, 1);
576f2bbc96eSHarald Freudenberger 		if (rc)
577f2bbc96eSHarald Freudenberger 			goto out;
578f2bbc96eSHarald Freudenberger 		if (ktype)
579f2bbc96eSHarald Freudenberger 			*ktype = PKEY_TYPE_CCA_CIPHER;
580f2bbc96eSHarald Freudenberger 		if (ksize) {
581f2bbc96eSHarald Freudenberger 			*ksize = PKEY_SIZE_UNKNOWN;
582f2bbc96eSHarald Freudenberger 			if (!t->plfver && t->wpllen == 512)
583f2bbc96eSHarald Freudenberger 				*ksize = PKEY_SIZE_AES_128;
584f2bbc96eSHarald Freudenberger 			else if (!t->plfver && t->wpllen == 576)
585f2bbc96eSHarald Freudenberger 				*ksize = PKEY_SIZE_AES_192;
586f2bbc96eSHarald Freudenberger 			else if (!t->plfver && t->wpllen == 640)
587f2bbc96eSHarald Freudenberger 				*ksize = PKEY_SIZE_AES_256;
588f2bbc96eSHarald Freudenberger 		}
589f2bbc96eSHarald Freudenberger 
590f2bbc96eSHarald Freudenberger 		rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain,
591f2bbc96eSHarald Freudenberger 				   ZCRYPT_CEX6, t->mkvp0, 0, 1);
592f2bbc96eSHarald Freudenberger 		if (rc == 0 && flags)
593f2bbc96eSHarald Freudenberger 			*flags = PKEY_FLAGS_MATCH_CUR_MKVP;
594f2bbc96eSHarald Freudenberger 		if (rc == -ENODEV) {
595f2bbc96eSHarald Freudenberger 			rc = cca_findcard2(&_apqns, &_nr_apqns,
596f2bbc96eSHarald Freudenberger 					   *cardnr, *domain,
597f2bbc96eSHarald Freudenberger 					   ZCRYPT_CEX6, 0, t->mkvp0, 1);
598f2bbc96eSHarald Freudenberger 			if (rc == 0 && flags)
599f2bbc96eSHarald Freudenberger 				*flags = PKEY_FLAGS_MATCH_ALT_MKVP;
600f2bbc96eSHarald Freudenberger 		}
601f2bbc96eSHarald Freudenberger 		if (rc)
602f2bbc96eSHarald Freudenberger 			goto out;
603f2bbc96eSHarald Freudenberger 
604f2bbc96eSHarald Freudenberger 		*cardnr = ((struct pkey_apqn *)_apqns)->card;
605f2bbc96eSHarald Freudenberger 		*domain = ((struct pkey_apqn *)_apqns)->domain;
606f2bbc96eSHarald Freudenberger 
607f2bbc96eSHarald Freudenberger 	} else
608f2bbc96eSHarald Freudenberger 		rc = -EINVAL;
609f2bbc96eSHarald Freudenberger 
610f2bbc96eSHarald Freudenberger out:
611f2bbc96eSHarald Freudenberger 	kfree(_apqns);
612f2bbc96eSHarald Freudenberger 	return rc;
613f2bbc96eSHarald Freudenberger }
614f2bbc96eSHarald Freudenberger 
615f2bbc96eSHarald Freudenberger static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns,
616f2bbc96eSHarald Freudenberger 			      const u8 *key, size_t keylen,
617f2bbc96eSHarald Freudenberger 			      struct pkey_protkey *pkey)
618f2bbc96eSHarald Freudenberger {
619f2bbc96eSHarald Freudenberger 	int i, card, dom, rc;
620f2bbc96eSHarald Freudenberger 	struct keytoken_header *hdr = (struct keytoken_header *)key;
621f2bbc96eSHarald Freudenberger 
622f2bbc96eSHarald Freudenberger 	/* check for at least one apqn given */
623f2bbc96eSHarald Freudenberger 	if (!apqns || !nr_apqns)
624f2bbc96eSHarald Freudenberger 		return -EINVAL;
625f2bbc96eSHarald Freudenberger 
626fb1136d6SIngo Franzki 	if (keylen < sizeof(struct keytoken_header))
627fb1136d6SIngo Franzki 		return -EINVAL;
628fb1136d6SIngo Franzki 
629fb1136d6SIngo Franzki 	switch (hdr->type) {
630fb1136d6SIngo Franzki 	case TOKTYPE_NON_CCA:
631f2bbc96eSHarald Freudenberger 		return pkey_nonccatok2pkey(key, keylen, pkey);
632fb1136d6SIngo Franzki 	case TOKTYPE_CCA_INTERNAL:
633f2bbc96eSHarald Freudenberger 		switch (hdr->version) {
634f2bbc96eSHarald Freudenberger 		case TOKVER_CCA_AES:
635f2bbc96eSHarald Freudenberger 			if (keylen != sizeof(struct secaeskeytoken))
636f2bbc96eSHarald Freudenberger 				return -EINVAL;
637f2bbc96eSHarald Freudenberger 			if (cca_check_secaeskeytoken(debug_info, 3, key, 0))
638f2bbc96eSHarald Freudenberger 				return -EINVAL;
639f2bbc96eSHarald Freudenberger 			break;
640f2bbc96eSHarald Freudenberger 		case TOKVER_CCA_VLSC:
641f2bbc96eSHarald Freudenberger 			if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE)
642f2bbc96eSHarald Freudenberger 				return -EINVAL;
643f2bbc96eSHarald Freudenberger 			if (cca_check_secaescipherkey(debug_info, 3, key, 0, 1))
644f2bbc96eSHarald Freudenberger 				return -EINVAL;
645f2bbc96eSHarald Freudenberger 			break;
646fb1136d6SIngo Franzki 		default:
647f2bbc96eSHarald Freudenberger 			DEBUG_ERR("%s unknown CCA internal token version %d\n",
648f2bbc96eSHarald Freudenberger 				  __func__, hdr->version);
649fb1136d6SIngo Franzki 			return -EINVAL;
650fb1136d6SIngo Franzki 		}
651f2bbc96eSHarald Freudenberger 		break;
652f2bbc96eSHarald Freudenberger 	default:
653f2bbc96eSHarald Freudenberger 		DEBUG_ERR("%s unknown/unsupported blob type %d\n",
654f2bbc96eSHarald Freudenberger 			  __func__, hdr->type);
655f2bbc96eSHarald Freudenberger 		return -EINVAL;
656fb1136d6SIngo Franzki 	}
657f2bbc96eSHarald Freudenberger 
658f2bbc96eSHarald Freudenberger 	/* simple try all apqns from the list */
659f2bbc96eSHarald Freudenberger 	for (i = 0, rc = -ENODEV; i < nr_apqns; i++) {
660f2bbc96eSHarald Freudenberger 		card = apqns[i].card;
661f2bbc96eSHarald Freudenberger 		dom = apqns[i].domain;
662f2bbc96eSHarald Freudenberger 		if (hdr->version == TOKVER_CCA_AES)
663f2bbc96eSHarald Freudenberger 			rc = cca_sec2protkey(card, dom, key, pkey->protkey,
664f2bbc96eSHarald Freudenberger 					     &pkey->len, &pkey->type);
665f2bbc96eSHarald Freudenberger 		else /* TOKVER_CCA_VLSC */
666f2bbc96eSHarald Freudenberger 			rc = cca_cipher2protkey(card, dom, key, pkey->protkey,
667f2bbc96eSHarald Freudenberger 						&pkey->len, &pkey->type);
668f2bbc96eSHarald Freudenberger 		if (rc == 0)
669f2bbc96eSHarald Freudenberger 			break;
670f2bbc96eSHarald Freudenberger 	}
671f2bbc96eSHarald Freudenberger 
672f2bbc96eSHarald Freudenberger 	return rc;
673f2bbc96eSHarald Freudenberger }
674f2bbc96eSHarald Freudenberger 
675f2bbc96eSHarald Freudenberger static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags,
676f2bbc96eSHarald Freudenberger 			  struct pkey_apqn *apqns, size_t *nr_apqns)
677f2bbc96eSHarald Freudenberger {
678f2bbc96eSHarald Freudenberger 	int rc = EINVAL;
679f2bbc96eSHarald Freudenberger 	u32 _nr_apqns, *_apqns = NULL;
680f2bbc96eSHarald Freudenberger 	struct keytoken_header *hdr = (struct keytoken_header *)key;
681f2bbc96eSHarald Freudenberger 
682f2bbc96eSHarald Freudenberger 	if (keylen < sizeof(struct keytoken_header) ||
683f2bbc96eSHarald Freudenberger 	    hdr->type != TOKTYPE_CCA_INTERNAL ||
684f2bbc96eSHarald Freudenberger 	    flags == 0)
685f2bbc96eSHarald Freudenberger 		return -EINVAL;
686f2bbc96eSHarald Freudenberger 
687f2bbc96eSHarald Freudenberger 	if (hdr->version == TOKVER_CCA_AES || hdr->version == TOKVER_CCA_VLSC) {
688f2bbc96eSHarald Freudenberger 		int minhwtype = ZCRYPT_CEX3C;
689f2bbc96eSHarald Freudenberger 		u64 cur_mkvp = 0, old_mkvp = 0;
690f2bbc96eSHarald Freudenberger 
691f2bbc96eSHarald Freudenberger 		if (hdr->version == TOKVER_CCA_AES) {
692f2bbc96eSHarald Freudenberger 			struct secaeskeytoken *t = (struct secaeskeytoken *)key;
693f2bbc96eSHarald Freudenberger 
694f2bbc96eSHarald Freudenberger 			if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
695f2bbc96eSHarald Freudenberger 				cur_mkvp = t->mkvp;
696f2bbc96eSHarald Freudenberger 			if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
697f2bbc96eSHarald Freudenberger 				old_mkvp = t->mkvp;
698f2bbc96eSHarald Freudenberger 		} else {
699f2bbc96eSHarald Freudenberger 			struct cipherkeytoken *t = (struct cipherkeytoken *)key;
700f2bbc96eSHarald Freudenberger 
701f2bbc96eSHarald Freudenberger 			minhwtype = ZCRYPT_CEX6;
702f2bbc96eSHarald Freudenberger 			if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
703f2bbc96eSHarald Freudenberger 				cur_mkvp = t->mkvp0;
704f2bbc96eSHarald Freudenberger 			if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
705f2bbc96eSHarald Freudenberger 				old_mkvp = t->mkvp0;
706f2bbc96eSHarald Freudenberger 		}
707f2bbc96eSHarald Freudenberger 		rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
708f2bbc96eSHarald Freudenberger 				   minhwtype, cur_mkvp, old_mkvp, 1);
709f2bbc96eSHarald Freudenberger 		if (rc)
710f2bbc96eSHarald Freudenberger 			goto out;
711f2bbc96eSHarald Freudenberger 		if (apqns) {
712f2bbc96eSHarald Freudenberger 			if (*nr_apqns < _nr_apqns)
713f2bbc96eSHarald Freudenberger 				rc = -ENOSPC;
714f2bbc96eSHarald Freudenberger 			else
715f2bbc96eSHarald Freudenberger 				memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
716f2bbc96eSHarald Freudenberger 		}
717f2bbc96eSHarald Freudenberger 		*nr_apqns = _nr_apqns;
718f2bbc96eSHarald Freudenberger 	}
719f2bbc96eSHarald Freudenberger 
720f2bbc96eSHarald Freudenberger out:
721f2bbc96eSHarald Freudenberger 	kfree(_apqns);
722f2bbc96eSHarald Freudenberger 	return rc;
723f2bbc96eSHarald Freudenberger }
724f2bbc96eSHarald Freudenberger 
725f2bbc96eSHarald Freudenberger static int pkey_apqns4keytype(enum pkey_key_type ktype,
726f2bbc96eSHarald Freudenberger 			      u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags,
727f2bbc96eSHarald Freudenberger 			      struct pkey_apqn *apqns, size_t *nr_apqns)
728f2bbc96eSHarald Freudenberger {
729f2bbc96eSHarald Freudenberger 	int rc = -EINVAL;
730f2bbc96eSHarald Freudenberger 	u32 _nr_apqns, *_apqns = NULL;
731f2bbc96eSHarald Freudenberger 
732f2bbc96eSHarald Freudenberger 	if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) {
733f2bbc96eSHarald Freudenberger 		u64 cur_mkvp = 0, old_mkvp = 0;
734f2bbc96eSHarald Freudenberger 		int minhwtype = ZCRYPT_CEX3C;
735f2bbc96eSHarald Freudenberger 
736f2bbc96eSHarald Freudenberger 		if (flags & PKEY_FLAGS_MATCH_CUR_MKVP)
737f2bbc96eSHarald Freudenberger 			cur_mkvp = *((u64 *) cur_mkvp);
738f2bbc96eSHarald Freudenberger 		if (flags & PKEY_FLAGS_MATCH_ALT_MKVP)
739f2bbc96eSHarald Freudenberger 			old_mkvp = *((u64 *) alt_mkvp);
740f2bbc96eSHarald Freudenberger 		if (ktype == PKEY_TYPE_CCA_CIPHER)
741f2bbc96eSHarald Freudenberger 			minhwtype = ZCRYPT_CEX6;
742f2bbc96eSHarald Freudenberger 		rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF,
743f2bbc96eSHarald Freudenberger 				   minhwtype, cur_mkvp, old_mkvp, 1);
744f2bbc96eSHarald Freudenberger 		if (rc)
745f2bbc96eSHarald Freudenberger 			goto out;
746f2bbc96eSHarald Freudenberger 		if (apqns) {
747f2bbc96eSHarald Freudenberger 			if (*nr_apqns < _nr_apqns)
748f2bbc96eSHarald Freudenberger 				rc = -ENOSPC;
749f2bbc96eSHarald Freudenberger 			else
750f2bbc96eSHarald Freudenberger 				memcpy(apqns, _apqns, _nr_apqns * sizeof(u32));
751f2bbc96eSHarald Freudenberger 		}
752f2bbc96eSHarald Freudenberger 		*nr_apqns = _nr_apqns;
753f2bbc96eSHarald Freudenberger 	}
754f2bbc96eSHarald Freudenberger 
755f2bbc96eSHarald Freudenberger out:
756f2bbc96eSHarald Freudenberger 	kfree(_apqns);
757f2bbc96eSHarald Freudenberger 	return rc;
758f2bbc96eSHarald Freudenberger }
759fb1136d6SIngo Franzki 
760fb1136d6SIngo Franzki /*
761e80d4af0SHarald Freudenberger  * File io functions
762e80d4af0SHarald Freudenberger  */
763e80d4af0SHarald Freudenberger 
764f2bbc96eSHarald Freudenberger static void *_copy_key_from_user(void __user *ukey, size_t keylen)
765f2bbc96eSHarald Freudenberger {
766f2bbc96eSHarald Freudenberger 	if (!ukey || keylen < MINKEYBLOBSIZE || keylen > KEYBLOBBUFSIZE)
767f2bbc96eSHarald Freudenberger 		return ERR_PTR(-EINVAL);
768f2bbc96eSHarald Freudenberger 
7698b57e7c8SMarkus Elfring 	return memdup_user(ukey, keylen);
770f2bbc96eSHarald Freudenberger }
771f2bbc96eSHarald Freudenberger 
772f2bbc96eSHarald Freudenberger static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns)
773f2bbc96eSHarald Freudenberger {
7748b57e7c8SMarkus Elfring 	if (!uapqns || nr_apqns == 0)
7758b57e7c8SMarkus Elfring 		return NULL;
776f2bbc96eSHarald Freudenberger 
7778b57e7c8SMarkus Elfring 	return memdup_user(uapqns, nr_apqns * sizeof(struct pkey_apqn));
778f2bbc96eSHarald Freudenberger }
779f2bbc96eSHarald Freudenberger 
780e80d4af0SHarald Freudenberger static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
781e80d4af0SHarald Freudenberger 				unsigned long arg)
782e80d4af0SHarald Freudenberger {
783e80d4af0SHarald Freudenberger 	int rc;
784e80d4af0SHarald Freudenberger 
785e80d4af0SHarald Freudenberger 	switch (cmd) {
786e80d4af0SHarald Freudenberger 	case PKEY_GENSECK: {
787e80d4af0SHarald Freudenberger 		struct pkey_genseck __user *ugs = (void __user *) arg;
788e80d4af0SHarald Freudenberger 		struct pkey_genseck kgs;
789e80d4af0SHarald Freudenberger 
790e80d4af0SHarald Freudenberger 		if (copy_from_user(&kgs, ugs, sizeof(kgs)))
791e80d4af0SHarald Freudenberger 			return -EFAULT;
792efc598e6SHarald Freudenberger 		rc = cca_genseckey(kgs.cardnr, kgs.domain,
793efc598e6SHarald Freudenberger 				   kgs.keytype, kgs.seckey.seckey);
794efc598e6SHarald Freudenberger 		DEBUG_DBG("%s cca_genseckey()=%d\n", __func__, rc);
795e80d4af0SHarald Freudenberger 		if (rc)
796e80d4af0SHarald Freudenberger 			break;
797e80d4af0SHarald Freudenberger 		if (copy_to_user(ugs, &kgs, sizeof(kgs)))
798e80d4af0SHarald Freudenberger 			return -EFAULT;
799e80d4af0SHarald Freudenberger 		break;
800e80d4af0SHarald Freudenberger 	}
801e80d4af0SHarald Freudenberger 	case PKEY_CLR2SECK: {
802e80d4af0SHarald Freudenberger 		struct pkey_clr2seck __user *ucs = (void __user *) arg;
803e80d4af0SHarald Freudenberger 		struct pkey_clr2seck kcs;
804e80d4af0SHarald Freudenberger 
805e80d4af0SHarald Freudenberger 		if (copy_from_user(&kcs, ucs, sizeof(kcs)))
806e80d4af0SHarald Freudenberger 			return -EFAULT;
807efc598e6SHarald Freudenberger 		rc = cca_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype,
808efc598e6SHarald Freudenberger 				    kcs.clrkey.clrkey, kcs.seckey.seckey);
809efc598e6SHarald Freudenberger 		DEBUG_DBG("%s cca_clr2seckey()=%d\n", __func__, rc);
810e80d4af0SHarald Freudenberger 		if (rc)
811e80d4af0SHarald Freudenberger 			break;
812e80d4af0SHarald Freudenberger 		if (copy_to_user(ucs, &kcs, sizeof(kcs)))
813e80d4af0SHarald Freudenberger 			return -EFAULT;
814e80d4af0SHarald Freudenberger 		memzero_explicit(&kcs, sizeof(kcs));
815e80d4af0SHarald Freudenberger 		break;
816e80d4af0SHarald Freudenberger 	}
817e80d4af0SHarald Freudenberger 	case PKEY_SEC2PROTK: {
818e80d4af0SHarald Freudenberger 		struct pkey_sec2protk __user *usp = (void __user *) arg;
819e80d4af0SHarald Freudenberger 		struct pkey_sec2protk ksp;
820e80d4af0SHarald Freudenberger 
821e80d4af0SHarald Freudenberger 		if (copy_from_user(&ksp, usp, sizeof(ksp)))
822e80d4af0SHarald Freudenberger 			return -EFAULT;
823efc598e6SHarald Freudenberger 		rc = cca_sec2protkey(ksp.cardnr, ksp.domain,
824efc598e6SHarald Freudenberger 				     ksp.seckey.seckey, ksp.protkey.protkey,
825efc598e6SHarald Freudenberger 				     NULL, &ksp.protkey.type);
826efc598e6SHarald Freudenberger 		DEBUG_DBG("%s cca_sec2protkey()=%d\n", __func__, rc);
827e80d4af0SHarald Freudenberger 		if (rc)
828e80d4af0SHarald Freudenberger 			break;
829e80d4af0SHarald Freudenberger 		if (copy_to_user(usp, &ksp, sizeof(ksp)))
830e80d4af0SHarald Freudenberger 			return -EFAULT;
831e80d4af0SHarald Freudenberger 		break;
832e80d4af0SHarald Freudenberger 	}
833e80d4af0SHarald Freudenberger 	case PKEY_CLR2PROTK: {
834e80d4af0SHarald Freudenberger 		struct pkey_clr2protk __user *ucp = (void __user *) arg;
835e80d4af0SHarald Freudenberger 		struct pkey_clr2protk kcp;
836e80d4af0SHarald Freudenberger 
837e80d4af0SHarald Freudenberger 		if (copy_from_user(&kcp, ucp, sizeof(kcp)))
838e80d4af0SHarald Freudenberger 			return -EFAULT;
839e80d4af0SHarald Freudenberger 		rc = pkey_clr2protkey(kcp.keytype,
840e80d4af0SHarald Freudenberger 				      &kcp.clrkey, &kcp.protkey);
841ac2b96f3SHarald Freudenberger 		DEBUG_DBG("%s pkey_clr2protkey()=%d\n", __func__, rc);
842e80d4af0SHarald Freudenberger 		if (rc)
843e80d4af0SHarald Freudenberger 			break;
844e80d4af0SHarald Freudenberger 		if (copy_to_user(ucp, &kcp, sizeof(kcp)))
845e80d4af0SHarald Freudenberger 			return -EFAULT;
846e80d4af0SHarald Freudenberger 		memzero_explicit(&kcp, sizeof(kcp));
847e80d4af0SHarald Freudenberger 		break;
848e80d4af0SHarald Freudenberger 	}
849e80d4af0SHarald Freudenberger 	case PKEY_FINDCARD: {
850e80d4af0SHarald Freudenberger 		struct pkey_findcard __user *ufc = (void __user *) arg;
851e80d4af0SHarald Freudenberger 		struct pkey_findcard kfc;
852e80d4af0SHarald Freudenberger 
853e80d4af0SHarald Freudenberger 		if (copy_from_user(&kfc, ufc, sizeof(kfc)))
854e80d4af0SHarald Freudenberger 			return -EFAULT;
855efc598e6SHarald Freudenberger 		rc = cca_findcard(kfc.seckey.seckey,
856e80d4af0SHarald Freudenberger 				  &kfc.cardnr, &kfc.domain, 1);
857efc598e6SHarald Freudenberger 		DEBUG_DBG("%s cca_findcard()=%d\n", __func__, rc);
858efc598e6SHarald Freudenberger 		if (rc < 0)
859e80d4af0SHarald Freudenberger 			break;
860e80d4af0SHarald Freudenberger 		if (copy_to_user(ufc, &kfc, sizeof(kfc)))
861e80d4af0SHarald Freudenberger 			return -EFAULT;
862e80d4af0SHarald Freudenberger 		break;
863e80d4af0SHarald Freudenberger 	}
864e80d4af0SHarald Freudenberger 	case PKEY_SKEY2PKEY: {
865e80d4af0SHarald Freudenberger 		struct pkey_skey2pkey __user *usp = (void __user *) arg;
866e80d4af0SHarald Freudenberger 		struct pkey_skey2pkey ksp;
867e80d4af0SHarald Freudenberger 
868e80d4af0SHarald Freudenberger 		if (copy_from_user(&ksp, usp, sizeof(ksp)))
869e80d4af0SHarald Freudenberger 			return -EFAULT;
870f2bbc96eSHarald Freudenberger 		rc = pkey_skey2pkey(ksp.seckey.seckey, &ksp.protkey);
871ac2b96f3SHarald Freudenberger 		DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc);
872e80d4af0SHarald Freudenberger 		if (rc)
873e80d4af0SHarald Freudenberger 			break;
874e80d4af0SHarald Freudenberger 		if (copy_to_user(usp, &ksp, sizeof(ksp)))
875e80d4af0SHarald Freudenberger 			return -EFAULT;
876e80d4af0SHarald Freudenberger 		break;
877e80d4af0SHarald Freudenberger 	}
878e61a6134SHarald Freudenberger 	case PKEY_VERIFYKEY: {
879e61a6134SHarald Freudenberger 		struct pkey_verifykey __user *uvk = (void __user *) arg;
880e61a6134SHarald Freudenberger 		struct pkey_verifykey kvk;
881e61a6134SHarald Freudenberger 
882e61a6134SHarald Freudenberger 		if (copy_from_user(&kvk, uvk, sizeof(kvk)))
883e61a6134SHarald Freudenberger 			return -EFAULT;
884e61a6134SHarald Freudenberger 		rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain,
885e61a6134SHarald Freudenberger 				    &kvk.keysize, &kvk.attributes);
886ac2b96f3SHarald Freudenberger 		DEBUG_DBG("%s pkey_verifykey()=%d\n", __func__, rc);
887e61a6134SHarald Freudenberger 		if (rc)
888e61a6134SHarald Freudenberger 			break;
889e61a6134SHarald Freudenberger 		if (copy_to_user(uvk, &kvk, sizeof(kvk)))
890e61a6134SHarald Freudenberger 			return -EFAULT;
891e61a6134SHarald Freudenberger 		break;
892e61a6134SHarald Freudenberger 	}
893a45a5c7dSIngo Franzki 	case PKEY_GENPROTK: {
894a45a5c7dSIngo Franzki 		struct pkey_genprotk __user *ugp = (void __user *) arg;
895a45a5c7dSIngo Franzki 		struct pkey_genprotk kgp;
896a45a5c7dSIngo Franzki 
897a45a5c7dSIngo Franzki 		if (copy_from_user(&kgp, ugp, sizeof(kgp)))
898a45a5c7dSIngo Franzki 			return -EFAULT;
899a45a5c7dSIngo Franzki 		rc = pkey_genprotkey(kgp.keytype, &kgp.protkey);
900a45a5c7dSIngo Franzki 		DEBUG_DBG("%s pkey_genprotkey()=%d\n", __func__, rc);
901a45a5c7dSIngo Franzki 		if (rc)
902a45a5c7dSIngo Franzki 			break;
903a45a5c7dSIngo Franzki 		if (copy_to_user(ugp, &kgp, sizeof(kgp)))
904a45a5c7dSIngo Franzki 			return -EFAULT;
905a45a5c7dSIngo Franzki 		break;
906a45a5c7dSIngo Franzki 	}
907cb26b9ffSIngo Franzki 	case PKEY_VERIFYPROTK: {
908cb26b9ffSIngo Franzki 		struct pkey_verifyprotk __user *uvp = (void __user *) arg;
909cb26b9ffSIngo Franzki 		struct pkey_verifyprotk kvp;
910cb26b9ffSIngo Franzki 
911cb26b9ffSIngo Franzki 		if (copy_from_user(&kvp, uvp, sizeof(kvp)))
912cb26b9ffSIngo Franzki 			return -EFAULT;
913cb26b9ffSIngo Franzki 		rc = pkey_verifyprotkey(&kvp.protkey);
914cb26b9ffSIngo Franzki 		DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc);
915cb26b9ffSIngo Franzki 		break;
916cb26b9ffSIngo Franzki 	}
917fb1136d6SIngo Franzki 	case PKEY_KBLOB2PROTK: {
918fb1136d6SIngo Franzki 		struct pkey_kblob2pkey __user *utp = (void __user *) arg;
919fb1136d6SIngo Franzki 		struct pkey_kblob2pkey ktp;
920183cb469SHarald Freudenberger 		u8 *kkey;
921fb1136d6SIngo Franzki 
922fb1136d6SIngo Franzki 		if (copy_from_user(&ktp, utp, sizeof(ktp)))
923fb1136d6SIngo Franzki 			return -EFAULT;
924f2bbc96eSHarald Freudenberger 		kkey = _copy_key_from_user(ktp.key, ktp.keylen);
925f2bbc96eSHarald Freudenberger 		if (IS_ERR(kkey))
926f2bbc96eSHarald Freudenberger 			return PTR_ERR(kkey);
927fb1136d6SIngo Franzki 		rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey);
928fb1136d6SIngo Franzki 		DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
929fb1136d6SIngo Franzki 		kfree(kkey);
930fb1136d6SIngo Franzki 		if (rc)
931fb1136d6SIngo Franzki 			break;
932fb1136d6SIngo Franzki 		if (copy_to_user(utp, &ktp, sizeof(ktp)))
933fb1136d6SIngo Franzki 			return -EFAULT;
934fb1136d6SIngo Franzki 		break;
935fb1136d6SIngo Franzki 	}
936f2bbc96eSHarald Freudenberger 	case PKEY_GENSECK2: {
937f2bbc96eSHarald Freudenberger 		struct pkey_genseck2 __user *ugs = (void __user *) arg;
938f2bbc96eSHarald Freudenberger 		struct pkey_genseck2 kgs;
939f2bbc96eSHarald Freudenberger 		struct pkey_apqn *apqns;
940f2bbc96eSHarald Freudenberger 		size_t klen = KEYBLOBBUFSIZE;
941f2bbc96eSHarald Freudenberger 		u8 *kkey;
942f2bbc96eSHarald Freudenberger 
943f2bbc96eSHarald Freudenberger 		if (copy_from_user(&kgs, ugs, sizeof(kgs)))
944f2bbc96eSHarald Freudenberger 			return -EFAULT;
945f2bbc96eSHarald Freudenberger 		apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries);
946f2bbc96eSHarald Freudenberger 		if (IS_ERR(apqns))
947f2bbc96eSHarald Freudenberger 			return PTR_ERR(apqns);
948f2bbc96eSHarald Freudenberger 		kkey = kmalloc(klen, GFP_KERNEL);
949f2bbc96eSHarald Freudenberger 		if (!kkey) {
950f2bbc96eSHarald Freudenberger 			kfree(apqns);
951f2bbc96eSHarald Freudenberger 			return -ENOMEM;
952f2bbc96eSHarald Freudenberger 		}
953f2bbc96eSHarald Freudenberger 		rc = pkey_genseckey2(apqns, kgs.apqn_entries,
954f2bbc96eSHarald Freudenberger 				     kgs.type, kgs.size, kgs.keygenflags,
955f2bbc96eSHarald Freudenberger 				     kkey, &klen);
956f2bbc96eSHarald Freudenberger 		DEBUG_DBG("%s pkey_genseckey2()=%d\n", __func__, rc);
957f2bbc96eSHarald Freudenberger 		kfree(apqns);
958f2bbc96eSHarald Freudenberger 		if (rc) {
959f2bbc96eSHarald Freudenberger 			kfree(kkey);
960f2bbc96eSHarald Freudenberger 			break;
961f2bbc96eSHarald Freudenberger 		}
962f2bbc96eSHarald Freudenberger 		if (kgs.key) {
963f2bbc96eSHarald Freudenberger 			if (kgs.keylen < klen) {
964f2bbc96eSHarald Freudenberger 				kfree(kkey);
965f2bbc96eSHarald Freudenberger 				return -EINVAL;
966f2bbc96eSHarald Freudenberger 			}
967f2bbc96eSHarald Freudenberger 			if (copy_to_user(kgs.key, kkey, klen)) {
968f2bbc96eSHarald Freudenberger 				kfree(kkey);
969f2bbc96eSHarald Freudenberger 				return -EFAULT;
970f2bbc96eSHarald Freudenberger 			}
971f2bbc96eSHarald Freudenberger 		}
972f2bbc96eSHarald Freudenberger 		kgs.keylen = klen;
973f2bbc96eSHarald Freudenberger 		if (copy_to_user(ugs, &kgs, sizeof(kgs)))
974f2bbc96eSHarald Freudenberger 			rc = -EFAULT;
975f2bbc96eSHarald Freudenberger 		kfree(kkey);
976f2bbc96eSHarald Freudenberger 		break;
977f2bbc96eSHarald Freudenberger 	}
978f2bbc96eSHarald Freudenberger 	case PKEY_CLR2SECK2: {
979f2bbc96eSHarald Freudenberger 		struct pkey_clr2seck2 __user *ucs = (void __user *) arg;
980f2bbc96eSHarald Freudenberger 		struct pkey_clr2seck2 kcs;
981f2bbc96eSHarald Freudenberger 		struct pkey_apqn *apqns;
982f2bbc96eSHarald Freudenberger 		size_t klen = KEYBLOBBUFSIZE;
983f2bbc96eSHarald Freudenberger 		u8 *kkey;
984f2bbc96eSHarald Freudenberger 
985f2bbc96eSHarald Freudenberger 		if (copy_from_user(&kcs, ucs, sizeof(kcs)))
986f2bbc96eSHarald Freudenberger 			return -EFAULT;
987f2bbc96eSHarald Freudenberger 		apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries);
988f2bbc96eSHarald Freudenberger 		if (IS_ERR(apqns))
989f2bbc96eSHarald Freudenberger 			return PTR_ERR(apqns);
990f2bbc96eSHarald Freudenberger 		kkey = kmalloc(klen, GFP_KERNEL);
991f2bbc96eSHarald Freudenberger 		if (!kkey) {
992f2bbc96eSHarald Freudenberger 			kfree(apqns);
993f2bbc96eSHarald Freudenberger 			return -ENOMEM;
994f2bbc96eSHarald Freudenberger 		}
995f2bbc96eSHarald Freudenberger 		rc = pkey_clr2seckey2(apqns, kcs.apqn_entries,
996f2bbc96eSHarald Freudenberger 				      kcs.type, kcs.size, kcs.keygenflags,
997f2bbc96eSHarald Freudenberger 				      kcs.clrkey.clrkey, kkey, &klen);
998f2bbc96eSHarald Freudenberger 		DEBUG_DBG("%s pkey_clr2seckey2()=%d\n", __func__, rc);
999f2bbc96eSHarald Freudenberger 		kfree(apqns);
1000f2bbc96eSHarald Freudenberger 		if (rc) {
1001f2bbc96eSHarald Freudenberger 			kfree(kkey);
1002f2bbc96eSHarald Freudenberger 			break;
1003f2bbc96eSHarald Freudenberger 		}
1004f2bbc96eSHarald Freudenberger 		if (kcs.key) {
1005f2bbc96eSHarald Freudenberger 			if (kcs.keylen < klen) {
1006f2bbc96eSHarald Freudenberger 				kfree(kkey);
1007f2bbc96eSHarald Freudenberger 				return -EINVAL;
1008f2bbc96eSHarald Freudenberger 			}
1009f2bbc96eSHarald Freudenberger 			if (copy_to_user(kcs.key, kkey, klen)) {
1010f2bbc96eSHarald Freudenberger 				kfree(kkey);
1011f2bbc96eSHarald Freudenberger 				return -EFAULT;
1012f2bbc96eSHarald Freudenberger 			}
1013f2bbc96eSHarald Freudenberger 		}
1014f2bbc96eSHarald Freudenberger 		kcs.keylen = klen;
1015f2bbc96eSHarald Freudenberger 		if (copy_to_user(ucs, &kcs, sizeof(kcs)))
1016f2bbc96eSHarald Freudenberger 			rc = -EFAULT;
1017f2bbc96eSHarald Freudenberger 		memzero_explicit(&kcs, sizeof(kcs));
1018f2bbc96eSHarald Freudenberger 		kfree(kkey);
1019f2bbc96eSHarald Freudenberger 		break;
1020f2bbc96eSHarald Freudenberger 	}
1021f2bbc96eSHarald Freudenberger 	case PKEY_VERIFYKEY2: {
1022f2bbc96eSHarald Freudenberger 		struct pkey_verifykey2 __user *uvk = (void __user *) arg;
1023f2bbc96eSHarald Freudenberger 		struct pkey_verifykey2 kvk;
1024f2bbc96eSHarald Freudenberger 		u8 *kkey;
1025f2bbc96eSHarald Freudenberger 
1026f2bbc96eSHarald Freudenberger 		if (copy_from_user(&kvk, uvk, sizeof(kvk)))
1027f2bbc96eSHarald Freudenberger 			return -EFAULT;
1028f2bbc96eSHarald Freudenberger 		kkey = _copy_key_from_user(kvk.key, kvk.keylen);
1029f2bbc96eSHarald Freudenberger 		if (IS_ERR(kkey))
1030f2bbc96eSHarald Freudenberger 			return PTR_ERR(kkey);
1031f2bbc96eSHarald Freudenberger 		rc = pkey_verifykey2(kkey, kvk.keylen,
1032f2bbc96eSHarald Freudenberger 				     &kvk.cardnr, &kvk.domain,
1033f2bbc96eSHarald Freudenberger 				     &kvk.type, &kvk.size, &kvk.flags);
1034f2bbc96eSHarald Freudenberger 		DEBUG_DBG("%s pkey_verifykey2()=%d\n", __func__, rc);
1035f2bbc96eSHarald Freudenberger 		kfree(kkey);
1036f2bbc96eSHarald Freudenberger 		if (rc)
1037f2bbc96eSHarald Freudenberger 			break;
1038f2bbc96eSHarald Freudenberger 		if (copy_to_user(uvk, &kvk, sizeof(kvk)))
1039f2bbc96eSHarald Freudenberger 			return -EFAULT;
1040f2bbc96eSHarald Freudenberger 		break;
1041f2bbc96eSHarald Freudenberger 	}
1042f2bbc96eSHarald Freudenberger 	case PKEY_KBLOB2PROTK2: {
1043f2bbc96eSHarald Freudenberger 		struct pkey_kblob2pkey2 __user *utp = (void __user *) arg;
1044f2bbc96eSHarald Freudenberger 		struct pkey_kblob2pkey2 ktp;
1045f2bbc96eSHarald Freudenberger 		struct pkey_apqn *apqns = NULL;
1046f2bbc96eSHarald Freudenberger 		u8 *kkey;
1047f2bbc96eSHarald Freudenberger 
1048f2bbc96eSHarald Freudenberger 		if (copy_from_user(&ktp, utp, sizeof(ktp)))
1049f2bbc96eSHarald Freudenberger 			return -EFAULT;
1050f2bbc96eSHarald Freudenberger 		apqns = _copy_apqns_from_user(ktp.apqns, ktp.apqn_entries);
1051f2bbc96eSHarald Freudenberger 		if (IS_ERR(apqns))
1052f2bbc96eSHarald Freudenberger 			return PTR_ERR(apqns);
1053f2bbc96eSHarald Freudenberger 		kkey = _copy_key_from_user(ktp.key, ktp.keylen);
1054f2bbc96eSHarald Freudenberger 		if (IS_ERR(kkey)) {
1055f2bbc96eSHarald Freudenberger 			kfree(apqns);
1056f2bbc96eSHarald Freudenberger 			return PTR_ERR(kkey);
1057f2bbc96eSHarald Freudenberger 		}
1058f2bbc96eSHarald Freudenberger 		rc = pkey_keyblob2pkey2(apqns, ktp.apqn_entries,
1059f2bbc96eSHarald Freudenberger 					kkey, ktp.keylen, &ktp.protkey);
1060f2bbc96eSHarald Freudenberger 		DEBUG_DBG("%s pkey_keyblob2pkey2()=%d\n", __func__, rc);
1061f2bbc96eSHarald Freudenberger 		kfree(apqns);
1062f2bbc96eSHarald Freudenberger 		kfree(kkey);
1063f2bbc96eSHarald Freudenberger 		if (rc)
1064f2bbc96eSHarald Freudenberger 			break;
1065f2bbc96eSHarald Freudenberger 		if (copy_to_user(utp, &ktp, sizeof(ktp)))
1066f2bbc96eSHarald Freudenberger 			return -EFAULT;
1067f2bbc96eSHarald Freudenberger 		break;
1068f2bbc96eSHarald Freudenberger 	}
1069f2bbc96eSHarald Freudenberger 	case PKEY_APQNS4K: {
1070f2bbc96eSHarald Freudenberger 		struct pkey_apqns4key __user *uak = (void __user *) arg;
1071f2bbc96eSHarald Freudenberger 		struct pkey_apqns4key kak;
1072f2bbc96eSHarald Freudenberger 		struct pkey_apqn *apqns = NULL;
1073f2bbc96eSHarald Freudenberger 		size_t nr_apqns, len;
1074f2bbc96eSHarald Freudenberger 		u8 *kkey;
1075f2bbc96eSHarald Freudenberger 
1076f2bbc96eSHarald Freudenberger 		if (copy_from_user(&kak, uak, sizeof(kak)))
1077f2bbc96eSHarald Freudenberger 			return -EFAULT;
1078f2bbc96eSHarald Freudenberger 		nr_apqns = kak.apqn_entries;
1079f2bbc96eSHarald Freudenberger 		if (nr_apqns) {
1080f2bbc96eSHarald Freudenberger 			apqns = kmalloc_array(nr_apqns,
1081f2bbc96eSHarald Freudenberger 					      sizeof(struct pkey_apqn),
1082f2bbc96eSHarald Freudenberger 					      GFP_KERNEL);
1083f2bbc96eSHarald Freudenberger 			if (!apqns)
1084f2bbc96eSHarald Freudenberger 				return -ENOMEM;
1085f2bbc96eSHarald Freudenberger 		}
1086f2bbc96eSHarald Freudenberger 		kkey = _copy_key_from_user(kak.key, kak.keylen);
1087f2bbc96eSHarald Freudenberger 		if (IS_ERR(kkey)) {
1088f2bbc96eSHarald Freudenberger 			kfree(apqns);
1089f2bbc96eSHarald Freudenberger 			return PTR_ERR(kkey);
1090f2bbc96eSHarald Freudenberger 		}
1091f2bbc96eSHarald Freudenberger 		rc = pkey_apqns4key(kkey, kak.keylen, kak.flags,
1092f2bbc96eSHarald Freudenberger 				    apqns, &nr_apqns);
1093f2bbc96eSHarald Freudenberger 		DEBUG_DBG("%s pkey_apqns4key()=%d\n", __func__, rc);
1094f2bbc96eSHarald Freudenberger 		kfree(kkey);
1095f2bbc96eSHarald Freudenberger 		if (rc && rc != -ENOSPC) {
1096f2bbc96eSHarald Freudenberger 			kfree(apqns);
1097f2bbc96eSHarald Freudenberger 			break;
1098f2bbc96eSHarald Freudenberger 		}
1099f2bbc96eSHarald Freudenberger 		if (!rc && kak.apqns) {
1100f2bbc96eSHarald Freudenberger 			if (nr_apqns > kak.apqn_entries) {
1101f2bbc96eSHarald Freudenberger 				kfree(apqns);
1102f2bbc96eSHarald Freudenberger 				return -EINVAL;
1103f2bbc96eSHarald Freudenberger 			}
1104f2bbc96eSHarald Freudenberger 			len = nr_apqns * sizeof(struct pkey_apqn);
1105f2bbc96eSHarald Freudenberger 			if (len) {
1106f2bbc96eSHarald Freudenberger 				if (copy_to_user(kak.apqns, apqns, len)) {
1107f2bbc96eSHarald Freudenberger 					kfree(apqns);
1108f2bbc96eSHarald Freudenberger 					return -EFAULT;
1109f2bbc96eSHarald Freudenberger 				}
1110f2bbc96eSHarald Freudenberger 			}
1111f2bbc96eSHarald Freudenberger 		}
1112f2bbc96eSHarald Freudenberger 		kak.apqn_entries = nr_apqns;
1113f2bbc96eSHarald Freudenberger 		if (copy_to_user(uak, &kak, sizeof(kak)))
1114f2bbc96eSHarald Freudenberger 			rc = -EFAULT;
1115f2bbc96eSHarald Freudenberger 		kfree(apqns);
1116f2bbc96eSHarald Freudenberger 		break;
1117f2bbc96eSHarald Freudenberger 	}
1118f2bbc96eSHarald Freudenberger 	case PKEY_APQNS4KT: {
1119f2bbc96eSHarald Freudenberger 		struct pkey_apqns4keytype __user *uat = (void __user *) arg;
1120f2bbc96eSHarald Freudenberger 		struct pkey_apqns4keytype kat;
1121f2bbc96eSHarald Freudenberger 		struct pkey_apqn *apqns = NULL;
1122f2bbc96eSHarald Freudenberger 		size_t nr_apqns, len;
1123f2bbc96eSHarald Freudenberger 
1124f2bbc96eSHarald Freudenberger 		if (copy_from_user(&kat, uat, sizeof(kat)))
1125f2bbc96eSHarald Freudenberger 			return -EFAULT;
1126f2bbc96eSHarald Freudenberger 		nr_apqns = kat.apqn_entries;
1127f2bbc96eSHarald Freudenberger 		if (nr_apqns) {
1128f2bbc96eSHarald Freudenberger 			apqns = kmalloc_array(nr_apqns,
1129f2bbc96eSHarald Freudenberger 					      sizeof(struct pkey_apqn),
1130f2bbc96eSHarald Freudenberger 					      GFP_KERNEL);
1131f2bbc96eSHarald Freudenberger 			if (!apqns)
1132f2bbc96eSHarald Freudenberger 				return -ENOMEM;
1133f2bbc96eSHarald Freudenberger 		}
1134f2bbc96eSHarald Freudenberger 		rc = pkey_apqns4keytype(kat.type, kat.cur_mkvp, kat.alt_mkvp,
1135f2bbc96eSHarald Freudenberger 					kat.flags, apqns, &nr_apqns);
1136f2bbc96eSHarald Freudenberger 		DEBUG_DBG("%s pkey_apqns4keytype()=%d\n", __func__, rc);
1137f2bbc96eSHarald Freudenberger 		if (rc && rc != -ENOSPC) {
1138f2bbc96eSHarald Freudenberger 			kfree(apqns);
1139f2bbc96eSHarald Freudenberger 			break;
1140f2bbc96eSHarald Freudenberger 		}
1141f2bbc96eSHarald Freudenberger 		if (!rc && kat.apqns) {
1142f2bbc96eSHarald Freudenberger 			if (nr_apqns > kat.apqn_entries) {
1143f2bbc96eSHarald Freudenberger 				kfree(apqns);
1144f2bbc96eSHarald Freudenberger 				return -EINVAL;
1145f2bbc96eSHarald Freudenberger 			}
1146f2bbc96eSHarald Freudenberger 			len = nr_apqns * sizeof(struct pkey_apqn);
1147f2bbc96eSHarald Freudenberger 			if (len) {
1148f2bbc96eSHarald Freudenberger 				if (copy_to_user(kat.apqns, apqns, len)) {
1149f2bbc96eSHarald Freudenberger 					kfree(apqns);
1150f2bbc96eSHarald Freudenberger 					return -EFAULT;
1151f2bbc96eSHarald Freudenberger 				}
1152f2bbc96eSHarald Freudenberger 			}
1153f2bbc96eSHarald Freudenberger 		}
1154f2bbc96eSHarald Freudenberger 		kat.apqn_entries = nr_apqns;
1155f2bbc96eSHarald Freudenberger 		if (copy_to_user(uat, &kat, sizeof(kat)))
1156f2bbc96eSHarald Freudenberger 			rc = -EFAULT;
1157f2bbc96eSHarald Freudenberger 		kfree(apqns);
1158f2bbc96eSHarald Freudenberger 		break;
1159f2bbc96eSHarald Freudenberger 	}
1160e80d4af0SHarald Freudenberger 	default:
1161e80d4af0SHarald Freudenberger 		/* unknown/unsupported ioctl cmd */
1162e80d4af0SHarald Freudenberger 		return -ENOTTY;
1163e80d4af0SHarald Freudenberger 	}
1164e80d4af0SHarald Freudenberger 
1165e80d4af0SHarald Freudenberger 	return rc;
1166e80d4af0SHarald Freudenberger }
1167e80d4af0SHarald Freudenberger 
1168e80d4af0SHarald Freudenberger /*
1169e80d4af0SHarald Freudenberger  * Sysfs and file io operations
1170e80d4af0SHarald Freudenberger  */
1171d632c047SIngo Franzki 
1172d632c047SIngo Franzki /*
1173d632c047SIngo Franzki  * Sysfs attribute read function for all protected key binary attributes.
1174d632c047SIngo Franzki  * The implementation can not deal with partial reads, because a new random
1175d632c047SIngo Franzki  * protected key blob is generated with each read. In case of partial reads
1176d632c047SIngo Franzki  * (i.e. off != 0 or count < key blob size) -EINVAL is returned.
1177d632c047SIngo Franzki  */
1178d632c047SIngo Franzki static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf,
1179d632c047SIngo Franzki 					  loff_t off, size_t count)
1180d632c047SIngo Franzki {
1181d632c047SIngo Franzki 	struct protaeskeytoken protkeytoken;
1182d632c047SIngo Franzki 	struct pkey_protkey protkey;
1183d632c047SIngo Franzki 	int rc;
1184d632c047SIngo Franzki 
1185d632c047SIngo Franzki 	if (off != 0 || count < sizeof(protkeytoken))
1186d632c047SIngo Franzki 		return -EINVAL;
1187d632c047SIngo Franzki 	if (is_xts)
1188d632c047SIngo Franzki 		if (count < 2 * sizeof(protkeytoken))
1189d632c047SIngo Franzki 			return -EINVAL;
1190d632c047SIngo Franzki 
1191d632c047SIngo Franzki 	memset(&protkeytoken, 0, sizeof(protkeytoken));
1192d632c047SIngo Franzki 	protkeytoken.type = TOKTYPE_NON_CCA;
1193d632c047SIngo Franzki 	protkeytoken.version = TOKVER_PROTECTED_KEY;
1194d632c047SIngo Franzki 	protkeytoken.keytype = keytype;
1195d632c047SIngo Franzki 
1196d632c047SIngo Franzki 	rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
1197d632c047SIngo Franzki 	if (rc)
1198d632c047SIngo Franzki 		return rc;
1199d632c047SIngo Franzki 
1200d632c047SIngo Franzki 	protkeytoken.len = protkey.len;
1201d632c047SIngo Franzki 	memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
1202d632c047SIngo Franzki 
1203d632c047SIngo Franzki 	memcpy(buf, &protkeytoken, sizeof(protkeytoken));
1204d632c047SIngo Franzki 
1205d632c047SIngo Franzki 	if (is_xts) {
1206d632c047SIngo Franzki 		rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
1207d632c047SIngo Franzki 		if (rc)
1208d632c047SIngo Franzki 			return rc;
1209d632c047SIngo Franzki 
1210d632c047SIngo Franzki 		protkeytoken.len = protkey.len;
1211d632c047SIngo Franzki 		memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
1212d632c047SIngo Franzki 
1213d632c047SIngo Franzki 		memcpy(buf + sizeof(protkeytoken), &protkeytoken,
1214d632c047SIngo Franzki 		       sizeof(protkeytoken));
1215d632c047SIngo Franzki 
1216d632c047SIngo Franzki 		return 2 * sizeof(protkeytoken);
1217d632c047SIngo Franzki 	}
1218d632c047SIngo Franzki 
1219d632c047SIngo Franzki 	return sizeof(protkeytoken);
1220d632c047SIngo Franzki }
1221d632c047SIngo Franzki 
1222d632c047SIngo Franzki static ssize_t protkey_aes_128_read(struct file *filp,
1223d632c047SIngo Franzki 				    struct kobject *kobj,
1224d632c047SIngo Franzki 				    struct bin_attribute *attr,
1225d632c047SIngo Franzki 				    char *buf, loff_t off,
1226d632c047SIngo Franzki 				    size_t count)
1227d632c047SIngo Franzki {
1228d632c047SIngo Franzki 	return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
1229d632c047SIngo Franzki 					  off, count);
1230d632c047SIngo Franzki }
1231d632c047SIngo Franzki 
1232d632c047SIngo Franzki static ssize_t protkey_aes_192_read(struct file *filp,
1233d632c047SIngo Franzki 				    struct kobject *kobj,
1234d632c047SIngo Franzki 				    struct bin_attribute *attr,
1235d632c047SIngo Franzki 				    char *buf, loff_t off,
1236d632c047SIngo Franzki 				    size_t count)
1237d632c047SIngo Franzki {
1238d632c047SIngo Franzki 	return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
1239d632c047SIngo Franzki 					  off, count);
1240d632c047SIngo Franzki }
1241d632c047SIngo Franzki 
1242d632c047SIngo Franzki static ssize_t protkey_aes_256_read(struct file *filp,
1243d632c047SIngo Franzki 				    struct kobject *kobj,
1244d632c047SIngo Franzki 				    struct bin_attribute *attr,
1245d632c047SIngo Franzki 				    char *buf, loff_t off,
1246d632c047SIngo Franzki 				    size_t count)
1247d632c047SIngo Franzki {
1248d632c047SIngo Franzki 	return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
1249d632c047SIngo Franzki 					  off, count);
1250d632c047SIngo Franzki }
1251d632c047SIngo Franzki 
1252d632c047SIngo Franzki static ssize_t protkey_aes_128_xts_read(struct file *filp,
1253d632c047SIngo Franzki 					struct kobject *kobj,
1254d632c047SIngo Franzki 					struct bin_attribute *attr,
1255d632c047SIngo Franzki 					char *buf, loff_t off,
1256d632c047SIngo Franzki 					size_t count)
1257d632c047SIngo Franzki {
1258d632c047SIngo Franzki 	return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
1259d632c047SIngo Franzki 					  off, count);
1260d632c047SIngo Franzki }
1261d632c047SIngo Franzki 
1262d632c047SIngo Franzki static ssize_t protkey_aes_256_xts_read(struct file *filp,
1263d632c047SIngo Franzki 					struct kobject *kobj,
1264d632c047SIngo Franzki 					struct bin_attribute *attr,
1265d632c047SIngo Franzki 					char *buf, loff_t off,
1266d632c047SIngo Franzki 					size_t count)
1267d632c047SIngo Franzki {
1268d632c047SIngo Franzki 	return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
1269d632c047SIngo Franzki 					  off, count);
1270d632c047SIngo Franzki }
1271d632c047SIngo Franzki 
1272d632c047SIngo Franzki static BIN_ATTR_RO(protkey_aes_128, sizeof(struct protaeskeytoken));
1273d632c047SIngo Franzki static BIN_ATTR_RO(protkey_aes_192, sizeof(struct protaeskeytoken));
1274d632c047SIngo Franzki static BIN_ATTR_RO(protkey_aes_256, sizeof(struct protaeskeytoken));
1275d632c047SIngo Franzki static BIN_ATTR_RO(protkey_aes_128_xts, 2 * sizeof(struct protaeskeytoken));
1276d632c047SIngo Franzki static BIN_ATTR_RO(protkey_aes_256_xts, 2 * sizeof(struct protaeskeytoken));
1277d632c047SIngo Franzki 
1278d632c047SIngo Franzki static struct bin_attribute *protkey_attrs[] = {
1279d632c047SIngo Franzki 	&bin_attr_protkey_aes_128,
1280d632c047SIngo Franzki 	&bin_attr_protkey_aes_192,
1281d632c047SIngo Franzki 	&bin_attr_protkey_aes_256,
1282d632c047SIngo Franzki 	&bin_attr_protkey_aes_128_xts,
1283d632c047SIngo Franzki 	&bin_attr_protkey_aes_256_xts,
1284d632c047SIngo Franzki 	NULL
1285d632c047SIngo Franzki };
1286d632c047SIngo Franzki 
1287d632c047SIngo Franzki static struct attribute_group protkey_attr_group = {
1288d632c047SIngo Franzki 	.name	   = "protkey",
1289d632c047SIngo Franzki 	.bin_attrs = protkey_attrs,
1290d632c047SIngo Franzki };
1291d632c047SIngo Franzki 
1292af504452SIngo Franzki /*
1293af504452SIngo Franzki  * Sysfs attribute read function for all secure key ccadata binary attributes.
1294af504452SIngo Franzki  * The implementation can not deal with partial reads, because a new random
1295af504452SIngo Franzki  * protected key blob is generated with each read. In case of partial reads
1296af504452SIngo Franzki  * (i.e. off != 0 or count < key blob size) -EINVAL is returned.
1297af504452SIngo Franzki  */
1298af504452SIngo Franzki static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf,
1299af504452SIngo Franzki 					  loff_t off, size_t count)
1300af504452SIngo Franzki {
1301af504452SIngo Franzki 	int rc;
1302efc598e6SHarald Freudenberger 	struct pkey_seckey *seckey = (struct pkey_seckey *) buf;
1303af504452SIngo Franzki 
1304af504452SIngo Franzki 	if (off != 0 || count < sizeof(struct secaeskeytoken))
1305af504452SIngo Franzki 		return -EINVAL;
1306af504452SIngo Franzki 	if (is_xts)
1307af504452SIngo Franzki 		if (count < 2 * sizeof(struct secaeskeytoken))
1308af504452SIngo Franzki 			return -EINVAL;
1309af504452SIngo Franzki 
1310efc598e6SHarald Freudenberger 	rc = cca_genseckey(-1, -1, keytype, seckey->seckey);
1311af504452SIngo Franzki 	if (rc)
1312af504452SIngo Franzki 		return rc;
1313af504452SIngo Franzki 
1314af504452SIngo Franzki 	if (is_xts) {
1315efc598e6SHarald Freudenberger 		seckey++;
1316efc598e6SHarald Freudenberger 		rc = cca_genseckey(-1, -1, keytype, seckey->seckey);
1317af504452SIngo Franzki 		if (rc)
1318af504452SIngo Franzki 			return rc;
1319af504452SIngo Franzki 
1320af504452SIngo Franzki 		return 2 * sizeof(struct secaeskeytoken);
1321af504452SIngo Franzki 	}
1322af504452SIngo Franzki 
1323af504452SIngo Franzki 	return sizeof(struct secaeskeytoken);
1324af504452SIngo Franzki }
1325af504452SIngo Franzki 
1326af504452SIngo Franzki static ssize_t ccadata_aes_128_read(struct file *filp,
1327af504452SIngo Franzki 				    struct kobject *kobj,
1328af504452SIngo Franzki 				    struct bin_attribute *attr,
1329af504452SIngo Franzki 				    char *buf, loff_t off,
1330af504452SIngo Franzki 				    size_t count)
1331af504452SIngo Franzki {
1332af504452SIngo Franzki 	return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
1333af504452SIngo Franzki 					  off, count);
1334af504452SIngo Franzki }
1335af504452SIngo Franzki 
1336af504452SIngo Franzki static ssize_t ccadata_aes_192_read(struct file *filp,
1337af504452SIngo Franzki 				    struct kobject *kobj,
1338af504452SIngo Franzki 				    struct bin_attribute *attr,
1339af504452SIngo Franzki 				    char *buf, loff_t off,
1340af504452SIngo Franzki 				    size_t count)
1341af504452SIngo Franzki {
1342af504452SIngo Franzki 	return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
1343af504452SIngo Franzki 					  off, count);
1344af504452SIngo Franzki }
1345af504452SIngo Franzki 
1346af504452SIngo Franzki static ssize_t ccadata_aes_256_read(struct file *filp,
1347af504452SIngo Franzki 				    struct kobject *kobj,
1348af504452SIngo Franzki 				    struct bin_attribute *attr,
1349af504452SIngo Franzki 				    char *buf, loff_t off,
1350af504452SIngo Franzki 				    size_t count)
1351af504452SIngo Franzki {
1352af504452SIngo Franzki 	return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
1353af504452SIngo Franzki 					  off, count);
1354af504452SIngo Franzki }
1355af504452SIngo Franzki 
1356af504452SIngo Franzki static ssize_t ccadata_aes_128_xts_read(struct file *filp,
1357af504452SIngo Franzki 					struct kobject *kobj,
1358af504452SIngo Franzki 					struct bin_attribute *attr,
1359af504452SIngo Franzki 					char *buf, loff_t off,
1360af504452SIngo Franzki 					size_t count)
1361af504452SIngo Franzki {
1362af504452SIngo Franzki 	return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
1363af504452SIngo Franzki 					  off, count);
1364af504452SIngo Franzki }
1365af504452SIngo Franzki 
1366af504452SIngo Franzki static ssize_t ccadata_aes_256_xts_read(struct file *filp,
1367af504452SIngo Franzki 					struct kobject *kobj,
1368af504452SIngo Franzki 					struct bin_attribute *attr,
1369af504452SIngo Franzki 					char *buf, loff_t off,
1370af504452SIngo Franzki 					size_t count)
1371af504452SIngo Franzki {
1372af504452SIngo Franzki 	return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
1373af504452SIngo Franzki 					  off, count);
1374af504452SIngo Franzki }
1375af504452SIngo Franzki 
1376af504452SIngo Franzki static BIN_ATTR_RO(ccadata_aes_128, sizeof(struct secaeskeytoken));
1377af504452SIngo Franzki static BIN_ATTR_RO(ccadata_aes_192, sizeof(struct secaeskeytoken));
1378af504452SIngo Franzki static BIN_ATTR_RO(ccadata_aes_256, sizeof(struct secaeskeytoken));
1379af504452SIngo Franzki static BIN_ATTR_RO(ccadata_aes_128_xts, 2 * sizeof(struct secaeskeytoken));
1380af504452SIngo Franzki static BIN_ATTR_RO(ccadata_aes_256_xts, 2 * sizeof(struct secaeskeytoken));
1381af504452SIngo Franzki 
1382af504452SIngo Franzki static struct bin_attribute *ccadata_attrs[] = {
1383af504452SIngo Franzki 	&bin_attr_ccadata_aes_128,
1384af504452SIngo Franzki 	&bin_attr_ccadata_aes_192,
1385af504452SIngo Franzki 	&bin_attr_ccadata_aes_256,
1386af504452SIngo Franzki 	&bin_attr_ccadata_aes_128_xts,
1387af504452SIngo Franzki 	&bin_attr_ccadata_aes_256_xts,
1388af504452SIngo Franzki 	NULL
1389af504452SIngo Franzki };
1390af504452SIngo Franzki 
1391af504452SIngo Franzki static struct attribute_group ccadata_attr_group = {
1392af504452SIngo Franzki 	.name	   = "ccadata",
1393af504452SIngo Franzki 	.bin_attrs = ccadata_attrs,
1394af504452SIngo Franzki };
1395af504452SIngo Franzki 
1396f71fee27SIngo Franzki #define CCACIPHERTOKENSIZE	(sizeof(struct cipherkeytoken) + 80)
1397f71fee27SIngo Franzki 
1398f71fee27SIngo Franzki /*
1399f71fee27SIngo Franzki  * Sysfs attribute read function for all secure key ccacipher binary attributes.
1400f71fee27SIngo Franzki  * The implementation can not deal with partial reads, because a new random
1401f71fee27SIngo Franzki  * secure key blob is generated with each read. In case of partial reads
1402f71fee27SIngo Franzki  * (i.e. off != 0 or count < key blob size) -EINVAL is returned.
1403f71fee27SIngo Franzki  */
1404f71fee27SIngo Franzki static ssize_t pkey_ccacipher_aes_attr_read(enum pkey_key_size keybits,
1405f71fee27SIngo Franzki 					    bool is_xts, char *buf, loff_t off,
1406f71fee27SIngo Franzki 					    size_t count)
1407f71fee27SIngo Franzki {
1408f71fee27SIngo Franzki 	size_t keysize;
1409f71fee27SIngo Franzki 	int rc;
1410f71fee27SIngo Franzki 
1411f71fee27SIngo Franzki 	if (off != 0 || count < CCACIPHERTOKENSIZE)
1412f71fee27SIngo Franzki 		return -EINVAL;
1413f71fee27SIngo Franzki 	if (is_xts)
1414f71fee27SIngo Franzki 		if (count < 2 * CCACIPHERTOKENSIZE)
1415f71fee27SIngo Franzki 			return -EINVAL;
1416f71fee27SIngo Franzki 
1417f71fee27SIngo Franzki 	keysize = CCACIPHERTOKENSIZE;
1418f71fee27SIngo Franzki 	rc = cca_gencipherkey(-1, -1, keybits, 0, buf, &keysize);
1419f71fee27SIngo Franzki 	if (rc)
1420f71fee27SIngo Franzki 		return rc;
1421f71fee27SIngo Franzki 	memset(buf + keysize, 0, CCACIPHERTOKENSIZE - keysize);
1422f71fee27SIngo Franzki 
1423f71fee27SIngo Franzki 	if (is_xts) {
1424f71fee27SIngo Franzki 		keysize = CCACIPHERTOKENSIZE;
1425f71fee27SIngo Franzki 		rc = cca_gencipherkey(-1, -1, keybits, 0,
1426f71fee27SIngo Franzki 				      buf + CCACIPHERTOKENSIZE, &keysize);
1427f71fee27SIngo Franzki 		if (rc)
1428f71fee27SIngo Franzki 			return rc;
1429f71fee27SIngo Franzki 		memset(buf + CCACIPHERTOKENSIZE + keysize, 0,
1430f71fee27SIngo Franzki 		       CCACIPHERTOKENSIZE - keysize);
1431f71fee27SIngo Franzki 
1432f71fee27SIngo Franzki 		return 2 * CCACIPHERTOKENSIZE;
1433f71fee27SIngo Franzki 	}
1434f71fee27SIngo Franzki 
1435f71fee27SIngo Franzki 	return CCACIPHERTOKENSIZE;
1436f71fee27SIngo Franzki }
1437f71fee27SIngo Franzki 
1438f71fee27SIngo Franzki static ssize_t ccacipher_aes_128_read(struct file *filp,
1439f71fee27SIngo Franzki 				      struct kobject *kobj,
1440f71fee27SIngo Franzki 				      struct bin_attribute *attr,
1441f71fee27SIngo Franzki 				      char *buf, loff_t off,
1442f71fee27SIngo Franzki 				      size_t count)
1443f71fee27SIngo Franzki {
1444f71fee27SIngo Franzki 	return pkey_ccacipher_aes_attr_read(PKEY_SIZE_AES_128, false, buf,
1445f71fee27SIngo Franzki 					    off, count);
1446f71fee27SIngo Franzki }
1447f71fee27SIngo Franzki 
1448f71fee27SIngo Franzki static ssize_t ccacipher_aes_192_read(struct file *filp,
1449f71fee27SIngo Franzki 				      struct kobject *kobj,
1450f71fee27SIngo Franzki 				      struct bin_attribute *attr,
1451f71fee27SIngo Franzki 				      char *buf, loff_t off,
1452f71fee27SIngo Franzki 				      size_t count)
1453f71fee27SIngo Franzki {
1454f71fee27SIngo Franzki 	return pkey_ccacipher_aes_attr_read(PKEY_SIZE_AES_192, false, buf,
1455f71fee27SIngo Franzki 					    off, count);
1456f71fee27SIngo Franzki }
1457f71fee27SIngo Franzki 
1458f71fee27SIngo Franzki static ssize_t ccacipher_aes_256_read(struct file *filp,
1459f71fee27SIngo Franzki 				      struct kobject *kobj,
1460f71fee27SIngo Franzki 				      struct bin_attribute *attr,
1461f71fee27SIngo Franzki 				      char *buf, loff_t off,
1462f71fee27SIngo Franzki 				      size_t count)
1463f71fee27SIngo Franzki {
1464f71fee27SIngo Franzki 	return pkey_ccacipher_aes_attr_read(PKEY_SIZE_AES_256, false, buf,
1465f71fee27SIngo Franzki 					    off, count);
1466f71fee27SIngo Franzki }
1467f71fee27SIngo Franzki 
1468f71fee27SIngo Franzki static ssize_t ccacipher_aes_128_xts_read(struct file *filp,
1469f71fee27SIngo Franzki 					  struct kobject *kobj,
1470f71fee27SIngo Franzki 					  struct bin_attribute *attr,
1471f71fee27SIngo Franzki 					  char *buf, loff_t off,
1472f71fee27SIngo Franzki 					  size_t count)
1473f71fee27SIngo Franzki {
1474f71fee27SIngo Franzki 	return pkey_ccacipher_aes_attr_read(PKEY_SIZE_AES_128, true, buf,
1475f71fee27SIngo Franzki 					    off, count);
1476f71fee27SIngo Franzki }
1477f71fee27SIngo Franzki 
1478f71fee27SIngo Franzki static ssize_t ccacipher_aes_256_xts_read(struct file *filp,
1479f71fee27SIngo Franzki 					  struct kobject *kobj,
1480f71fee27SIngo Franzki 					  struct bin_attribute *attr,
1481f71fee27SIngo Franzki 					  char *buf, loff_t off,
1482f71fee27SIngo Franzki 					  size_t count)
1483f71fee27SIngo Franzki {
1484f71fee27SIngo Franzki 	return pkey_ccacipher_aes_attr_read(PKEY_SIZE_AES_256, true, buf,
1485f71fee27SIngo Franzki 					    off, count);
1486f71fee27SIngo Franzki }
1487f71fee27SIngo Franzki 
1488f71fee27SIngo Franzki static BIN_ATTR_RO(ccacipher_aes_128, CCACIPHERTOKENSIZE);
1489f71fee27SIngo Franzki static BIN_ATTR_RO(ccacipher_aes_192, CCACIPHERTOKENSIZE);
1490f71fee27SIngo Franzki static BIN_ATTR_RO(ccacipher_aes_256, CCACIPHERTOKENSIZE);
1491f71fee27SIngo Franzki static BIN_ATTR_RO(ccacipher_aes_128_xts, 2 * CCACIPHERTOKENSIZE);
1492f71fee27SIngo Franzki static BIN_ATTR_RO(ccacipher_aes_256_xts, 2 * CCACIPHERTOKENSIZE);
1493f71fee27SIngo Franzki 
1494f71fee27SIngo Franzki static struct bin_attribute *ccacipher_attrs[] = {
1495f71fee27SIngo Franzki 	&bin_attr_ccacipher_aes_128,
1496f71fee27SIngo Franzki 	&bin_attr_ccacipher_aes_192,
1497f71fee27SIngo Franzki 	&bin_attr_ccacipher_aes_256,
1498f71fee27SIngo Franzki 	&bin_attr_ccacipher_aes_128_xts,
1499f71fee27SIngo Franzki 	&bin_attr_ccacipher_aes_256_xts,
1500f71fee27SIngo Franzki 	NULL
1501f71fee27SIngo Franzki };
1502f71fee27SIngo Franzki 
1503f71fee27SIngo Franzki static struct attribute_group ccacipher_attr_group = {
1504f71fee27SIngo Franzki 	.name	   = "ccacipher",
1505f71fee27SIngo Franzki 	.bin_attrs = ccacipher_attrs,
1506f71fee27SIngo Franzki };
1507f71fee27SIngo Franzki 
1508d632c047SIngo Franzki static const struct attribute_group *pkey_attr_groups[] = {
1509d632c047SIngo Franzki 	&protkey_attr_group,
1510af504452SIngo Franzki 	&ccadata_attr_group,
1511f71fee27SIngo Franzki 	&ccacipher_attr_group,
1512d632c047SIngo Franzki 	NULL,
1513d632c047SIngo Franzki };
1514d632c047SIngo Franzki 
1515e80d4af0SHarald Freudenberger static const struct file_operations pkey_fops = {
1516e80d4af0SHarald Freudenberger 	.owner		= THIS_MODULE,
1517e80d4af0SHarald Freudenberger 	.open		= nonseekable_open,
1518e80d4af0SHarald Freudenberger 	.llseek		= no_llseek,
1519e80d4af0SHarald Freudenberger 	.unlocked_ioctl = pkey_unlocked_ioctl,
1520e80d4af0SHarald Freudenberger };
1521e80d4af0SHarald Freudenberger 
1522e80d4af0SHarald Freudenberger static struct miscdevice pkey_dev = {
1523e80d4af0SHarald Freudenberger 	.name	= "pkey",
1524e80d4af0SHarald Freudenberger 	.minor	= MISC_DYNAMIC_MINOR,
1525e80d4af0SHarald Freudenberger 	.mode	= 0666,
1526e80d4af0SHarald Freudenberger 	.fops	= &pkey_fops,
1527d632c047SIngo Franzki 	.groups = pkey_attr_groups,
1528e80d4af0SHarald Freudenberger };
1529e80d4af0SHarald Freudenberger 
1530e80d4af0SHarald Freudenberger /*
1531e80d4af0SHarald Freudenberger  * Module init
1532e80d4af0SHarald Freudenberger  */
1533cb4ef3c2SHeiko Carstens static int __init pkey_init(void)
1534e80d4af0SHarald Freudenberger {
1535f822ad2cSHarald Freudenberger 	cpacf_mask_t kmc_functions;
1536e80d4af0SHarald Freudenberger 
1537f822ad2cSHarald Freudenberger 	/*
1538f822ad2cSHarald Freudenberger 	 * The pckmo instruction should be available - even if we don't
1539f822ad2cSHarald Freudenberger 	 * actually invoke it. This instruction comes with MSA 3 which
1540f822ad2cSHarald Freudenberger 	 * is also the minimum level for the kmc instructions which
1541f822ad2cSHarald Freudenberger 	 * are able to work with protected keys.
1542f822ad2cSHarald Freudenberger 	 */
1543e80d4af0SHarald Freudenberger 	if (!cpacf_query(CPACF_PCKMO, &pckmo_functions))
154458443b67SDavid Hildenbrand 		return -ENODEV;
1545e80d4af0SHarald Freudenberger 
1546cb26b9ffSIngo Franzki 	/* check for kmc instructions available */
1547cb26b9ffSIngo Franzki 	if (!cpacf_query(CPACF_KMC, &kmc_functions))
154858443b67SDavid Hildenbrand 		return -ENODEV;
1549cb26b9ffSIngo Franzki 	if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
1550cb26b9ffSIngo Franzki 	    !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
1551cb26b9ffSIngo Franzki 	    !cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256))
155258443b67SDavid Hildenbrand 		return -ENODEV;
1553cb26b9ffSIngo Franzki 
1554e80d4af0SHarald Freudenberger 	pkey_debug_init();
1555e80d4af0SHarald Freudenberger 
1556e80d4af0SHarald Freudenberger 	return misc_register(&pkey_dev);
1557e80d4af0SHarald Freudenberger }
1558e80d4af0SHarald Freudenberger 
1559e80d4af0SHarald Freudenberger /*
1560e80d4af0SHarald Freudenberger  * Module exit
1561e80d4af0SHarald Freudenberger  */
1562e80d4af0SHarald Freudenberger static void __exit pkey_exit(void)
1563e80d4af0SHarald Freudenberger {
1564e80d4af0SHarald Freudenberger 	misc_deregister(&pkey_dev);
1565e80d4af0SHarald Freudenberger 	pkey_debug_exit();
1566e80d4af0SHarald Freudenberger }
1567e80d4af0SHarald Freudenberger 
156863c19be0SIngo Franzki module_cpu_feature_match(MSA, pkey_init);
1569e80d4af0SHarald Freudenberger module_exit(pkey_exit);
1570