xref: /openbmc/linux/drivers/s390/crypto/pkey_api.c (revision e80d4af0a320972aac58e2004d0ba4e44ef4c5c7)
1*e80d4af0SHarald Freudenberger /*
2*e80d4af0SHarald Freudenberger  *  pkey device driver
3*e80d4af0SHarald Freudenberger  *
4*e80d4af0SHarald Freudenberger  *  Copyright IBM Corp. 2017
5*e80d4af0SHarald Freudenberger  *  Author(s): Harald Freudenberger
6*e80d4af0SHarald Freudenberger  *
7*e80d4af0SHarald Freudenberger  * This program is free software; you can redistribute it and/or modify
8*e80d4af0SHarald Freudenberger  * it under the terms of the GNU General Public License (version 2 only)
9*e80d4af0SHarald Freudenberger  * as published by the Free Software Foundation.
10*e80d4af0SHarald Freudenberger  *
11*e80d4af0SHarald Freudenberger  */
12*e80d4af0SHarald Freudenberger 
13*e80d4af0SHarald Freudenberger #define KMSG_COMPONENT "pkey"
14*e80d4af0SHarald Freudenberger #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
15*e80d4af0SHarald Freudenberger 
16*e80d4af0SHarald Freudenberger #include <linux/fs.h>
17*e80d4af0SHarald Freudenberger #include <linux/init.h>
18*e80d4af0SHarald Freudenberger #include <linux/miscdevice.h>
19*e80d4af0SHarald Freudenberger #include <linux/module.h>
20*e80d4af0SHarald Freudenberger #include <linux/slab.h>
21*e80d4af0SHarald Freudenberger #include <linux/kallsyms.h>
22*e80d4af0SHarald Freudenberger #include <linux/debugfs.h>
23*e80d4af0SHarald Freudenberger #include <asm/zcrypt.h>
24*e80d4af0SHarald Freudenberger #include <asm/cpacf.h>
25*e80d4af0SHarald Freudenberger #include <asm/pkey.h>
26*e80d4af0SHarald Freudenberger 
27*e80d4af0SHarald Freudenberger #include "zcrypt_api.h"
28*e80d4af0SHarald Freudenberger 
29*e80d4af0SHarald Freudenberger MODULE_LICENSE("GPL");
30*e80d4af0SHarald Freudenberger MODULE_AUTHOR("IBM Corporation");
31*e80d4af0SHarald Freudenberger MODULE_DESCRIPTION("s390 protected key interface");
32*e80d4af0SHarald Freudenberger 
33*e80d4af0SHarald Freudenberger /* Size of parameter block used for all cca requests/replies */
34*e80d4af0SHarald Freudenberger #define PARMBSIZE 512
35*e80d4af0SHarald Freudenberger 
36*e80d4af0SHarald Freudenberger /* Size of vardata block used for some of the cca requests/replies */
37*e80d4af0SHarald Freudenberger #define VARDATASIZE 4096
38*e80d4af0SHarald Freudenberger 
39*e80d4af0SHarald Freudenberger /*
40*e80d4af0SHarald Freudenberger  * debug feature data and functions
41*e80d4af0SHarald Freudenberger  */
42*e80d4af0SHarald Freudenberger 
43*e80d4af0SHarald Freudenberger static debug_info_t *debug_info;
44*e80d4af0SHarald Freudenberger 
45*e80d4af0SHarald Freudenberger #define DEBUG_DBG(...)	debug_sprintf_event(debug_info, 6, ##__VA_ARGS__)
46*e80d4af0SHarald Freudenberger #define DEBUG_INFO(...) debug_sprintf_event(debug_info, 5, ##__VA_ARGS__)
47*e80d4af0SHarald Freudenberger #define DEBUG_WARN(...) debug_sprintf_event(debug_info, 4, ##__VA_ARGS__)
48*e80d4af0SHarald Freudenberger #define DEBUG_ERR(...)	debug_sprintf_event(debug_info, 3, ##__VA_ARGS__)
49*e80d4af0SHarald Freudenberger 
50*e80d4af0SHarald Freudenberger static void __init pkey_debug_init(void)
51*e80d4af0SHarald Freudenberger {
52*e80d4af0SHarald Freudenberger 	debug_info = debug_register("pkey", 1, 1, 4 * sizeof(long));
53*e80d4af0SHarald Freudenberger 	debug_register_view(debug_info, &debug_sprintf_view);
54*e80d4af0SHarald Freudenberger 	debug_set_level(debug_info, 3);
55*e80d4af0SHarald Freudenberger }
56*e80d4af0SHarald Freudenberger 
57*e80d4af0SHarald Freudenberger static void __exit pkey_debug_exit(void)
58*e80d4af0SHarald Freudenberger {
59*e80d4af0SHarald Freudenberger 	debug_unregister(debug_info);
60*e80d4af0SHarald Freudenberger }
61*e80d4af0SHarald Freudenberger 
62*e80d4af0SHarald Freudenberger /* inside view of a secure key token (only type 0x01 version 0x04) */
63*e80d4af0SHarald Freudenberger struct secaeskeytoken {
64*e80d4af0SHarald Freudenberger 	u8  type;     /* 0x01 for internal key token */
65*e80d4af0SHarald Freudenberger 	u8  res0[3];
66*e80d4af0SHarald Freudenberger 	u8  version;  /* should be 0x04 */
67*e80d4af0SHarald Freudenberger 	u8  res1[1];
68*e80d4af0SHarald Freudenberger 	u8  flag;     /* key flags */
69*e80d4af0SHarald Freudenberger 	u8  res2[1];
70*e80d4af0SHarald Freudenberger 	u64 mkvp;     /* master key verification pattern */
71*e80d4af0SHarald Freudenberger 	u8  key[32];  /* key value (encrypted) */
72*e80d4af0SHarald Freudenberger 	u8  cv[8];    /* control vector */
73*e80d4af0SHarald Freudenberger 	u16 bitsize;  /* key bit size */
74*e80d4af0SHarald Freudenberger 	u16 keysize;  /* key byte size */
75*e80d4af0SHarald Freudenberger 	u8  tvv[4];   /* token validation value */
76*e80d4af0SHarald Freudenberger } __packed;
77*e80d4af0SHarald Freudenberger 
78*e80d4af0SHarald Freudenberger /*
79*e80d4af0SHarald Freudenberger  * Simple check if the token is a valid CCA secure AES key
80*e80d4af0SHarald Freudenberger  * token. If keybitsize is given, the bitsize of the key is
81*e80d4af0SHarald Freudenberger  * also checked. Returns 0 on success or errno value on failure.
82*e80d4af0SHarald Freudenberger  */
83*e80d4af0SHarald Freudenberger static int check_secaeskeytoken(u8 *token, int keybitsize)
84*e80d4af0SHarald Freudenberger {
85*e80d4af0SHarald Freudenberger 	struct secaeskeytoken *t = (struct secaeskeytoken *) token;
86*e80d4af0SHarald Freudenberger 
87*e80d4af0SHarald Freudenberger 	if (t->type != 0x01) {
88*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
89*e80d4af0SHarald Freudenberger 			"check_secaeskeytoken secure token check failed, type mismatch 0x%02x != 0x01\n",
90*e80d4af0SHarald Freudenberger 			(int) t->type);
91*e80d4af0SHarald Freudenberger 		return -EINVAL;
92*e80d4af0SHarald Freudenberger 	}
93*e80d4af0SHarald Freudenberger 	if (t->version != 0x04) {
94*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
95*e80d4af0SHarald Freudenberger 			"check_secaeskeytoken secure token check failed, version mismatch 0x%02x != 0x04\n",
96*e80d4af0SHarald Freudenberger 			(int) t->version);
97*e80d4af0SHarald Freudenberger 		return -EINVAL;
98*e80d4af0SHarald Freudenberger 	}
99*e80d4af0SHarald Freudenberger 	if (keybitsize > 0 && t->bitsize != keybitsize) {
100*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
101*e80d4af0SHarald Freudenberger 			"check_secaeskeytoken secure token check failed, bitsize mismatch %d != %d\n",
102*e80d4af0SHarald Freudenberger 			(int) t->bitsize, keybitsize);
103*e80d4af0SHarald Freudenberger 		return -EINVAL;
104*e80d4af0SHarald Freudenberger 	}
105*e80d4af0SHarald Freudenberger 
106*e80d4af0SHarald Freudenberger 	return 0;
107*e80d4af0SHarald Freudenberger }
108*e80d4af0SHarald Freudenberger 
109*e80d4af0SHarald Freudenberger /*
110*e80d4af0SHarald Freudenberger  * Allocate consecutive memory for request CPRB, request param
111*e80d4af0SHarald Freudenberger  * block, reply CPRB and reply param block and fill in values
112*e80d4af0SHarald Freudenberger  * for the common fields. Returns 0 on success or errno value
113*e80d4af0SHarald Freudenberger  * on failure.
114*e80d4af0SHarald Freudenberger  */
115*e80d4af0SHarald Freudenberger static int alloc_and_prep_cprbmem(size_t paramblen,
116*e80d4af0SHarald Freudenberger 				  u8 **pcprbmem,
117*e80d4af0SHarald Freudenberger 				  struct CPRBX **preqCPRB,
118*e80d4af0SHarald Freudenberger 				  struct CPRBX **prepCPRB)
119*e80d4af0SHarald Freudenberger {
120*e80d4af0SHarald Freudenberger 	u8 *cprbmem;
121*e80d4af0SHarald Freudenberger 	size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen;
122*e80d4af0SHarald Freudenberger 	struct CPRBX *preqcblk, *prepcblk;
123*e80d4af0SHarald Freudenberger 
124*e80d4af0SHarald Freudenberger 	/*
125*e80d4af0SHarald Freudenberger 	 * allocate consecutive memory for request CPRB, request param
126*e80d4af0SHarald Freudenberger 	 * block, reply CPRB and reply param block
127*e80d4af0SHarald Freudenberger 	 */
128*e80d4af0SHarald Freudenberger 	cprbmem = kmalloc(2 * cprbplusparamblen, GFP_KERNEL);
129*e80d4af0SHarald Freudenberger 	if (!cprbmem)
130*e80d4af0SHarald Freudenberger 		return -ENOMEM;
131*e80d4af0SHarald Freudenberger 	memset(cprbmem, 0, 2 * cprbplusparamblen);
132*e80d4af0SHarald Freudenberger 
133*e80d4af0SHarald Freudenberger 	preqcblk = (struct CPRBX *) cprbmem;
134*e80d4af0SHarald Freudenberger 	prepcblk = (struct CPRBX *) (cprbmem + cprbplusparamblen);
135*e80d4af0SHarald Freudenberger 
136*e80d4af0SHarald Freudenberger 	/* fill request cprb struct */
137*e80d4af0SHarald Freudenberger 	preqcblk->cprb_len = sizeof(struct CPRBX);
138*e80d4af0SHarald Freudenberger 	preqcblk->cprb_ver_id = 0x02;
139*e80d4af0SHarald Freudenberger 	memcpy(preqcblk->func_id, "T2", 2);
140*e80d4af0SHarald Freudenberger 	preqcblk->rpl_msgbl = cprbplusparamblen;
141*e80d4af0SHarald Freudenberger 	if (paramblen) {
142*e80d4af0SHarald Freudenberger 		preqcblk->req_parmb =
143*e80d4af0SHarald Freudenberger 			((u8 *) preqcblk) + sizeof(struct CPRBX);
144*e80d4af0SHarald Freudenberger 		preqcblk->rpl_parmb =
145*e80d4af0SHarald Freudenberger 			((u8 *) prepcblk) + sizeof(struct CPRBX);
146*e80d4af0SHarald Freudenberger 	}
147*e80d4af0SHarald Freudenberger 
148*e80d4af0SHarald Freudenberger 	*pcprbmem = cprbmem;
149*e80d4af0SHarald Freudenberger 	*preqCPRB = preqcblk;
150*e80d4af0SHarald Freudenberger 	*prepCPRB = prepcblk;
151*e80d4af0SHarald Freudenberger 
152*e80d4af0SHarald Freudenberger 	return 0;
153*e80d4af0SHarald Freudenberger }
154*e80d4af0SHarald Freudenberger 
155*e80d4af0SHarald Freudenberger /*
156*e80d4af0SHarald Freudenberger  * Free the cprb memory allocated with the function above.
157*e80d4af0SHarald Freudenberger  * If the scrub value is not zero, the memory is filled
158*e80d4af0SHarald Freudenberger  * with zeros before freeing (useful if there was some
159*e80d4af0SHarald Freudenberger  * clear key material in there).
160*e80d4af0SHarald Freudenberger  */
161*e80d4af0SHarald Freudenberger static void free_cprbmem(void *mem, size_t paramblen, int scrub)
162*e80d4af0SHarald Freudenberger {
163*e80d4af0SHarald Freudenberger 	if (scrub)
164*e80d4af0SHarald Freudenberger 		memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen));
165*e80d4af0SHarald Freudenberger 	kfree(mem);
166*e80d4af0SHarald Freudenberger }
167*e80d4af0SHarald Freudenberger 
168*e80d4af0SHarald Freudenberger /*
169*e80d4af0SHarald Freudenberger  * Helper function to prepare the xcrb struct
170*e80d4af0SHarald Freudenberger  */
171*e80d4af0SHarald Freudenberger static inline void prep_xcrb(struct ica_xcRB *pxcrb,
172*e80d4af0SHarald Freudenberger 			     u16 cardnr,
173*e80d4af0SHarald Freudenberger 			     struct CPRBX *preqcblk,
174*e80d4af0SHarald Freudenberger 			     struct CPRBX *prepcblk)
175*e80d4af0SHarald Freudenberger {
176*e80d4af0SHarald Freudenberger 	memset(pxcrb, 0, sizeof(*pxcrb));
177*e80d4af0SHarald Freudenberger 	pxcrb->agent_ID = 0x4341; /* 'CA' */
178*e80d4af0SHarald Freudenberger 	pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr);
179*e80d4af0SHarald Freudenberger 	pxcrb->request_control_blk_length =
180*e80d4af0SHarald Freudenberger 		preqcblk->cprb_len + preqcblk->req_parml;
181*e80d4af0SHarald Freudenberger 	pxcrb->request_control_blk_addr = (void *) preqcblk;
182*e80d4af0SHarald Freudenberger 	pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl;
183*e80d4af0SHarald Freudenberger 	pxcrb->reply_control_blk_addr = (void *) prepcblk;
184*e80d4af0SHarald Freudenberger }
185*e80d4af0SHarald Freudenberger 
186*e80d4af0SHarald Freudenberger /*
187*e80d4af0SHarald Freudenberger  * Helper function which calls zcrypt_send_cprb with
188*e80d4af0SHarald Freudenberger  * memory management segment adjusted to kernel space
189*e80d4af0SHarald Freudenberger  * so that the copy_from_user called within this
190*e80d4af0SHarald Freudenberger  * function do in fact copy from kernel space.
191*e80d4af0SHarald Freudenberger  */
192*e80d4af0SHarald Freudenberger static inline int _zcrypt_send_cprb(struct ica_xcRB *xcrb)
193*e80d4af0SHarald Freudenberger {
194*e80d4af0SHarald Freudenberger 	int rc;
195*e80d4af0SHarald Freudenberger 	mm_segment_t old_fs = get_fs();
196*e80d4af0SHarald Freudenberger 
197*e80d4af0SHarald Freudenberger 	set_fs(KERNEL_DS);
198*e80d4af0SHarald Freudenberger 	rc = zcrypt_send_cprb(xcrb);
199*e80d4af0SHarald Freudenberger 	set_fs(old_fs);
200*e80d4af0SHarald Freudenberger 
201*e80d4af0SHarald Freudenberger 	return rc;
202*e80d4af0SHarald Freudenberger }
203*e80d4af0SHarald Freudenberger 
204*e80d4af0SHarald Freudenberger /*
205*e80d4af0SHarald Freudenberger  * Generate (random) AES secure key.
206*e80d4af0SHarald Freudenberger  */
207*e80d4af0SHarald Freudenberger int pkey_genseckey(u16 cardnr, u16 domain,
208*e80d4af0SHarald Freudenberger 		   u32 keytype, struct pkey_seckey *seckey)
209*e80d4af0SHarald Freudenberger {
210*e80d4af0SHarald Freudenberger 	int i, rc, keysize;
211*e80d4af0SHarald Freudenberger 	int seckeysize;
212*e80d4af0SHarald Freudenberger 	u8 *mem;
213*e80d4af0SHarald Freudenberger 	struct CPRBX *preqcblk, *prepcblk;
214*e80d4af0SHarald Freudenberger 	struct ica_xcRB xcrb;
215*e80d4af0SHarald Freudenberger 	struct kgreqparm {
216*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
217*e80d4af0SHarald Freudenberger 		u16 rule_array_len;
218*e80d4af0SHarald Freudenberger 		struct lv1 {
219*e80d4af0SHarald Freudenberger 			u16 len;
220*e80d4af0SHarald Freudenberger 			char  key_form[8];
221*e80d4af0SHarald Freudenberger 			char  key_length[8];
222*e80d4af0SHarald Freudenberger 			char  key_type1[8];
223*e80d4af0SHarald Freudenberger 			char  key_type2[8];
224*e80d4af0SHarald Freudenberger 		} lv1;
225*e80d4af0SHarald Freudenberger 		struct lv2 {
226*e80d4af0SHarald Freudenberger 			u16 len;
227*e80d4af0SHarald Freudenberger 			struct keyid {
228*e80d4af0SHarald Freudenberger 				u16 len;
229*e80d4af0SHarald Freudenberger 				u16 attr;
230*e80d4af0SHarald Freudenberger 				u8  data[SECKEYBLOBSIZE];
231*e80d4af0SHarald Freudenberger 			} keyid[6];
232*e80d4af0SHarald Freudenberger 		} lv2;
233*e80d4af0SHarald Freudenberger 	} *preqparm;
234*e80d4af0SHarald Freudenberger 	struct kgrepparm {
235*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
236*e80d4af0SHarald Freudenberger 		u16 rule_array_len;
237*e80d4af0SHarald Freudenberger 		struct lv3 {
238*e80d4af0SHarald Freudenberger 			u16 len;
239*e80d4af0SHarald Freudenberger 			u16 keyblocklen;
240*e80d4af0SHarald Freudenberger 			struct {
241*e80d4af0SHarald Freudenberger 				u16 toklen;
242*e80d4af0SHarald Freudenberger 				u16 tokattr;
243*e80d4af0SHarald Freudenberger 				u8  tok[0];
244*e80d4af0SHarald Freudenberger 				/* ... some more data ... */
245*e80d4af0SHarald Freudenberger 			} keyblock;
246*e80d4af0SHarald Freudenberger 		} lv3;
247*e80d4af0SHarald Freudenberger 	} *prepparm;
248*e80d4af0SHarald Freudenberger 
249*e80d4af0SHarald Freudenberger 	/* get already prepared memory for 2 cprbs with param block each */
250*e80d4af0SHarald Freudenberger 	rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
251*e80d4af0SHarald Freudenberger 	if (rc)
252*e80d4af0SHarald Freudenberger 		return rc;
253*e80d4af0SHarald Freudenberger 
254*e80d4af0SHarald Freudenberger 	/* fill request cprb struct */
255*e80d4af0SHarald Freudenberger 	preqcblk->domain = domain;
256*e80d4af0SHarald Freudenberger 
257*e80d4af0SHarald Freudenberger 	/* fill request cprb param block with KG request */
258*e80d4af0SHarald Freudenberger 	preqparm = (struct kgreqparm *) preqcblk->req_parmb;
259*e80d4af0SHarald Freudenberger 	memcpy(preqparm->subfunc_code, "KG", 2);
260*e80d4af0SHarald Freudenberger 	preqparm->rule_array_len = sizeof(preqparm->rule_array_len);
261*e80d4af0SHarald Freudenberger 	preqparm->lv1.len = sizeof(struct lv1);
262*e80d4af0SHarald Freudenberger 	memcpy(preqparm->lv1.key_form,	 "OP      ", 8);
263*e80d4af0SHarald Freudenberger 	switch (keytype) {
264*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_128:
265*e80d4af0SHarald Freudenberger 		keysize = 16;
266*e80d4af0SHarald Freudenberger 		memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8);
267*e80d4af0SHarald Freudenberger 		break;
268*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_192:
269*e80d4af0SHarald Freudenberger 		keysize = 24;
270*e80d4af0SHarald Freudenberger 		memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8);
271*e80d4af0SHarald Freudenberger 		break;
272*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_256:
273*e80d4af0SHarald Freudenberger 		keysize = 32;
274*e80d4af0SHarald Freudenberger 		memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8);
275*e80d4af0SHarald Freudenberger 		break;
276*e80d4af0SHarald Freudenberger 	default:
277*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
278*e80d4af0SHarald Freudenberger 			"pkey_genseckey unknown/unsupported keytype %d\n",
279*e80d4af0SHarald Freudenberger 			keytype);
280*e80d4af0SHarald Freudenberger 		rc = -EINVAL;
281*e80d4af0SHarald Freudenberger 		goto out;
282*e80d4af0SHarald Freudenberger 	}
283*e80d4af0SHarald Freudenberger 	memcpy(preqparm->lv1.key_type1,  "AESDATA ", 8);
284*e80d4af0SHarald Freudenberger 	preqparm->lv2.len = sizeof(struct lv2);
285*e80d4af0SHarald Freudenberger 	for (i = 0; i < 6; i++) {
286*e80d4af0SHarald Freudenberger 		preqparm->lv2.keyid[i].len = sizeof(struct keyid);
287*e80d4af0SHarald Freudenberger 		preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10);
288*e80d4af0SHarald Freudenberger 	}
289*e80d4af0SHarald Freudenberger 	preqcblk->req_parml = sizeof(struct kgreqparm);
290*e80d4af0SHarald Freudenberger 
291*e80d4af0SHarald Freudenberger 	/* fill xcrb struct */
292*e80d4af0SHarald Freudenberger 	prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
293*e80d4af0SHarald Freudenberger 
294*e80d4af0SHarald Freudenberger 	/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
295*e80d4af0SHarald Freudenberger 	rc = _zcrypt_send_cprb(&xcrb);
296*e80d4af0SHarald Freudenberger 	if (rc) {
297*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
298*e80d4af0SHarald Freudenberger 			"pkey_genseckey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n",
299*e80d4af0SHarald Freudenberger 			(int) cardnr, (int) domain, rc);
300*e80d4af0SHarald Freudenberger 		goto out;
301*e80d4af0SHarald Freudenberger 	}
302*e80d4af0SHarald Freudenberger 
303*e80d4af0SHarald Freudenberger 	/* check response returncode and reasoncode */
304*e80d4af0SHarald Freudenberger 	if (prepcblk->ccp_rtcode != 0) {
305*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
306*e80d4af0SHarald Freudenberger 			"pkey_genseckey secure key generate failure, card response %d/%d\n",
307*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rtcode,
308*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rscode);
309*e80d4af0SHarald Freudenberger 		rc = -EIO;
310*e80d4af0SHarald Freudenberger 		goto out;
311*e80d4af0SHarald Freudenberger 	}
312*e80d4af0SHarald Freudenberger 
313*e80d4af0SHarald Freudenberger 	/* process response cprb param block */
314*e80d4af0SHarald Freudenberger 	prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX);
315*e80d4af0SHarald Freudenberger 	prepparm = (struct kgrepparm *) prepcblk->rpl_parmb;
316*e80d4af0SHarald Freudenberger 
317*e80d4af0SHarald Freudenberger 	/* check length of the returned secure key token */
318*e80d4af0SHarald Freudenberger 	seckeysize = prepparm->lv3.keyblock.toklen
319*e80d4af0SHarald Freudenberger 		- sizeof(prepparm->lv3.keyblock.toklen)
320*e80d4af0SHarald Freudenberger 		- sizeof(prepparm->lv3.keyblock.tokattr);
321*e80d4af0SHarald Freudenberger 	if (seckeysize != SECKEYBLOBSIZE) {
322*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
323*e80d4af0SHarald Freudenberger 			"pkey_genseckey secure token size mismatch %d != %d bytes\n",
324*e80d4af0SHarald Freudenberger 			seckeysize, SECKEYBLOBSIZE);
325*e80d4af0SHarald Freudenberger 		rc = -EIO;
326*e80d4af0SHarald Freudenberger 		goto out;
327*e80d4af0SHarald Freudenberger 	}
328*e80d4af0SHarald Freudenberger 
329*e80d4af0SHarald Freudenberger 	/* check secure key token */
330*e80d4af0SHarald Freudenberger 	rc = check_secaeskeytoken(prepparm->lv3.keyblock.tok, 8*keysize);
331*e80d4af0SHarald Freudenberger 	if (rc) {
332*e80d4af0SHarald Freudenberger 		rc = -EIO;
333*e80d4af0SHarald Freudenberger 		goto out;
334*e80d4af0SHarald Freudenberger 	}
335*e80d4af0SHarald Freudenberger 
336*e80d4af0SHarald Freudenberger 	/* copy the generated secure key token */
337*e80d4af0SHarald Freudenberger 	memcpy(seckey->seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE);
338*e80d4af0SHarald Freudenberger 
339*e80d4af0SHarald Freudenberger out:
340*e80d4af0SHarald Freudenberger 	free_cprbmem(mem, PARMBSIZE, 0);
341*e80d4af0SHarald Freudenberger 	return rc;
342*e80d4af0SHarald Freudenberger }
343*e80d4af0SHarald Freudenberger EXPORT_SYMBOL(pkey_genseckey);
344*e80d4af0SHarald Freudenberger 
345*e80d4af0SHarald Freudenberger /*
346*e80d4af0SHarald Freudenberger  * Generate an AES secure key with given key value.
347*e80d4af0SHarald Freudenberger  */
348*e80d4af0SHarald Freudenberger int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype,
349*e80d4af0SHarald Freudenberger 		    const struct pkey_clrkey *clrkey,
350*e80d4af0SHarald Freudenberger 		    struct pkey_seckey *seckey)
351*e80d4af0SHarald Freudenberger {
352*e80d4af0SHarald Freudenberger 	int rc, keysize, seckeysize;
353*e80d4af0SHarald Freudenberger 	u8 *mem;
354*e80d4af0SHarald Freudenberger 	struct CPRBX *preqcblk, *prepcblk;
355*e80d4af0SHarald Freudenberger 	struct ica_xcRB xcrb;
356*e80d4af0SHarald Freudenberger 	struct cmreqparm {
357*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
358*e80d4af0SHarald Freudenberger 		u16 rule_array_len;
359*e80d4af0SHarald Freudenberger 		char  rule_array[8];
360*e80d4af0SHarald Freudenberger 		struct lv1 {
361*e80d4af0SHarald Freudenberger 			u16 len;
362*e80d4af0SHarald Freudenberger 			u8  clrkey[0];
363*e80d4af0SHarald Freudenberger 		} lv1;
364*e80d4af0SHarald Freudenberger 		struct lv2 {
365*e80d4af0SHarald Freudenberger 			u16 len;
366*e80d4af0SHarald Freudenberger 			struct keyid {
367*e80d4af0SHarald Freudenberger 				u16 len;
368*e80d4af0SHarald Freudenberger 				u16 attr;
369*e80d4af0SHarald Freudenberger 				u8  data[SECKEYBLOBSIZE];
370*e80d4af0SHarald Freudenberger 			} keyid;
371*e80d4af0SHarald Freudenberger 		} lv2;
372*e80d4af0SHarald Freudenberger 	} *preqparm;
373*e80d4af0SHarald Freudenberger 	struct lv2 *plv2;
374*e80d4af0SHarald Freudenberger 	struct cmrepparm {
375*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
376*e80d4af0SHarald Freudenberger 		u16 rule_array_len;
377*e80d4af0SHarald Freudenberger 		struct lv3 {
378*e80d4af0SHarald Freudenberger 			u16 len;
379*e80d4af0SHarald Freudenberger 			u16 keyblocklen;
380*e80d4af0SHarald Freudenberger 			struct {
381*e80d4af0SHarald Freudenberger 				u16 toklen;
382*e80d4af0SHarald Freudenberger 				u16 tokattr;
383*e80d4af0SHarald Freudenberger 				u8  tok[0];
384*e80d4af0SHarald Freudenberger 				/* ... some more data ... */
385*e80d4af0SHarald Freudenberger 			} keyblock;
386*e80d4af0SHarald Freudenberger 		} lv3;
387*e80d4af0SHarald Freudenberger 	} *prepparm;
388*e80d4af0SHarald Freudenberger 
389*e80d4af0SHarald Freudenberger 	/* get already prepared memory for 2 cprbs with param block each */
390*e80d4af0SHarald Freudenberger 	rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
391*e80d4af0SHarald Freudenberger 	if (rc)
392*e80d4af0SHarald Freudenberger 		return rc;
393*e80d4af0SHarald Freudenberger 
394*e80d4af0SHarald Freudenberger 	/* fill request cprb struct */
395*e80d4af0SHarald Freudenberger 	preqcblk->domain = domain;
396*e80d4af0SHarald Freudenberger 
397*e80d4af0SHarald Freudenberger 	/* fill request cprb param block with CM request */
398*e80d4af0SHarald Freudenberger 	preqparm = (struct cmreqparm *) preqcblk->req_parmb;
399*e80d4af0SHarald Freudenberger 	memcpy(preqparm->subfunc_code, "CM", 2);
400*e80d4af0SHarald Freudenberger 	memcpy(preqparm->rule_array, "AES     ", 8);
401*e80d4af0SHarald Freudenberger 	preqparm->rule_array_len =
402*e80d4af0SHarald Freudenberger 		sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array);
403*e80d4af0SHarald Freudenberger 	switch (keytype) {
404*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_128:
405*e80d4af0SHarald Freudenberger 		keysize = 16;
406*e80d4af0SHarald Freudenberger 		break;
407*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_192:
408*e80d4af0SHarald Freudenberger 		keysize = 24;
409*e80d4af0SHarald Freudenberger 		break;
410*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_256:
411*e80d4af0SHarald Freudenberger 		keysize = 32;
412*e80d4af0SHarald Freudenberger 		break;
413*e80d4af0SHarald Freudenberger 	default:
414*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
415*e80d4af0SHarald Freudenberger 			"pkey_clr2seckey unknown/unsupported keytype %d\n",
416*e80d4af0SHarald Freudenberger 			keytype);
417*e80d4af0SHarald Freudenberger 		rc = -EINVAL;
418*e80d4af0SHarald Freudenberger 		goto out;
419*e80d4af0SHarald Freudenberger 	}
420*e80d4af0SHarald Freudenberger 	preqparm->lv1.len = sizeof(struct lv1) + keysize;
421*e80d4af0SHarald Freudenberger 	memcpy(preqparm->lv1.clrkey, clrkey->clrkey, keysize);
422*e80d4af0SHarald Freudenberger 	plv2 = (struct lv2 *) (((u8 *) &preqparm->lv2) + keysize);
423*e80d4af0SHarald Freudenberger 	plv2->len = sizeof(struct lv2);
424*e80d4af0SHarald Freudenberger 	plv2->keyid.len = sizeof(struct keyid);
425*e80d4af0SHarald Freudenberger 	plv2->keyid.attr = 0x30;
426*e80d4af0SHarald Freudenberger 	preqcblk->req_parml = sizeof(struct cmreqparm) + keysize;
427*e80d4af0SHarald Freudenberger 
428*e80d4af0SHarald Freudenberger 	/* fill xcrb struct */
429*e80d4af0SHarald Freudenberger 	prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
430*e80d4af0SHarald Freudenberger 
431*e80d4af0SHarald Freudenberger 	/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
432*e80d4af0SHarald Freudenberger 	rc = _zcrypt_send_cprb(&xcrb);
433*e80d4af0SHarald Freudenberger 	if (rc) {
434*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
435*e80d4af0SHarald Freudenberger 			"pkey_clr2seckey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n",
436*e80d4af0SHarald Freudenberger 			(int) cardnr, (int) domain, rc);
437*e80d4af0SHarald Freudenberger 		goto out;
438*e80d4af0SHarald Freudenberger 	}
439*e80d4af0SHarald Freudenberger 
440*e80d4af0SHarald Freudenberger 	/* check response returncode and reasoncode */
441*e80d4af0SHarald Freudenberger 	if (prepcblk->ccp_rtcode != 0) {
442*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
443*e80d4af0SHarald Freudenberger 			"pkey_clr2seckey clear key import failure, card response %d/%d\n",
444*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rtcode,
445*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rscode);
446*e80d4af0SHarald Freudenberger 		rc = -EIO;
447*e80d4af0SHarald Freudenberger 		goto out;
448*e80d4af0SHarald Freudenberger 	}
449*e80d4af0SHarald Freudenberger 
450*e80d4af0SHarald Freudenberger 	/* process response cprb param block */
451*e80d4af0SHarald Freudenberger 	prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX);
452*e80d4af0SHarald Freudenberger 	prepparm = (struct cmrepparm *) prepcblk->rpl_parmb;
453*e80d4af0SHarald Freudenberger 
454*e80d4af0SHarald Freudenberger 	/* check length of the returned secure key token */
455*e80d4af0SHarald Freudenberger 	seckeysize = prepparm->lv3.keyblock.toklen
456*e80d4af0SHarald Freudenberger 		- sizeof(prepparm->lv3.keyblock.toklen)
457*e80d4af0SHarald Freudenberger 		- sizeof(prepparm->lv3.keyblock.tokattr);
458*e80d4af0SHarald Freudenberger 	if (seckeysize != SECKEYBLOBSIZE) {
459*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
460*e80d4af0SHarald Freudenberger 			"pkey_clr2seckey secure token size mismatch %d != %d bytes\n",
461*e80d4af0SHarald Freudenberger 			seckeysize, SECKEYBLOBSIZE);
462*e80d4af0SHarald Freudenberger 		rc = -EIO;
463*e80d4af0SHarald Freudenberger 		goto out;
464*e80d4af0SHarald Freudenberger 	}
465*e80d4af0SHarald Freudenberger 
466*e80d4af0SHarald Freudenberger 	/* check secure key token */
467*e80d4af0SHarald Freudenberger 	rc = check_secaeskeytoken(prepparm->lv3.keyblock.tok, 8*keysize);
468*e80d4af0SHarald Freudenberger 	if (rc) {
469*e80d4af0SHarald Freudenberger 		rc = -EIO;
470*e80d4af0SHarald Freudenberger 		goto out;
471*e80d4af0SHarald Freudenberger 	}
472*e80d4af0SHarald Freudenberger 
473*e80d4af0SHarald Freudenberger 	/* copy the generated secure key token */
474*e80d4af0SHarald Freudenberger 	memcpy(seckey->seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE);
475*e80d4af0SHarald Freudenberger 
476*e80d4af0SHarald Freudenberger out:
477*e80d4af0SHarald Freudenberger 	free_cprbmem(mem, PARMBSIZE, 1);
478*e80d4af0SHarald Freudenberger 	return rc;
479*e80d4af0SHarald Freudenberger }
480*e80d4af0SHarald Freudenberger EXPORT_SYMBOL(pkey_clr2seckey);
481*e80d4af0SHarald Freudenberger 
482*e80d4af0SHarald Freudenberger /*
483*e80d4af0SHarald Freudenberger  * Derive a proteced key from the secure key blob.
484*e80d4af0SHarald Freudenberger  */
485*e80d4af0SHarald Freudenberger int pkey_sec2protkey(u16 cardnr, u16 domain,
486*e80d4af0SHarald Freudenberger 		     const struct pkey_seckey *seckey,
487*e80d4af0SHarald Freudenberger 		     struct pkey_protkey *protkey)
488*e80d4af0SHarald Freudenberger {
489*e80d4af0SHarald Freudenberger 	int rc;
490*e80d4af0SHarald Freudenberger 	u8 *mem;
491*e80d4af0SHarald Freudenberger 	struct CPRBX *preqcblk, *prepcblk;
492*e80d4af0SHarald Freudenberger 	struct ica_xcRB xcrb;
493*e80d4af0SHarald Freudenberger 	struct uskreqparm {
494*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
495*e80d4af0SHarald Freudenberger 		u16 rule_array_len;
496*e80d4af0SHarald Freudenberger 		struct lv1 {
497*e80d4af0SHarald Freudenberger 			u16 len;
498*e80d4af0SHarald Freudenberger 			u16 attr_len;
499*e80d4af0SHarald Freudenberger 			u16 attr_flags;
500*e80d4af0SHarald Freudenberger 		} lv1;
501*e80d4af0SHarald Freudenberger 		struct lv2 {
502*e80d4af0SHarald Freudenberger 			u16 len;
503*e80d4af0SHarald Freudenberger 			u16 attr_len;
504*e80d4af0SHarald Freudenberger 			u16 attr_flags;
505*e80d4af0SHarald Freudenberger 			u8  token[0];	      /* cca secure key token */
506*e80d4af0SHarald Freudenberger 		} lv2 __packed;
507*e80d4af0SHarald Freudenberger 	} *preqparm;
508*e80d4af0SHarald Freudenberger 	struct uskrepparm {
509*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
510*e80d4af0SHarald Freudenberger 		u16 rule_array_len;
511*e80d4af0SHarald Freudenberger 		struct lv3 {
512*e80d4af0SHarald Freudenberger 			u16 len;
513*e80d4af0SHarald Freudenberger 			u16 attr_len;
514*e80d4af0SHarald Freudenberger 			u16 attr_flags;
515*e80d4af0SHarald Freudenberger 			struct cpacfkeyblock {
516*e80d4af0SHarald Freudenberger 				u8  version;  /* version of this struct */
517*e80d4af0SHarald Freudenberger 				u8  flags[2];
518*e80d4af0SHarald Freudenberger 				u8  algo;
519*e80d4af0SHarald Freudenberger 				u8  form;
520*e80d4af0SHarald Freudenberger 				u8  pad1[3];
521*e80d4af0SHarald Freudenberger 				u16 keylen;
522*e80d4af0SHarald Freudenberger 				u8  key[64];  /* the key (keylen bytes) */
523*e80d4af0SHarald Freudenberger 				u16 keyattrlen;
524*e80d4af0SHarald Freudenberger 				u8  keyattr[32];
525*e80d4af0SHarald Freudenberger 				u8  pad2[1];
526*e80d4af0SHarald Freudenberger 				u8  vptype;
527*e80d4af0SHarald Freudenberger 				u8  vp[32];  /* verification pattern */
528*e80d4af0SHarald Freudenberger 			} keyblock;
529*e80d4af0SHarald Freudenberger 		} lv3 __packed;
530*e80d4af0SHarald Freudenberger 	} *prepparm;
531*e80d4af0SHarald Freudenberger 
532*e80d4af0SHarald Freudenberger 	/* get already prepared memory for 2 cprbs with param block each */
533*e80d4af0SHarald Freudenberger 	rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
534*e80d4af0SHarald Freudenberger 	if (rc)
535*e80d4af0SHarald Freudenberger 		return rc;
536*e80d4af0SHarald Freudenberger 
537*e80d4af0SHarald Freudenberger 	/* fill request cprb struct */
538*e80d4af0SHarald Freudenberger 	preqcblk->domain = domain;
539*e80d4af0SHarald Freudenberger 
540*e80d4af0SHarald Freudenberger 	/* fill request cprb param block with USK request */
541*e80d4af0SHarald Freudenberger 	preqparm = (struct uskreqparm *) preqcblk->req_parmb;
542*e80d4af0SHarald Freudenberger 	memcpy(preqparm->subfunc_code, "US", 2);
543*e80d4af0SHarald Freudenberger 	preqparm->rule_array_len = sizeof(preqparm->rule_array_len);
544*e80d4af0SHarald Freudenberger 	preqparm->lv1.len = sizeof(struct lv1);
545*e80d4af0SHarald Freudenberger 	preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len);
546*e80d4af0SHarald Freudenberger 	preqparm->lv1.attr_flags = 0x0001;
547*e80d4af0SHarald Freudenberger 	preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE;
548*e80d4af0SHarald Freudenberger 	preqparm->lv2.attr_len = sizeof(struct lv2)
549*e80d4af0SHarald Freudenberger 		- sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE;
550*e80d4af0SHarald Freudenberger 	preqparm->lv2.attr_flags = 0x0000;
551*e80d4af0SHarald Freudenberger 	memcpy(preqparm->lv2.token, seckey->seckey, SECKEYBLOBSIZE);
552*e80d4af0SHarald Freudenberger 	preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE;
553*e80d4af0SHarald Freudenberger 
554*e80d4af0SHarald Freudenberger 	/* fill xcrb struct */
555*e80d4af0SHarald Freudenberger 	prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
556*e80d4af0SHarald Freudenberger 
557*e80d4af0SHarald Freudenberger 	/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
558*e80d4af0SHarald Freudenberger 	rc = _zcrypt_send_cprb(&xcrb);
559*e80d4af0SHarald Freudenberger 	if (rc) {
560*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
561*e80d4af0SHarald Freudenberger 			"pkey_sec2protkey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n",
562*e80d4af0SHarald Freudenberger 			(int) cardnr, (int) domain, rc);
563*e80d4af0SHarald Freudenberger 		goto out;
564*e80d4af0SHarald Freudenberger 	}
565*e80d4af0SHarald Freudenberger 
566*e80d4af0SHarald Freudenberger 	/* check response returncode and reasoncode */
567*e80d4af0SHarald Freudenberger 	if (prepcblk->ccp_rtcode != 0) {
568*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
569*e80d4af0SHarald Freudenberger 			"pkey_sec2protkey unwrap secure key failure, card response %d/%d\n",
570*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rtcode,
571*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rscode);
572*e80d4af0SHarald Freudenberger 		rc = -EIO;
573*e80d4af0SHarald Freudenberger 		goto out;
574*e80d4af0SHarald Freudenberger 	}
575*e80d4af0SHarald Freudenberger 
576*e80d4af0SHarald Freudenberger 	/* process response cprb param block */
577*e80d4af0SHarald Freudenberger 	prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX);
578*e80d4af0SHarald Freudenberger 	prepparm = (struct uskrepparm *) prepcblk->rpl_parmb;
579*e80d4af0SHarald Freudenberger 
580*e80d4af0SHarald Freudenberger 	/* check the returned keyblock */
581*e80d4af0SHarald Freudenberger 	if (prepparm->lv3.keyblock.version != 0x01) {
582*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
583*e80d4af0SHarald Freudenberger 			"pkey_sec2protkey reply param keyblock version mismatch 0x%02x != 0x01\n",
584*e80d4af0SHarald Freudenberger 			(int) prepparm->lv3.keyblock.version);
585*e80d4af0SHarald Freudenberger 		rc = -EIO;
586*e80d4af0SHarald Freudenberger 		goto out;
587*e80d4af0SHarald Freudenberger 	}
588*e80d4af0SHarald Freudenberger 
589*e80d4af0SHarald Freudenberger 	/* copy the tanslated protected key */
590*e80d4af0SHarald Freudenberger 	switch (prepparm->lv3.keyblock.keylen) {
591*e80d4af0SHarald Freudenberger 	case 16+32:
592*e80d4af0SHarald Freudenberger 		protkey->type = PKEY_KEYTYPE_AES_128;
593*e80d4af0SHarald Freudenberger 		break;
594*e80d4af0SHarald Freudenberger 	case 24+32:
595*e80d4af0SHarald Freudenberger 		protkey->type = PKEY_KEYTYPE_AES_192;
596*e80d4af0SHarald Freudenberger 		break;
597*e80d4af0SHarald Freudenberger 	case 32+32:
598*e80d4af0SHarald Freudenberger 		protkey->type = PKEY_KEYTYPE_AES_256;
599*e80d4af0SHarald Freudenberger 		break;
600*e80d4af0SHarald Freudenberger 	default:
601*e80d4af0SHarald Freudenberger 		DEBUG_ERR("pkey_sec2protkey unknown/unsupported keytype %d\n",
602*e80d4af0SHarald Freudenberger 			  prepparm->lv3.keyblock.keylen);
603*e80d4af0SHarald Freudenberger 		rc = -EIO;
604*e80d4af0SHarald Freudenberger 		goto out;
605*e80d4af0SHarald Freudenberger 	}
606*e80d4af0SHarald Freudenberger 	protkey->len = prepparm->lv3.keyblock.keylen;
607*e80d4af0SHarald Freudenberger 	memcpy(protkey->protkey, prepparm->lv3.keyblock.key, protkey->len);
608*e80d4af0SHarald Freudenberger 
609*e80d4af0SHarald Freudenberger out:
610*e80d4af0SHarald Freudenberger 	free_cprbmem(mem, PARMBSIZE, 0);
611*e80d4af0SHarald Freudenberger 	return rc;
612*e80d4af0SHarald Freudenberger }
613*e80d4af0SHarald Freudenberger EXPORT_SYMBOL(pkey_sec2protkey);
614*e80d4af0SHarald Freudenberger 
615*e80d4af0SHarald Freudenberger /*
616*e80d4af0SHarald Freudenberger  * Create a protected key from a clear key value.
617*e80d4af0SHarald Freudenberger  */
618*e80d4af0SHarald Freudenberger int pkey_clr2protkey(u32 keytype,
619*e80d4af0SHarald Freudenberger 		     const struct pkey_clrkey *clrkey,
620*e80d4af0SHarald Freudenberger 		     struct pkey_protkey *protkey)
621*e80d4af0SHarald Freudenberger {
622*e80d4af0SHarald Freudenberger 	long fc;
623*e80d4af0SHarald Freudenberger 	int keysize;
624*e80d4af0SHarald Freudenberger 	u8 paramblock[64];
625*e80d4af0SHarald Freudenberger 
626*e80d4af0SHarald Freudenberger 	switch (keytype) {
627*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_128:
628*e80d4af0SHarald Freudenberger 		keysize = 16;
629*e80d4af0SHarald Freudenberger 		fc = CPACF_PCKMO_ENC_AES_128_KEY;
630*e80d4af0SHarald Freudenberger 		break;
631*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_192:
632*e80d4af0SHarald Freudenberger 		keysize = 24;
633*e80d4af0SHarald Freudenberger 		fc = CPACF_PCKMO_ENC_AES_192_KEY;
634*e80d4af0SHarald Freudenberger 		break;
635*e80d4af0SHarald Freudenberger 	case PKEY_KEYTYPE_AES_256:
636*e80d4af0SHarald Freudenberger 		keysize = 32;
637*e80d4af0SHarald Freudenberger 		fc = CPACF_PCKMO_ENC_AES_256_KEY;
638*e80d4af0SHarald Freudenberger 		break;
639*e80d4af0SHarald Freudenberger 	default:
640*e80d4af0SHarald Freudenberger 		DEBUG_ERR("pkey_clr2protkey unknown/unsupported keytype %d\n",
641*e80d4af0SHarald Freudenberger 			  keytype);
642*e80d4af0SHarald Freudenberger 		return -EINVAL;
643*e80d4af0SHarald Freudenberger 	}
644*e80d4af0SHarald Freudenberger 
645*e80d4af0SHarald Freudenberger 	/* prepare param block */
646*e80d4af0SHarald Freudenberger 	memset(paramblock, 0, sizeof(paramblock));
647*e80d4af0SHarald Freudenberger 	memcpy(paramblock, clrkey->clrkey, keysize);
648*e80d4af0SHarald Freudenberger 
649*e80d4af0SHarald Freudenberger 	/* call the pckmo instruction */
650*e80d4af0SHarald Freudenberger 	cpacf_pckmo(fc, paramblock);
651*e80d4af0SHarald Freudenberger 
652*e80d4af0SHarald Freudenberger 	/* copy created protected key */
653*e80d4af0SHarald Freudenberger 	protkey->type = keytype;
654*e80d4af0SHarald Freudenberger 	protkey->len = keysize + 32;
655*e80d4af0SHarald Freudenberger 	memcpy(protkey->protkey, paramblock, keysize + 32);
656*e80d4af0SHarald Freudenberger 
657*e80d4af0SHarald Freudenberger 	return 0;
658*e80d4af0SHarald Freudenberger }
659*e80d4af0SHarald Freudenberger EXPORT_SYMBOL(pkey_clr2protkey);
660*e80d4af0SHarald Freudenberger 
661*e80d4af0SHarald Freudenberger /*
662*e80d4af0SHarald Freudenberger  * query cryptographic facility from adapter
663*e80d4af0SHarald Freudenberger  */
664*e80d4af0SHarald Freudenberger static int query_crypto_facility(u16 cardnr, u16 domain,
665*e80d4af0SHarald Freudenberger 				 const char *keyword,
666*e80d4af0SHarald Freudenberger 				 u8 *rarray, size_t *rarraylen,
667*e80d4af0SHarald Freudenberger 				 u8 *varray, size_t *varraylen)
668*e80d4af0SHarald Freudenberger {
669*e80d4af0SHarald Freudenberger 	int rc;
670*e80d4af0SHarald Freudenberger 	u16 len;
671*e80d4af0SHarald Freudenberger 	u8 *mem, *ptr;
672*e80d4af0SHarald Freudenberger 	struct CPRBX *preqcblk, *prepcblk;
673*e80d4af0SHarald Freudenberger 	struct ica_xcRB xcrb;
674*e80d4af0SHarald Freudenberger 	struct fqreqparm {
675*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
676*e80d4af0SHarald Freudenberger 		u16 rule_array_len;
677*e80d4af0SHarald Freudenberger 		char  rule_array[8];
678*e80d4af0SHarald Freudenberger 		struct lv1 {
679*e80d4af0SHarald Freudenberger 			u16 len;
680*e80d4af0SHarald Freudenberger 			u8  data[VARDATASIZE];
681*e80d4af0SHarald Freudenberger 		} lv1;
682*e80d4af0SHarald Freudenberger 		u16 dummylen;
683*e80d4af0SHarald Freudenberger 	} *preqparm;
684*e80d4af0SHarald Freudenberger 	size_t parmbsize = sizeof(struct fqreqparm);
685*e80d4af0SHarald Freudenberger 	struct fqrepparm {
686*e80d4af0SHarald Freudenberger 		u8  subfunc_code[2];
687*e80d4af0SHarald Freudenberger 		u8  lvdata[0];
688*e80d4af0SHarald Freudenberger 	} *prepparm;
689*e80d4af0SHarald Freudenberger 
690*e80d4af0SHarald Freudenberger 	/* get already prepared memory for 2 cprbs with param block each */
691*e80d4af0SHarald Freudenberger 	rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk);
692*e80d4af0SHarald Freudenberger 	if (rc)
693*e80d4af0SHarald Freudenberger 		return rc;
694*e80d4af0SHarald Freudenberger 
695*e80d4af0SHarald Freudenberger 	/* fill request cprb struct */
696*e80d4af0SHarald Freudenberger 	preqcblk->domain = domain;
697*e80d4af0SHarald Freudenberger 
698*e80d4af0SHarald Freudenberger 	/* fill request cprb param block with FQ request */
699*e80d4af0SHarald Freudenberger 	preqparm = (struct fqreqparm *) preqcblk->req_parmb;
700*e80d4af0SHarald Freudenberger 	memcpy(preqparm->subfunc_code, "FQ", 2);
701*e80d4af0SHarald Freudenberger 	strncpy(preqparm->rule_array, keyword, sizeof(preqparm->rule_array));
702*e80d4af0SHarald Freudenberger 	preqparm->rule_array_len =
703*e80d4af0SHarald Freudenberger 		sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array);
704*e80d4af0SHarald Freudenberger 	preqparm->lv1.len = sizeof(preqparm->lv1);
705*e80d4af0SHarald Freudenberger 	preqparm->dummylen = sizeof(preqparm->dummylen);
706*e80d4af0SHarald Freudenberger 	preqcblk->req_parml = parmbsize;
707*e80d4af0SHarald Freudenberger 
708*e80d4af0SHarald Freudenberger 	/* fill xcrb struct */
709*e80d4af0SHarald Freudenberger 	prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
710*e80d4af0SHarald Freudenberger 
711*e80d4af0SHarald Freudenberger 	/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
712*e80d4af0SHarald Freudenberger 	rc = _zcrypt_send_cprb(&xcrb);
713*e80d4af0SHarald Freudenberger 	if (rc) {
714*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
715*e80d4af0SHarald Freudenberger 			"query_crypto_facility zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n",
716*e80d4af0SHarald Freudenberger 			(int) cardnr, (int) domain, rc);
717*e80d4af0SHarald Freudenberger 		goto out;
718*e80d4af0SHarald Freudenberger 	}
719*e80d4af0SHarald Freudenberger 
720*e80d4af0SHarald Freudenberger 	/* check response returncode and reasoncode */
721*e80d4af0SHarald Freudenberger 	if (prepcblk->ccp_rtcode != 0) {
722*e80d4af0SHarald Freudenberger 		DEBUG_ERR(
723*e80d4af0SHarald Freudenberger 			"query_crypto_facility unwrap secure key failure, card response %d/%d\n",
724*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rtcode,
725*e80d4af0SHarald Freudenberger 			(int) prepcblk->ccp_rscode);
726*e80d4af0SHarald Freudenberger 		rc = -EIO;
727*e80d4af0SHarald Freudenberger 		goto out;
728*e80d4af0SHarald Freudenberger 	}
729*e80d4af0SHarald Freudenberger 
730*e80d4af0SHarald Freudenberger 	/* process response cprb param block */
731*e80d4af0SHarald Freudenberger 	prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX);
732*e80d4af0SHarald Freudenberger 	prepparm = (struct fqrepparm *) prepcblk->rpl_parmb;
733*e80d4af0SHarald Freudenberger 	ptr = prepparm->lvdata;
734*e80d4af0SHarald Freudenberger 
735*e80d4af0SHarald Freudenberger 	/* check and possibly copy reply rule array */
736*e80d4af0SHarald Freudenberger 	len = *((u16 *) ptr);
737*e80d4af0SHarald Freudenberger 	if (len > sizeof(u16)) {
738*e80d4af0SHarald Freudenberger 		ptr += sizeof(u16);
739*e80d4af0SHarald Freudenberger 		len -= sizeof(u16);
740*e80d4af0SHarald Freudenberger 		if (rarray && rarraylen && *rarraylen > 0) {
741*e80d4af0SHarald Freudenberger 			*rarraylen = (len > *rarraylen ? *rarraylen : len);
742*e80d4af0SHarald Freudenberger 			memcpy(rarray, ptr, *rarraylen);
743*e80d4af0SHarald Freudenberger 		}
744*e80d4af0SHarald Freudenberger 		ptr += len;
745*e80d4af0SHarald Freudenberger 	}
746*e80d4af0SHarald Freudenberger 	/* check and possible copy reply var array */
747*e80d4af0SHarald Freudenberger 	len = *((u16 *) ptr);
748*e80d4af0SHarald Freudenberger 	if (len > sizeof(u16)) {
749*e80d4af0SHarald Freudenberger 		ptr += sizeof(u16);
750*e80d4af0SHarald Freudenberger 		len -= sizeof(u16);
751*e80d4af0SHarald Freudenberger 		if (varray && varraylen && *varraylen > 0) {
752*e80d4af0SHarald Freudenberger 			*varraylen = (len > *varraylen ? *varraylen : len);
753*e80d4af0SHarald Freudenberger 			memcpy(varray, ptr, *varraylen);
754*e80d4af0SHarald Freudenberger 		}
755*e80d4af0SHarald Freudenberger 		ptr += len;
756*e80d4af0SHarald Freudenberger 	}
757*e80d4af0SHarald Freudenberger 
758*e80d4af0SHarald Freudenberger out:
759*e80d4af0SHarald Freudenberger 	free_cprbmem(mem, parmbsize, 0);
760*e80d4af0SHarald Freudenberger 	return rc;
761*e80d4af0SHarald Freudenberger }
762*e80d4af0SHarald Freudenberger 
763*e80d4af0SHarald Freudenberger /*
764*e80d4af0SHarald Freudenberger  * Fetch just the mkvp value via query_crypto_facility from adapter.
765*e80d4af0SHarald Freudenberger  */
766*e80d4af0SHarald Freudenberger static int fetch_mkvp(u16 cardnr, u16 domain, u64 *mkvp)
767*e80d4af0SHarald Freudenberger {
768*e80d4af0SHarald Freudenberger 	int rc, found = 0;
769*e80d4af0SHarald Freudenberger 	size_t rlen, vlen;
770*e80d4af0SHarald Freudenberger 	u8 *rarray, *varray, *pg;
771*e80d4af0SHarald Freudenberger 
772*e80d4af0SHarald Freudenberger 	pg = (u8 *) __get_free_page(GFP_KERNEL);
773*e80d4af0SHarald Freudenberger 	if (!pg)
774*e80d4af0SHarald Freudenberger 		return -ENOMEM;
775*e80d4af0SHarald Freudenberger 	rarray = pg;
776*e80d4af0SHarald Freudenberger 	varray = pg + PAGE_SIZE/2;
777*e80d4af0SHarald Freudenberger 	rlen = vlen = PAGE_SIZE/2;
778*e80d4af0SHarald Freudenberger 
779*e80d4af0SHarald Freudenberger 	rc = query_crypto_facility(cardnr, domain, "STATICSA",
780*e80d4af0SHarald Freudenberger 				   rarray, &rlen, varray, &vlen);
781*e80d4af0SHarald Freudenberger 	if (rc == 0 && rlen > 8*8 && vlen > 184+8) {
782*e80d4af0SHarald Freudenberger 		if (rarray[64] == '2') {
783*e80d4af0SHarald Freudenberger 			/* current master key state is valid */
784*e80d4af0SHarald Freudenberger 			*mkvp = *((u64 *)(varray + 184));
785*e80d4af0SHarald Freudenberger 			found = 1;
786*e80d4af0SHarald Freudenberger 		}
787*e80d4af0SHarald Freudenberger 	}
788*e80d4af0SHarald Freudenberger 
789*e80d4af0SHarald Freudenberger 	free_page((unsigned long) pg);
790*e80d4af0SHarald Freudenberger 
791*e80d4af0SHarald Freudenberger 	return found ? 0 : -ENOENT;
792*e80d4af0SHarald Freudenberger }
793*e80d4af0SHarald Freudenberger 
794*e80d4af0SHarald Freudenberger /* struct to hold cached mkvp info for each card/domain */
795*e80d4af0SHarald Freudenberger struct mkvp_info {
796*e80d4af0SHarald Freudenberger 	struct list_head list;
797*e80d4af0SHarald Freudenberger 	u16 cardnr;
798*e80d4af0SHarald Freudenberger 	u16 domain;
799*e80d4af0SHarald Freudenberger 	u64 mkvp;
800*e80d4af0SHarald Freudenberger };
801*e80d4af0SHarald Freudenberger 
802*e80d4af0SHarald Freudenberger /* a list with mkvp_info entries */
803*e80d4af0SHarald Freudenberger static LIST_HEAD(mkvp_list);
804*e80d4af0SHarald Freudenberger static DEFINE_SPINLOCK(mkvp_list_lock);
805*e80d4af0SHarald Freudenberger 
806*e80d4af0SHarald Freudenberger static int mkvp_cache_fetch(u16 cardnr, u16 domain, u64 *mkvp)
807*e80d4af0SHarald Freudenberger {
808*e80d4af0SHarald Freudenberger 	int rc = -ENOENT;
809*e80d4af0SHarald Freudenberger 	struct mkvp_info *ptr;
810*e80d4af0SHarald Freudenberger 
811*e80d4af0SHarald Freudenberger 	spin_lock_bh(&mkvp_list_lock);
812*e80d4af0SHarald Freudenberger 	list_for_each_entry(ptr, &mkvp_list, list) {
813*e80d4af0SHarald Freudenberger 		if (ptr->cardnr == cardnr &&
814*e80d4af0SHarald Freudenberger 		    ptr->domain == domain) {
815*e80d4af0SHarald Freudenberger 			*mkvp = ptr->mkvp;
816*e80d4af0SHarald Freudenberger 			rc = 0;
817*e80d4af0SHarald Freudenberger 			break;
818*e80d4af0SHarald Freudenberger 		}
819*e80d4af0SHarald Freudenberger 	}
820*e80d4af0SHarald Freudenberger 	spin_unlock_bh(&mkvp_list_lock);
821*e80d4af0SHarald Freudenberger 
822*e80d4af0SHarald Freudenberger 	return rc;
823*e80d4af0SHarald Freudenberger }
824*e80d4af0SHarald Freudenberger 
825*e80d4af0SHarald Freudenberger static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp)
826*e80d4af0SHarald Freudenberger {
827*e80d4af0SHarald Freudenberger 	int found = 0;
828*e80d4af0SHarald Freudenberger 	struct mkvp_info *ptr;
829*e80d4af0SHarald Freudenberger 
830*e80d4af0SHarald Freudenberger 	spin_lock_bh(&mkvp_list_lock);
831*e80d4af0SHarald Freudenberger 	list_for_each_entry(ptr, &mkvp_list, list) {
832*e80d4af0SHarald Freudenberger 		if (ptr->cardnr == cardnr &&
833*e80d4af0SHarald Freudenberger 		    ptr->domain == domain) {
834*e80d4af0SHarald Freudenberger 			ptr->mkvp = mkvp;
835*e80d4af0SHarald Freudenberger 			found = 1;
836*e80d4af0SHarald Freudenberger 			break;
837*e80d4af0SHarald Freudenberger 		}
838*e80d4af0SHarald Freudenberger 	}
839*e80d4af0SHarald Freudenberger 	if (!found) {
840*e80d4af0SHarald Freudenberger 		ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC);
841*e80d4af0SHarald Freudenberger 		if (!ptr) {
842*e80d4af0SHarald Freudenberger 			spin_unlock_bh(&mkvp_list_lock);
843*e80d4af0SHarald Freudenberger 			return;
844*e80d4af0SHarald Freudenberger 		}
845*e80d4af0SHarald Freudenberger 		ptr->cardnr = cardnr;
846*e80d4af0SHarald Freudenberger 		ptr->domain = domain;
847*e80d4af0SHarald Freudenberger 		ptr->mkvp = mkvp;
848*e80d4af0SHarald Freudenberger 		list_add(&ptr->list, &mkvp_list);
849*e80d4af0SHarald Freudenberger 	}
850*e80d4af0SHarald Freudenberger 	spin_unlock_bh(&mkvp_list_lock);
851*e80d4af0SHarald Freudenberger }
852*e80d4af0SHarald Freudenberger 
853*e80d4af0SHarald Freudenberger static void mkvp_cache_scrub(u16 cardnr, u16 domain)
854*e80d4af0SHarald Freudenberger {
855*e80d4af0SHarald Freudenberger 	struct mkvp_info *ptr;
856*e80d4af0SHarald Freudenberger 
857*e80d4af0SHarald Freudenberger 	spin_lock_bh(&mkvp_list_lock);
858*e80d4af0SHarald Freudenberger 	list_for_each_entry(ptr, &mkvp_list, list) {
859*e80d4af0SHarald Freudenberger 		if (ptr->cardnr == cardnr &&
860*e80d4af0SHarald Freudenberger 		    ptr->domain == domain) {
861*e80d4af0SHarald Freudenberger 			list_del(&ptr->list);
862*e80d4af0SHarald Freudenberger 			kfree(ptr);
863*e80d4af0SHarald Freudenberger 			break;
864*e80d4af0SHarald Freudenberger 		}
865*e80d4af0SHarald Freudenberger 	}
866*e80d4af0SHarald Freudenberger 	spin_unlock_bh(&mkvp_list_lock);
867*e80d4af0SHarald Freudenberger }
868*e80d4af0SHarald Freudenberger 
869*e80d4af0SHarald Freudenberger static void __exit mkvp_cache_free(void)
870*e80d4af0SHarald Freudenberger {
871*e80d4af0SHarald Freudenberger 	struct mkvp_info *ptr, *pnext;
872*e80d4af0SHarald Freudenberger 
873*e80d4af0SHarald Freudenberger 	spin_lock_bh(&mkvp_list_lock);
874*e80d4af0SHarald Freudenberger 	list_for_each_entry_safe(ptr, pnext, &mkvp_list, list) {
875*e80d4af0SHarald Freudenberger 		list_del(&ptr->list);
876*e80d4af0SHarald Freudenberger 		kfree(ptr);
877*e80d4af0SHarald Freudenberger 	}
878*e80d4af0SHarald Freudenberger 	spin_unlock_bh(&mkvp_list_lock);
879*e80d4af0SHarald Freudenberger }
880*e80d4af0SHarald Freudenberger 
881*e80d4af0SHarald Freudenberger /*
882*e80d4af0SHarald Freudenberger  * Search for a matching crypto card based on the Master Key
883*e80d4af0SHarald Freudenberger  * Verification Pattern provided inside a secure key.
884*e80d4af0SHarald Freudenberger  */
885*e80d4af0SHarald Freudenberger int pkey_findcard(const struct pkey_seckey *seckey,
886*e80d4af0SHarald Freudenberger 		  u16 *pcardnr, u16 *pdomain, int verify)
887*e80d4af0SHarald Freudenberger {
888*e80d4af0SHarald Freudenberger 	struct secaeskeytoken *t = (struct secaeskeytoken *) seckey;
889*e80d4af0SHarald Freudenberger 	struct zcrypt_device_matrix *device_matrix;
890*e80d4af0SHarald Freudenberger 	u16 card, dom;
891*e80d4af0SHarald Freudenberger 	u64 mkvp;
892*e80d4af0SHarald Freudenberger 	int i, rc;
893*e80d4af0SHarald Freudenberger 
894*e80d4af0SHarald Freudenberger 	/* mkvp must not be zero */
895*e80d4af0SHarald Freudenberger 	if (t->mkvp == 0)
896*e80d4af0SHarald Freudenberger 		return -EINVAL;
897*e80d4af0SHarald Freudenberger 
898*e80d4af0SHarald Freudenberger 	/* fetch status of all crypto cards */
899*e80d4af0SHarald Freudenberger 	device_matrix = kmalloc(sizeof(struct zcrypt_device_matrix),
900*e80d4af0SHarald Freudenberger 				GFP_KERNEL);
901*e80d4af0SHarald Freudenberger 	if (!device_matrix)
902*e80d4af0SHarald Freudenberger 		return -ENOMEM;
903*e80d4af0SHarald Freudenberger 	zcrypt_device_status_mask(device_matrix);
904*e80d4af0SHarald Freudenberger 
905*e80d4af0SHarald Freudenberger 	/* walk through all crypto cards */
906*e80d4af0SHarald Freudenberger 	for (i = 0; i < MAX_ZDEV_ENTRIES; i++) {
907*e80d4af0SHarald Freudenberger 		card = AP_QID_CARD(device_matrix->device[i].qid);
908*e80d4af0SHarald Freudenberger 		dom = AP_QID_QUEUE(device_matrix->device[i].qid);
909*e80d4af0SHarald Freudenberger 		if (device_matrix->device[i].online &&
910*e80d4af0SHarald Freudenberger 		    device_matrix->device[i].functions & 0x04) {
911*e80d4af0SHarald Freudenberger 			/* an enabled CCA Coprocessor card */
912*e80d4af0SHarald Freudenberger 			/* try cached mkvp */
913*e80d4af0SHarald Freudenberger 			if (mkvp_cache_fetch(card, dom, &mkvp) == 0 &&
914*e80d4af0SHarald Freudenberger 			    t->mkvp == mkvp) {
915*e80d4af0SHarald Freudenberger 				if (!verify)
916*e80d4af0SHarald Freudenberger 					break;
917*e80d4af0SHarald Freudenberger 				/* verify: fetch mkvp from adapter */
918*e80d4af0SHarald Freudenberger 				if (fetch_mkvp(card, dom, &mkvp) == 0) {
919*e80d4af0SHarald Freudenberger 					mkvp_cache_update(card, dom, mkvp);
920*e80d4af0SHarald Freudenberger 					if (t->mkvp == mkvp)
921*e80d4af0SHarald Freudenberger 						break;
922*e80d4af0SHarald Freudenberger 				}
923*e80d4af0SHarald Freudenberger 			}
924*e80d4af0SHarald Freudenberger 		} else {
925*e80d4af0SHarald Freudenberger 			/* Card is offline and/or not a CCA card. */
926*e80d4af0SHarald Freudenberger 			/* del mkvp entry from cache if it exists */
927*e80d4af0SHarald Freudenberger 			mkvp_cache_scrub(card, dom);
928*e80d4af0SHarald Freudenberger 		}
929*e80d4af0SHarald Freudenberger 	}
930*e80d4af0SHarald Freudenberger 	if (i >= MAX_ZDEV_ENTRIES) {
931*e80d4af0SHarald Freudenberger 		/* nothing found, so this time without cache */
932*e80d4af0SHarald Freudenberger 		for (i = 0; i < MAX_ZDEV_ENTRIES; i++) {
933*e80d4af0SHarald Freudenberger 			if (!(device_matrix->device[i].online &&
934*e80d4af0SHarald Freudenberger 			      device_matrix->device[i].functions & 0x04))
935*e80d4af0SHarald Freudenberger 				continue;
936*e80d4af0SHarald Freudenberger 			card = AP_QID_CARD(device_matrix->device[i].qid);
937*e80d4af0SHarald Freudenberger 			dom = AP_QID_QUEUE(device_matrix->device[i].qid);
938*e80d4af0SHarald Freudenberger 			/* fresh fetch mkvp from adapter */
939*e80d4af0SHarald Freudenberger 			if (fetch_mkvp(card, dom, &mkvp) == 0) {
940*e80d4af0SHarald Freudenberger 				mkvp_cache_update(card, dom, mkvp);
941*e80d4af0SHarald Freudenberger 				if (t->mkvp == mkvp)
942*e80d4af0SHarald Freudenberger 					break;
943*e80d4af0SHarald Freudenberger 			}
944*e80d4af0SHarald Freudenberger 		}
945*e80d4af0SHarald Freudenberger 	}
946*e80d4af0SHarald Freudenberger 	if (i < MAX_ZDEV_ENTRIES) {
947*e80d4af0SHarald Freudenberger 		if (pcardnr)
948*e80d4af0SHarald Freudenberger 			*pcardnr = card;
949*e80d4af0SHarald Freudenberger 		if (pdomain)
950*e80d4af0SHarald Freudenberger 			*pdomain = dom;
951*e80d4af0SHarald Freudenberger 		rc = 0;
952*e80d4af0SHarald Freudenberger 	} else
953*e80d4af0SHarald Freudenberger 		rc = -ENODEV;
954*e80d4af0SHarald Freudenberger 
955*e80d4af0SHarald Freudenberger 	kfree(device_matrix);
956*e80d4af0SHarald Freudenberger 	return rc;
957*e80d4af0SHarald Freudenberger }
958*e80d4af0SHarald Freudenberger EXPORT_SYMBOL(pkey_findcard);
959*e80d4af0SHarald Freudenberger 
960*e80d4af0SHarald Freudenberger /*
961*e80d4af0SHarald Freudenberger  * Find card and transform secure key into protected key.
962*e80d4af0SHarald Freudenberger  */
963*e80d4af0SHarald Freudenberger int pkey_skey2pkey(const struct pkey_seckey *seckey,
964*e80d4af0SHarald Freudenberger 		   struct pkey_protkey *protkey)
965*e80d4af0SHarald Freudenberger {
966*e80d4af0SHarald Freudenberger 	u16 cardnr, domain;
967*e80d4af0SHarald Freudenberger 	int rc, verify;
968*e80d4af0SHarald Freudenberger 
969*e80d4af0SHarald Freudenberger 	/*
970*e80d4af0SHarald Freudenberger 	 * The pkey_sec2protkey call may fail when a card has been
971*e80d4af0SHarald Freudenberger 	 * addressed where the master key was changed after last fetch
972*e80d4af0SHarald Freudenberger 	 * of the mkvp into the cache. So first try without verify then
973*e80d4af0SHarald Freudenberger 	 * with verify enabled (thus refreshing the mkvp for each card).
974*e80d4af0SHarald Freudenberger 	 */
975*e80d4af0SHarald Freudenberger 	for (verify = 0; verify < 2; verify++) {
976*e80d4af0SHarald Freudenberger 		rc = pkey_findcard(seckey, &cardnr, &domain, verify);
977*e80d4af0SHarald Freudenberger 		if (rc)
978*e80d4af0SHarald Freudenberger 			continue;
979*e80d4af0SHarald Freudenberger 		rc = pkey_sec2protkey(cardnr, domain, seckey, protkey);
980*e80d4af0SHarald Freudenberger 		if (rc == 0)
981*e80d4af0SHarald Freudenberger 			break;
982*e80d4af0SHarald Freudenberger 	}
983*e80d4af0SHarald Freudenberger 
984*e80d4af0SHarald Freudenberger 	if (rc)
985*e80d4af0SHarald Freudenberger 		DEBUG_DBG("pkey_skey2pkey failed rc=%d\n", rc);
986*e80d4af0SHarald Freudenberger 
987*e80d4af0SHarald Freudenberger 	return rc;
988*e80d4af0SHarald Freudenberger }
989*e80d4af0SHarald Freudenberger EXPORT_SYMBOL(pkey_skey2pkey);
990*e80d4af0SHarald Freudenberger 
991*e80d4af0SHarald Freudenberger /*
992*e80d4af0SHarald Freudenberger  * File io functions
993*e80d4af0SHarald Freudenberger  */
994*e80d4af0SHarald Freudenberger 
995*e80d4af0SHarald Freudenberger static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
996*e80d4af0SHarald Freudenberger 				unsigned long arg)
997*e80d4af0SHarald Freudenberger {
998*e80d4af0SHarald Freudenberger 	int rc;
999*e80d4af0SHarald Freudenberger 
1000*e80d4af0SHarald Freudenberger 	switch (cmd) {
1001*e80d4af0SHarald Freudenberger 	case PKEY_GENSECK: {
1002*e80d4af0SHarald Freudenberger 		struct pkey_genseck __user *ugs = (void __user *) arg;
1003*e80d4af0SHarald Freudenberger 		struct pkey_genseck kgs;
1004*e80d4af0SHarald Freudenberger 
1005*e80d4af0SHarald Freudenberger 		if (copy_from_user(&kgs, ugs, sizeof(kgs)))
1006*e80d4af0SHarald Freudenberger 			return -EFAULT;
1007*e80d4af0SHarald Freudenberger 		rc = pkey_genseckey(kgs.cardnr, kgs.domain,
1008*e80d4af0SHarald Freudenberger 				    kgs.keytype, &kgs.seckey);
1009*e80d4af0SHarald Freudenberger 		DEBUG_DBG("pkey_ioctl pkey_genseckey()=%d\n", rc);
1010*e80d4af0SHarald Freudenberger 		if (rc)
1011*e80d4af0SHarald Freudenberger 			break;
1012*e80d4af0SHarald Freudenberger 		if (copy_to_user(ugs, &kgs, sizeof(kgs)))
1013*e80d4af0SHarald Freudenberger 			return -EFAULT;
1014*e80d4af0SHarald Freudenberger 		break;
1015*e80d4af0SHarald Freudenberger 	}
1016*e80d4af0SHarald Freudenberger 	case PKEY_CLR2SECK: {
1017*e80d4af0SHarald Freudenberger 		struct pkey_clr2seck __user *ucs = (void __user *) arg;
1018*e80d4af0SHarald Freudenberger 		struct pkey_clr2seck kcs;
1019*e80d4af0SHarald Freudenberger 
1020*e80d4af0SHarald Freudenberger 		if (copy_from_user(&kcs, ucs, sizeof(kcs)))
1021*e80d4af0SHarald Freudenberger 			return -EFAULT;
1022*e80d4af0SHarald Freudenberger 		rc = pkey_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype,
1023*e80d4af0SHarald Freudenberger 				     &kcs.clrkey, &kcs.seckey);
1024*e80d4af0SHarald Freudenberger 		DEBUG_DBG("pkey_ioctl pkey_clr2seckey()=%d\n", rc);
1025*e80d4af0SHarald Freudenberger 		if (rc)
1026*e80d4af0SHarald Freudenberger 			break;
1027*e80d4af0SHarald Freudenberger 		if (copy_to_user(ucs, &kcs, sizeof(kcs)))
1028*e80d4af0SHarald Freudenberger 			return -EFAULT;
1029*e80d4af0SHarald Freudenberger 		memzero_explicit(&kcs, sizeof(kcs));
1030*e80d4af0SHarald Freudenberger 		break;
1031*e80d4af0SHarald Freudenberger 	}
1032*e80d4af0SHarald Freudenberger 	case PKEY_SEC2PROTK: {
1033*e80d4af0SHarald Freudenberger 		struct pkey_sec2protk __user *usp = (void __user *) arg;
1034*e80d4af0SHarald Freudenberger 		struct pkey_sec2protk ksp;
1035*e80d4af0SHarald Freudenberger 
1036*e80d4af0SHarald Freudenberger 		if (copy_from_user(&ksp, usp, sizeof(ksp)))
1037*e80d4af0SHarald Freudenberger 			return -EFAULT;
1038*e80d4af0SHarald Freudenberger 		rc = pkey_sec2protkey(ksp.cardnr, ksp.domain,
1039*e80d4af0SHarald Freudenberger 				      &ksp.seckey, &ksp.protkey);
1040*e80d4af0SHarald Freudenberger 		DEBUG_DBG("pkey_ioctl pkey_sec2protkey()=%d\n", rc);
1041*e80d4af0SHarald Freudenberger 		if (rc)
1042*e80d4af0SHarald Freudenberger 			break;
1043*e80d4af0SHarald Freudenberger 		if (copy_to_user(usp, &ksp, sizeof(ksp)))
1044*e80d4af0SHarald Freudenberger 			return -EFAULT;
1045*e80d4af0SHarald Freudenberger 		break;
1046*e80d4af0SHarald Freudenberger 	}
1047*e80d4af0SHarald Freudenberger 	case PKEY_CLR2PROTK: {
1048*e80d4af0SHarald Freudenberger 		struct pkey_clr2protk __user *ucp = (void __user *) arg;
1049*e80d4af0SHarald Freudenberger 		struct pkey_clr2protk kcp;
1050*e80d4af0SHarald Freudenberger 
1051*e80d4af0SHarald Freudenberger 		if (copy_from_user(&kcp, ucp, sizeof(kcp)))
1052*e80d4af0SHarald Freudenberger 			return -EFAULT;
1053*e80d4af0SHarald Freudenberger 		rc = pkey_clr2protkey(kcp.keytype,
1054*e80d4af0SHarald Freudenberger 				      &kcp.clrkey, &kcp.protkey);
1055*e80d4af0SHarald Freudenberger 		DEBUG_DBG("pkey_ioctl pkey_clr2protkey()=%d\n", rc);
1056*e80d4af0SHarald Freudenberger 		if (rc)
1057*e80d4af0SHarald Freudenberger 			break;
1058*e80d4af0SHarald Freudenberger 		if (copy_to_user(ucp, &kcp, sizeof(kcp)))
1059*e80d4af0SHarald Freudenberger 			return -EFAULT;
1060*e80d4af0SHarald Freudenberger 		memzero_explicit(&kcp, sizeof(kcp));
1061*e80d4af0SHarald Freudenberger 		break;
1062*e80d4af0SHarald Freudenberger 	}
1063*e80d4af0SHarald Freudenberger 	case PKEY_FINDCARD: {
1064*e80d4af0SHarald Freudenberger 		struct pkey_findcard __user *ufc = (void __user *) arg;
1065*e80d4af0SHarald Freudenberger 		struct pkey_findcard kfc;
1066*e80d4af0SHarald Freudenberger 
1067*e80d4af0SHarald Freudenberger 		if (copy_from_user(&kfc, ufc, sizeof(kfc)))
1068*e80d4af0SHarald Freudenberger 			return -EFAULT;
1069*e80d4af0SHarald Freudenberger 		rc = pkey_findcard(&kfc.seckey,
1070*e80d4af0SHarald Freudenberger 				   &kfc.cardnr, &kfc.domain, 1);
1071*e80d4af0SHarald Freudenberger 		DEBUG_DBG("pkey_ioctl pkey_findcard()=%d\n", rc);
1072*e80d4af0SHarald Freudenberger 		if (rc)
1073*e80d4af0SHarald Freudenberger 			break;
1074*e80d4af0SHarald Freudenberger 		if (copy_to_user(ufc, &kfc, sizeof(kfc)))
1075*e80d4af0SHarald Freudenberger 			return -EFAULT;
1076*e80d4af0SHarald Freudenberger 		break;
1077*e80d4af0SHarald Freudenberger 	}
1078*e80d4af0SHarald Freudenberger 	case PKEY_SKEY2PKEY: {
1079*e80d4af0SHarald Freudenberger 		struct pkey_skey2pkey __user *usp = (void __user *) arg;
1080*e80d4af0SHarald Freudenberger 		struct pkey_skey2pkey ksp;
1081*e80d4af0SHarald Freudenberger 
1082*e80d4af0SHarald Freudenberger 		if (copy_from_user(&ksp, usp, sizeof(ksp)))
1083*e80d4af0SHarald Freudenberger 			return -EFAULT;
1084*e80d4af0SHarald Freudenberger 		rc = pkey_skey2pkey(&ksp.seckey, &ksp.protkey);
1085*e80d4af0SHarald Freudenberger 		DEBUG_DBG("pkey_ioctl pkey_skey2pkey()=%d\n", rc);
1086*e80d4af0SHarald Freudenberger 		if (rc)
1087*e80d4af0SHarald Freudenberger 			break;
1088*e80d4af0SHarald Freudenberger 		if (copy_to_user(usp, &ksp, sizeof(ksp)))
1089*e80d4af0SHarald Freudenberger 			return -EFAULT;
1090*e80d4af0SHarald Freudenberger 		break;
1091*e80d4af0SHarald Freudenberger 	}
1092*e80d4af0SHarald Freudenberger 	default:
1093*e80d4af0SHarald Freudenberger 		/* unknown/unsupported ioctl cmd */
1094*e80d4af0SHarald Freudenberger 		return -ENOTTY;
1095*e80d4af0SHarald Freudenberger 	}
1096*e80d4af0SHarald Freudenberger 
1097*e80d4af0SHarald Freudenberger 	return rc;
1098*e80d4af0SHarald Freudenberger }
1099*e80d4af0SHarald Freudenberger 
1100*e80d4af0SHarald Freudenberger /*
1101*e80d4af0SHarald Freudenberger  * Sysfs and file io operations
1102*e80d4af0SHarald Freudenberger  */
1103*e80d4af0SHarald Freudenberger static const struct file_operations pkey_fops = {
1104*e80d4af0SHarald Freudenberger 	.owner		= THIS_MODULE,
1105*e80d4af0SHarald Freudenberger 	.open		= nonseekable_open,
1106*e80d4af0SHarald Freudenberger 	.llseek		= no_llseek,
1107*e80d4af0SHarald Freudenberger 	.unlocked_ioctl = pkey_unlocked_ioctl,
1108*e80d4af0SHarald Freudenberger };
1109*e80d4af0SHarald Freudenberger 
1110*e80d4af0SHarald Freudenberger static struct miscdevice pkey_dev = {
1111*e80d4af0SHarald Freudenberger 	.name	= "pkey",
1112*e80d4af0SHarald Freudenberger 	.minor	= MISC_DYNAMIC_MINOR,
1113*e80d4af0SHarald Freudenberger 	.mode	= 0666,
1114*e80d4af0SHarald Freudenberger 	.fops	= &pkey_fops,
1115*e80d4af0SHarald Freudenberger };
1116*e80d4af0SHarald Freudenberger 
1117*e80d4af0SHarald Freudenberger /*
1118*e80d4af0SHarald Freudenberger  * Module init
1119*e80d4af0SHarald Freudenberger  */
1120*e80d4af0SHarald Freudenberger int __init pkey_init(void)
1121*e80d4af0SHarald Freudenberger {
1122*e80d4af0SHarald Freudenberger 	cpacf_mask_t pckmo_functions;
1123*e80d4af0SHarald Freudenberger 
1124*e80d4af0SHarald Freudenberger 	/* check for pckmo instructions available */
1125*e80d4af0SHarald Freudenberger 	if (!cpacf_query(CPACF_PCKMO, &pckmo_functions))
1126*e80d4af0SHarald Freudenberger 		return -EOPNOTSUPP;
1127*e80d4af0SHarald Freudenberger 	if (!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_128_KEY) ||
1128*e80d4af0SHarald Freudenberger 	    !cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_192_KEY) ||
1129*e80d4af0SHarald Freudenberger 	    !cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_256_KEY))
1130*e80d4af0SHarald Freudenberger 		return -EOPNOTSUPP;
1131*e80d4af0SHarald Freudenberger 
1132*e80d4af0SHarald Freudenberger 	pkey_debug_init();
1133*e80d4af0SHarald Freudenberger 
1134*e80d4af0SHarald Freudenberger 	return misc_register(&pkey_dev);
1135*e80d4af0SHarald Freudenberger }
1136*e80d4af0SHarald Freudenberger 
1137*e80d4af0SHarald Freudenberger /*
1138*e80d4af0SHarald Freudenberger  * Module exit
1139*e80d4af0SHarald Freudenberger  */
1140*e80d4af0SHarald Freudenberger static void __exit pkey_exit(void)
1141*e80d4af0SHarald Freudenberger {
1142*e80d4af0SHarald Freudenberger 	misc_deregister(&pkey_dev);
1143*e80d4af0SHarald Freudenberger 	mkvp_cache_free();
1144*e80d4af0SHarald Freudenberger 	pkey_debug_exit();
1145*e80d4af0SHarald Freudenberger }
1146*e80d4af0SHarald Freudenberger 
1147*e80d4af0SHarald Freudenberger module_init(pkey_init);
1148*e80d4af0SHarald Freudenberger module_exit(pkey_exit);
1149