Commit | Line | Data |
---|---|---|
efc598e6 HF |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright IBM Corp. 2019 | |
4 | * Author(s): Harald Freudenberger <freude@linux.ibm.com> | |
5 | * Ingo Franzki <ifranzki@linux.ibm.com> | |
6 | * | |
7 | * Collection of CCA misc functions used by zcrypt and pkey | |
8 | */ | |
9 | ||
10 | #define KMSG_COMPONENT "zcrypt" | |
11 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
12 | ||
13 | #include <linux/init.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/slab.h> | |
4bc123b1 | 16 | #include <linux/random.h> |
efc598e6 HF |
17 | #include <asm/zcrypt.h> |
18 | #include <asm/pkey.h> | |
19 | ||
20 | #include "ap_bus.h" | |
21 | #include "zcrypt_api.h" | |
22 | #include "zcrypt_debug.h" | |
23 | #include "zcrypt_msgtype6.h" | |
24 | #include "zcrypt_ccamisc.h" | |
25 | ||
efc598e6 HF |
26 | /* Size of parameter block used for all cca requests/replies */ |
27 | #define PARMBSIZE 512 | |
28 | ||
29 | /* Size of vardata block used for some of the cca requests/replies */ | |
30 | #define VARDATASIZE 4096 | |
31 | ||
94bbd34e | 32 | struct cca_info_list_entry { |
efc598e6 HF |
33 | struct list_head list; |
34 | u16 cardnr; | |
35 | u16 domain; | |
94bbd34e | 36 | struct cca_info info; |
efc598e6 HF |
37 | }; |
38 | ||
94bbd34e HF |
39 | /* a list with cca_info_list_entry entries */ |
40 | static LIST_HEAD(cca_info_list); | |
41 | static DEFINE_SPINLOCK(cca_info_list_lock); | |
efc598e6 HF |
42 | |
43 | /* | |
4bc123b1 | 44 | * Simple check if the token is a valid CCA secure AES data key |
efc598e6 HF |
45 | * token. If keybitsize is given, the bitsize of the key is |
46 | * also checked. Returns 0 on success or errno value on failure. | |
47 | */ | |
48 | int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, | |
49 | const u8 *token, int keybitsize) | |
efc598e6 | 50 | { |
2004b57c | 51 | struct secaeskeytoken *t = (struct secaeskeytoken *)token; |
efc598e6 HF |
52 | |
53 | #define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) | |
54 | ||
55 | if (t->type != TOKTYPE_CCA_INTERNAL) { | |
56 | if (dbg) | |
57 | DBF("%s token check failed, type 0x%02x != 0x%02x\n", | |
2004b57c | 58 | __func__, (int)t->type, TOKTYPE_CCA_INTERNAL); |
efc598e6 HF |
59 | return -EINVAL; |
60 | } | |
61 | if (t->version != TOKVER_CCA_AES) { | |
62 | if (dbg) | |
63 | DBF("%s token check failed, version 0x%02x != 0x%02x\n", | |
2004b57c | 64 | __func__, (int)t->version, TOKVER_CCA_AES); |
efc598e6 HF |
65 | return -EINVAL; |
66 | } | |
67 | if (keybitsize > 0 && t->bitsize != keybitsize) { | |
68 | if (dbg) | |
69 | DBF("%s token check failed, bitsize %d != %d\n", | |
2004b57c | 70 | __func__, (int)t->bitsize, keybitsize); |
efc598e6 HF |
71 | return -EINVAL; |
72 | } | |
73 | ||
74 | #undef DBF | |
75 | ||
76 | return 0; | |
77 | } | |
78 | EXPORT_SYMBOL(cca_check_secaeskeytoken); | |
79 | ||
4bc123b1 HF |
80 | /* |
81 | * Simple check if the token is a valid CCA secure AES cipher key | |
82 | * token. If keybitsize is given, the bitsize of the key is | |
83 | * also checked. If checkcpacfexport is enabled, the key is also | |
84 | * checked for the export flag to allow CPACF export. | |
85 | * Returns 0 on success or errno value on failure. | |
86 | */ | |
87 | int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, | |
88 | const u8 *token, int keybitsize, | |
89 | int checkcpacfexport) | |
90 | { | |
2004b57c | 91 | struct cipherkeytoken *t = (struct cipherkeytoken *)token; |
4bc123b1 HF |
92 | bool keybitsizeok = true; |
93 | ||
94 | #define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) | |
95 | ||
96 | if (t->type != TOKTYPE_CCA_INTERNAL) { | |
97 | if (dbg) | |
98 | DBF("%s token check failed, type 0x%02x != 0x%02x\n", | |
2004b57c | 99 | __func__, (int)t->type, TOKTYPE_CCA_INTERNAL); |
4bc123b1 HF |
100 | return -EINVAL; |
101 | } | |
102 | if (t->version != TOKVER_CCA_VLSC) { | |
103 | if (dbg) | |
104 | DBF("%s token check failed, version 0x%02x != 0x%02x\n", | |
2004b57c | 105 | __func__, (int)t->version, TOKVER_CCA_VLSC); |
4bc123b1 HF |
106 | return -EINVAL; |
107 | } | |
108 | if (t->algtype != 0x02) { | |
109 | if (dbg) | |
110 | DBF("%s token check failed, algtype 0x%02x != 0x02\n", | |
2004b57c | 111 | __func__, (int)t->algtype); |
4bc123b1 HF |
112 | return -EINVAL; |
113 | } | |
114 | if (t->keytype != 0x0001) { | |
115 | if (dbg) | |
116 | DBF("%s token check failed, keytype 0x%04x != 0x0001\n", | |
2004b57c | 117 | __func__, (int)t->keytype); |
4bc123b1 HF |
118 | return -EINVAL; |
119 | } | |
120 | if (t->plfver != 0x00 && t->plfver != 0x01) { | |
121 | if (dbg) | |
122 | DBF("%s token check failed, unknown plfver 0x%02x\n", | |
2004b57c | 123 | __func__, (int)t->plfver); |
4bc123b1 HF |
124 | return -EINVAL; |
125 | } | |
126 | if (t->wpllen != 512 && t->wpllen != 576 && t->wpllen != 640) { | |
127 | if (dbg) | |
128 | DBF("%s token check failed, unknown wpllen %d\n", | |
2004b57c | 129 | __func__, (int)t->wpllen); |
4bc123b1 HF |
130 | return -EINVAL; |
131 | } | |
132 | if (keybitsize > 0) { | |
133 | switch (keybitsize) { | |
134 | case 128: | |
135 | if (t->wpllen != (t->plfver ? 640 : 512)) | |
136 | keybitsizeok = false; | |
137 | break; | |
138 | case 192: | |
139 | if (t->wpllen != (t->plfver ? 640 : 576)) | |
140 | keybitsizeok = false; | |
141 | break; | |
142 | case 256: | |
143 | if (t->wpllen != 640) | |
144 | keybitsizeok = false; | |
145 | break; | |
146 | default: | |
147 | keybitsizeok = false; | |
148 | break; | |
149 | } | |
150 | if (!keybitsizeok) { | |
151 | if (dbg) | |
152 | DBF("%s token check failed, bitsize %d\n", | |
153 | __func__, keybitsize); | |
154 | return -EINVAL; | |
155 | } | |
156 | } | |
157 | if (checkcpacfexport && !(t->kmf1 & KMF1_XPRT_CPAC)) { | |
158 | if (dbg) | |
159 | DBF("%s token check failed, XPRT_CPAC bit is 0\n", | |
160 | __func__); | |
161 | return -EINVAL; | |
162 | } | |
163 | ||
164 | #undef DBF | |
165 | ||
166 | return 0; | |
167 | } | |
168 | EXPORT_SYMBOL(cca_check_secaescipherkey); | |
169 | ||
fa6999e3 HF |
170 | /* |
171 | * Simple check if the token is a valid CCA secure ECC private | |
172 | * key token. Returns 0 on success or errno value on failure. | |
173 | */ | |
174 | int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl, | |
175 | const u8 *token, size_t keysize, | |
176 | int checkcpacfexport) | |
177 | { | |
2004b57c | 178 | struct eccprivkeytoken *t = (struct eccprivkeytoken *)token; |
fa6999e3 HF |
179 | |
180 | #define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) | |
181 | ||
182 | if (t->type != TOKTYPE_CCA_INTERNAL_PKA) { | |
183 | if (dbg) | |
184 | DBF("%s token check failed, type 0x%02x != 0x%02x\n", | |
2004b57c | 185 | __func__, (int)t->type, TOKTYPE_CCA_INTERNAL_PKA); |
fa6999e3 HF |
186 | return -EINVAL; |
187 | } | |
188 | if (t->len > keysize) { | |
189 | if (dbg) | |
190 | DBF("%s token check failed, len %d > keysize %zu\n", | |
2004b57c | 191 | __func__, (int)t->len, keysize); |
fa6999e3 HF |
192 | return -EINVAL; |
193 | } | |
194 | if (t->secid != 0x20) { | |
195 | if (dbg) | |
196 | DBF("%s token check failed, secid 0x%02x != 0x20\n", | |
2004b57c | 197 | __func__, (int)t->secid); |
fa6999e3 HF |
198 | return -EINVAL; |
199 | } | |
200 | if (checkcpacfexport && !(t->kutc & 0x01)) { | |
201 | if (dbg) | |
202 | DBF("%s token check failed, XPRTCPAC bit is 0\n", | |
203 | __func__); | |
204 | return -EINVAL; | |
205 | } | |
206 | ||
207 | #undef DBF | |
208 | ||
209 | return 0; | |
210 | } | |
211 | EXPORT_SYMBOL(cca_check_sececckeytoken); | |
212 | ||
efc598e6 HF |
213 | /* |
214 | * Allocate consecutive memory for request CPRB, request param | |
215 | * block, reply CPRB and reply param block and fill in values | |
216 | * for the common fields. Returns 0 on success or errno value | |
217 | * on failure. | |
218 | */ | |
219 | static int alloc_and_prep_cprbmem(size_t paramblen, | |
2004b57c HF |
220 | u8 **p_cprb_mem, |
221 | struct CPRBX **p_req_cprb, | |
222 | struct CPRBX **p_rep_cprb) | |
efc598e6 HF |
223 | { |
224 | u8 *cprbmem; | |
225 | size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen; | |
226 | struct CPRBX *preqcblk, *prepcblk; | |
227 | ||
228 | /* | |
229 | * allocate consecutive memory for request CPRB, request param | |
230 | * block, reply CPRB and reply param block | |
231 | */ | |
232 | cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL); | |
233 | if (!cprbmem) | |
234 | return -ENOMEM; | |
235 | ||
2004b57c HF |
236 | preqcblk = (struct CPRBX *)cprbmem; |
237 | prepcblk = (struct CPRBX *)(cprbmem + cprbplusparamblen); | |
efc598e6 HF |
238 | |
239 | /* fill request cprb struct */ | |
240 | preqcblk->cprb_len = sizeof(struct CPRBX); | |
241 | preqcblk->cprb_ver_id = 0x02; | |
242 | memcpy(preqcblk->func_id, "T2", 2); | |
243 | preqcblk->rpl_msgbl = cprbplusparamblen; | |
244 | if (paramblen) { | |
245 | preqcblk->req_parmb = | |
2004b57c | 246 | ((u8 __user *)preqcblk) + sizeof(struct CPRBX); |
efc598e6 | 247 | preqcblk->rpl_parmb = |
2004b57c | 248 | ((u8 __user *)prepcblk) + sizeof(struct CPRBX); |
efc598e6 HF |
249 | } |
250 | ||
2004b57c HF |
251 | *p_cprb_mem = cprbmem; |
252 | *p_req_cprb = preqcblk; | |
253 | *p_rep_cprb = prepcblk; | |
efc598e6 HF |
254 | |
255 | return 0; | |
256 | } | |
257 | ||
258 | /* | |
259 | * Free the cprb memory allocated with the function above. | |
260 | * If the scrub value is not zero, the memory is filled | |
261 | * with zeros before freeing (useful if there was some | |
262 | * clear key material in there). | |
263 | */ | |
264 | static void free_cprbmem(void *mem, size_t paramblen, int scrub) | |
265 | { | |
266 | if (scrub) | |
267 | memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen)); | |
268 | kfree(mem); | |
269 | } | |
270 | ||
271 | /* | |
272 | * Helper function to prepare the xcrb struct | |
273 | */ | |
274 | static inline void prep_xcrb(struct ica_xcRB *pxcrb, | |
275 | u16 cardnr, | |
276 | struct CPRBX *preqcblk, | |
277 | struct CPRBX *prepcblk) | |
278 | { | |
279 | memset(pxcrb, 0, sizeof(*pxcrb)); | |
280 | pxcrb->agent_ID = 0x4341; /* 'CA' */ | |
281 | pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr); | |
282 | pxcrb->request_control_blk_length = | |
283 | preqcblk->cprb_len + preqcblk->req_parml; | |
2004b57c | 284 | pxcrb->request_control_blk_addr = (void __user *)preqcblk; |
efc598e6 | 285 | pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl; |
2004b57c | 286 | pxcrb->reply_control_blk_addr = (void __user *)prepcblk; |
efc598e6 HF |
287 | } |
288 | ||
efc598e6 HF |
289 | /* |
290 | * Generate (random) CCA AES DATA secure key. | |
291 | */ | |
292 | int cca_genseckey(u16 cardnr, u16 domain, | |
a237283f | 293 | u32 keybitsize, u8 *seckey) |
efc598e6 HF |
294 | { |
295 | int i, rc, keysize; | |
296 | int seckeysize; | |
74ecbef7 | 297 | u8 *mem, *ptr; |
efc598e6 HF |
298 | struct CPRBX *preqcblk, *prepcblk; |
299 | struct ica_xcRB xcrb; | |
300 | struct kgreqparm { | |
301 | u8 subfunc_code[2]; | |
302 | u16 rule_array_len; | |
303 | struct lv1 { | |
304 | u16 len; | |
305 | char key_form[8]; | |
306 | char key_length[8]; | |
307 | char key_type1[8]; | |
308 | char key_type2[8]; | |
309 | } lv1; | |
310 | struct lv2 { | |
311 | u16 len; | |
312 | struct keyid { | |
313 | u16 len; | |
314 | u16 attr; | |
315 | u8 data[SECKEYBLOBSIZE]; | |
316 | } keyid[6]; | |
317 | } lv2; | |
318 | } __packed * preqparm; | |
319 | struct kgrepparm { | |
320 | u8 subfunc_code[2]; | |
321 | u16 rule_array_len; | |
322 | struct lv3 { | |
323 | u16 len; | |
324 | u16 keyblocklen; | |
325 | struct { | |
326 | u16 toklen; | |
327 | u16 tokattr; | |
2a18a550 | 328 | u8 tok[]; |
efc598e6 HF |
329 | /* ... some more data ... */ |
330 | } keyblock; | |
331 | } lv3; | |
332 | } __packed * prepparm; | |
333 | ||
334 | /* get already prepared memory for 2 cprbs with param block each */ | |
335 | rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); | |
336 | if (rc) | |
337 | return rc; | |
338 | ||
339 | /* fill request cprb struct */ | |
340 | preqcblk->domain = domain; | |
341 | ||
342 | /* fill request cprb param block with KG request */ | |
2004b57c | 343 | preqparm = (struct kgreqparm __force *)preqcblk->req_parmb; |
efc598e6 HF |
344 | memcpy(preqparm->subfunc_code, "KG", 2); |
345 | preqparm->rule_array_len = sizeof(preqparm->rule_array_len); | |
346 | preqparm->lv1.len = sizeof(struct lv1); | |
347 | memcpy(preqparm->lv1.key_form, "OP ", 8); | |
f2bbc96e HF |
348 | switch (keybitsize) { |
349 | case PKEY_SIZE_AES_128: | |
350 | case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ | |
efc598e6 HF |
351 | keysize = 16; |
352 | memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); | |
353 | break; | |
f2bbc96e HF |
354 | case PKEY_SIZE_AES_192: |
355 | case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ | |
efc598e6 HF |
356 | keysize = 24; |
357 | memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); | |
358 | break; | |
f2bbc96e HF |
359 | case PKEY_SIZE_AES_256: |
360 | case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ | |
efc598e6 HF |
361 | keysize = 32; |
362 | memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); | |
363 | break; | |
364 | default: | |
88e4c0da HF |
365 | ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n", |
366 | __func__, keybitsize); | |
efc598e6 HF |
367 | rc = -EINVAL; |
368 | goto out; | |
369 | } | |
370 | memcpy(preqparm->lv1.key_type1, "AESDATA ", 8); | |
371 | preqparm->lv2.len = sizeof(struct lv2); | |
372 | for (i = 0; i < 6; i++) { | |
373 | preqparm->lv2.keyid[i].len = sizeof(struct keyid); | |
374 | preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10); | |
375 | } | |
376 | preqcblk->req_parml = sizeof(struct kgreqparm); | |
377 | ||
378 | /* fill xcrb struct */ | |
379 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
380 | ||
381 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
52f72feb | 382 | rc = zcrypt_send_cprb(&xcrb); |
efc598e6 | 383 | if (rc) { |
88e4c0da HF |
384 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n", |
385 | __func__, (int)cardnr, (int)domain, rc); | |
efc598e6 HF |
386 | goto out; |
387 | } | |
388 | ||
389 | /* check response returncode and reasoncode */ | |
390 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
391 | ZCRYPT_DBF_ERR("%s secure key generate failure, card response %d/%d\n", |
392 | __func__, | |
2004b57c HF |
393 | (int)prepcblk->ccp_rtcode, |
394 | (int)prepcblk->ccp_rscode); | |
efc598e6 HF |
395 | rc = -EIO; |
396 | goto out; | |
397 | } | |
398 | ||
399 | /* process response cprb param block */ | |
2004b57c HF |
400 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
401 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
402 | prepparm = (struct kgrepparm *)ptr; | |
efc598e6 HF |
403 | |
404 | /* check length of the returned secure key token */ | |
405 | seckeysize = prepparm->lv3.keyblock.toklen | |
406 | - sizeof(prepparm->lv3.keyblock.toklen) | |
407 | - sizeof(prepparm->lv3.keyblock.tokattr); | |
408 | if (seckeysize != SECKEYBLOBSIZE) { | |
88e4c0da HF |
409 | ZCRYPT_DBF_ERR("%s secure token size mismatch %d != %d bytes\n", |
410 | __func__, seckeysize, SECKEYBLOBSIZE); | |
efc598e6 HF |
411 | rc = -EIO; |
412 | goto out; | |
413 | } | |
414 | ||
415 | /* check secure key token */ | |
416 | rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, | |
2004b57c | 417 | prepparm->lv3.keyblock.tok, 8 * keysize); |
efc598e6 HF |
418 | if (rc) { |
419 | rc = -EIO; | |
420 | goto out; | |
421 | } | |
422 | ||
423 | /* copy the generated secure key token */ | |
424 | memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); | |
425 | ||
426 | out: | |
427 | free_cprbmem(mem, PARMBSIZE, 0); | |
428 | return rc; | |
429 | } | |
430 | EXPORT_SYMBOL(cca_genseckey); | |
431 | ||
432 | /* | |
433 | * Generate an CCA AES DATA secure key with given key value. | |
434 | */ | |
f2bbc96e | 435 | int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, |
a237283f | 436 | const u8 *clrkey, u8 *seckey) |
efc598e6 HF |
437 | { |
438 | int rc, keysize, seckeysize; | |
74ecbef7 | 439 | u8 *mem, *ptr; |
efc598e6 HF |
440 | struct CPRBX *preqcblk, *prepcblk; |
441 | struct ica_xcRB xcrb; | |
442 | struct cmreqparm { | |
443 | u8 subfunc_code[2]; | |
444 | u16 rule_array_len; | |
445 | char rule_array[8]; | |
446 | struct lv1 { | |
447 | u16 len; | |
3b42877c | 448 | u8 clrkey[]; |
efc598e6 | 449 | } lv1; |
3b42877c | 450 | /* followed by struct lv2 */ |
efc598e6 | 451 | } __packed * preqparm; |
3b42877c HF |
452 | struct lv2 { |
453 | u16 len; | |
454 | struct keyid { | |
455 | u16 len; | |
456 | u16 attr; | |
457 | u8 data[SECKEYBLOBSIZE]; | |
458 | } keyid; | |
459 | } __packed * plv2; | |
efc598e6 HF |
460 | struct cmrepparm { |
461 | u8 subfunc_code[2]; | |
462 | u16 rule_array_len; | |
463 | struct lv3 { | |
464 | u16 len; | |
465 | u16 keyblocklen; | |
466 | struct { | |
467 | u16 toklen; | |
468 | u16 tokattr; | |
2a18a550 | 469 | u8 tok[]; |
efc598e6 HF |
470 | /* ... some more data ... */ |
471 | } keyblock; | |
472 | } lv3; | |
473 | } __packed * prepparm; | |
474 | ||
475 | /* get already prepared memory for 2 cprbs with param block each */ | |
476 | rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); | |
477 | if (rc) | |
478 | return rc; | |
479 | ||
480 | /* fill request cprb struct */ | |
481 | preqcblk->domain = domain; | |
482 | ||
483 | /* fill request cprb param block with CM request */ | |
2004b57c | 484 | preqparm = (struct cmreqparm __force *)preqcblk->req_parmb; |
efc598e6 HF |
485 | memcpy(preqparm->subfunc_code, "CM", 2); |
486 | memcpy(preqparm->rule_array, "AES ", 8); | |
487 | preqparm->rule_array_len = | |
488 | sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); | |
f2bbc96e HF |
489 | switch (keybitsize) { |
490 | case PKEY_SIZE_AES_128: | |
491 | case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ | |
efc598e6 HF |
492 | keysize = 16; |
493 | break; | |
f2bbc96e HF |
494 | case PKEY_SIZE_AES_192: |
495 | case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ | |
efc598e6 HF |
496 | keysize = 24; |
497 | break; | |
f2bbc96e HF |
498 | case PKEY_SIZE_AES_256: |
499 | case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ | |
efc598e6 HF |
500 | keysize = 32; |
501 | break; | |
502 | default: | |
88e4c0da HF |
503 | ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n", |
504 | __func__, keybitsize); | |
efc598e6 HF |
505 | rc = -EINVAL; |
506 | goto out; | |
507 | } | |
508 | preqparm->lv1.len = sizeof(struct lv1) + keysize; | |
509 | memcpy(preqparm->lv1.clrkey, clrkey, keysize); | |
3b42877c | 510 | plv2 = (struct lv2 *)(((u8 *)preqparm) + sizeof(*preqparm) + keysize); |
efc598e6 HF |
511 | plv2->len = sizeof(struct lv2); |
512 | plv2->keyid.len = sizeof(struct keyid); | |
513 | plv2->keyid.attr = 0x30; | |
3b42877c | 514 | preqcblk->req_parml = sizeof(*preqparm) + keysize + sizeof(*plv2); |
efc598e6 HF |
515 | |
516 | /* fill xcrb struct */ | |
517 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
518 | ||
519 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
52f72feb | 520 | rc = zcrypt_send_cprb(&xcrb); |
efc598e6 | 521 | if (rc) { |
88e4c0da HF |
522 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", |
523 | __func__, (int)cardnr, (int)domain, rc); | |
efc598e6 HF |
524 | goto out; |
525 | } | |
526 | ||
527 | /* check response returncode and reasoncode */ | |
528 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
529 | ZCRYPT_DBF_ERR("%s clear key import failure, card response %d/%d\n", |
530 | __func__, | |
531 | (int)prepcblk->ccp_rtcode, | |
532 | (int)prepcblk->ccp_rscode); | |
efc598e6 HF |
533 | rc = -EIO; |
534 | goto out; | |
535 | } | |
536 | ||
537 | /* process response cprb param block */ | |
2004b57c HF |
538 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
539 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
540 | prepparm = (struct cmrepparm *)ptr; | |
efc598e6 HF |
541 | |
542 | /* check length of the returned secure key token */ | |
543 | seckeysize = prepparm->lv3.keyblock.toklen | |
544 | - sizeof(prepparm->lv3.keyblock.toklen) | |
545 | - sizeof(prepparm->lv3.keyblock.tokattr); | |
546 | if (seckeysize != SECKEYBLOBSIZE) { | |
88e4c0da HF |
547 | ZCRYPT_DBF_ERR("%s secure token size mismatch %d != %d bytes\n", |
548 | __func__, seckeysize, SECKEYBLOBSIZE); | |
efc598e6 HF |
549 | rc = -EIO; |
550 | goto out; | |
551 | } | |
552 | ||
553 | /* check secure key token */ | |
554 | rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, | |
2004b57c | 555 | prepparm->lv3.keyblock.tok, 8 * keysize); |
efc598e6 HF |
556 | if (rc) { |
557 | rc = -EIO; | |
558 | goto out; | |
559 | } | |
560 | ||
561 | /* copy the generated secure key token */ | |
4bc123b1 HF |
562 | if (seckey) |
563 | memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); | |
efc598e6 HF |
564 | |
565 | out: | |
566 | free_cprbmem(mem, PARMBSIZE, 1); | |
567 | return rc; | |
568 | } | |
569 | EXPORT_SYMBOL(cca_clr2seckey); | |
570 | ||
571 | /* | |
572 | * Derive proteced key from an CCA AES DATA secure key. | |
573 | */ | |
574 | int cca_sec2protkey(u16 cardnr, u16 domain, | |
a237283f SS |
575 | const u8 *seckey, u8 *protkey, u32 *protkeylen, |
576 | u32 *protkeytype) | |
efc598e6 HF |
577 | { |
578 | int rc; | |
74ecbef7 | 579 | u8 *mem, *ptr; |
efc598e6 HF |
580 | struct CPRBX *preqcblk, *prepcblk; |
581 | struct ica_xcRB xcrb; | |
582 | struct uskreqparm { | |
583 | u8 subfunc_code[2]; | |
584 | u16 rule_array_len; | |
585 | struct lv1 { | |
586 | u16 len; | |
587 | u16 attr_len; | |
588 | u16 attr_flags; | |
589 | } lv1; | |
590 | struct lv2 { | |
591 | u16 len; | |
592 | u16 attr_len; | |
593 | u16 attr_flags; | |
2a18a550 | 594 | u8 token[]; /* cca secure key token */ |
efc598e6 HF |
595 | } lv2; |
596 | } __packed * preqparm; | |
597 | struct uskrepparm { | |
598 | u8 subfunc_code[2]; | |
599 | u16 rule_array_len; | |
600 | struct lv3 { | |
601 | u16 len; | |
602 | u16 attr_len; | |
603 | u16 attr_flags; | |
604 | struct cpacfkeyblock { | |
605 | u8 version; /* version of this struct */ | |
606 | u8 flags[2]; | |
607 | u8 algo; | |
608 | u8 form; | |
609 | u8 pad1[3]; | |
610 | u16 len; | |
611 | u8 key[64]; /* the key (len bytes) */ | |
612 | u16 keyattrlen; | |
613 | u8 keyattr[32]; | |
614 | u8 pad2[1]; | |
615 | u8 vptype; | |
616 | u8 vp[32]; /* verification pattern */ | |
c4f762ff | 617 | } ckb; |
efc598e6 HF |
618 | } lv3; |
619 | } __packed * prepparm; | |
620 | ||
621 | /* get already prepared memory for 2 cprbs with param block each */ | |
622 | rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); | |
623 | if (rc) | |
624 | return rc; | |
625 | ||
626 | /* fill request cprb struct */ | |
627 | preqcblk->domain = domain; | |
628 | ||
629 | /* fill request cprb param block with USK request */ | |
2004b57c | 630 | preqparm = (struct uskreqparm __force *)preqcblk->req_parmb; |
efc598e6 HF |
631 | memcpy(preqparm->subfunc_code, "US", 2); |
632 | preqparm->rule_array_len = sizeof(preqparm->rule_array_len); | |
633 | preqparm->lv1.len = sizeof(struct lv1); | |
634 | preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len); | |
635 | preqparm->lv1.attr_flags = 0x0001; | |
636 | preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE; | |
637 | preqparm->lv2.attr_len = sizeof(struct lv2) | |
638 | - sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE; | |
639 | preqparm->lv2.attr_flags = 0x0000; | |
640 | memcpy(preqparm->lv2.token, seckey, SECKEYBLOBSIZE); | |
641 | preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE; | |
642 | ||
643 | /* fill xcrb struct */ | |
644 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
645 | ||
646 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
52f72feb | 647 | rc = zcrypt_send_cprb(&xcrb); |
efc598e6 | 648 | if (rc) { |
88e4c0da HF |
649 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", |
650 | __func__, (int)cardnr, (int)domain, rc); | |
efc598e6 HF |
651 | goto out; |
652 | } | |
653 | ||
654 | /* check response returncode and reasoncode */ | |
655 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
656 | ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n", |
657 | __func__, | |
658 | (int)prepcblk->ccp_rtcode, | |
659 | (int)prepcblk->ccp_rscode); | |
1daafea4 | 660 | if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290) |
da565832 | 661 | rc = -EBUSY; |
1daafea4 HF |
662 | else |
663 | rc = -EIO; | |
efc598e6 HF |
664 | goto out; |
665 | } | |
666 | if (prepcblk->ccp_rscode != 0) { | |
88e4c0da HF |
667 | ZCRYPT_DBF_WARN("%s unwrap secure key warning, card response %d/%d\n", |
668 | __func__, | |
669 | (int)prepcblk->ccp_rtcode, | |
670 | (int)prepcblk->ccp_rscode); | |
efc598e6 HF |
671 | } |
672 | ||
673 | /* process response cprb param block */ | |
2004b57c HF |
674 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
675 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
676 | prepparm = (struct uskrepparm *)ptr; | |
efc598e6 HF |
677 | |
678 | /* check the returned keyblock */ | |
c4f762ff HF |
679 | if (prepparm->lv3.ckb.version != 0x01 && |
680 | prepparm->lv3.ckb.version != 0x02) { | |
88e4c0da HF |
681 | ZCRYPT_DBF_ERR("%s reply param keyblock version mismatch 0x%02x\n", |
682 | __func__, (int)prepparm->lv3.ckb.version); | |
efc598e6 HF |
683 | rc = -EIO; |
684 | goto out; | |
685 | } | |
686 | ||
cada938a | 687 | /* copy the translated protected key */ |
c4f762ff | 688 | switch (prepparm->lv3.ckb.len) { |
2004b57c | 689 | case 16 + 32: |
efc598e6 | 690 | /* AES 128 protected key */ |
f2bbc96e HF |
691 | if (protkeytype) |
692 | *protkeytype = PKEY_KEYTYPE_AES_128; | |
efc598e6 | 693 | break; |
2004b57c | 694 | case 24 + 32: |
efc598e6 | 695 | /* AES 192 protected key */ |
f2bbc96e HF |
696 | if (protkeytype) |
697 | *protkeytype = PKEY_KEYTYPE_AES_192; | |
efc598e6 | 698 | break; |
2004b57c | 699 | case 32 + 32: |
efc598e6 | 700 | /* AES 256 protected key */ |
f2bbc96e HF |
701 | if (protkeytype) |
702 | *protkeytype = PKEY_KEYTYPE_AES_256; | |
efc598e6 HF |
703 | break; |
704 | default: | |
88e4c0da HF |
705 | ZCRYPT_DBF_ERR("%s unknown/unsupported keylen %d\n", |
706 | __func__, prepparm->lv3.ckb.len); | |
efc598e6 HF |
707 | rc = -EIO; |
708 | goto out; | |
709 | } | |
c4f762ff | 710 | memcpy(protkey, prepparm->lv3.ckb.key, prepparm->lv3.ckb.len); |
efc598e6 | 711 | if (protkeylen) |
c4f762ff | 712 | *protkeylen = prepparm->lv3.ckb.len; |
efc598e6 HF |
713 | |
714 | out: | |
715 | free_cprbmem(mem, PARMBSIZE, 0); | |
716 | return rc; | |
717 | } | |
718 | EXPORT_SYMBOL(cca_sec2protkey); | |
719 | ||
4bc123b1 HF |
720 | /* |
721 | * AES cipher key skeleton created with CSNBKTB2 with these flags: | |
722 | * INTERNAL, NO-KEY, AES, CIPHER, ANY-MODE, NOEX-SYM, NOEXAASY, | |
723 | * NOEXUASY, XPRTCPAC, NOEX-RAW, NOEX-DES, NOEX-AES, NOEX-RSA | |
724 | * used by cca_gencipherkey() and cca_clr2cipherkey(). | |
725 | */ | |
726 | static const u8 aes_cipher_key_skeleton[] = { | |
727 | 0x01, 0x00, 0x00, 0x38, 0x05, 0x00, 0x00, 0x00, | |
728 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
729 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
730 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, | |
731 | 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
732 | 0x00, 0x02, 0x00, 0x01, 0x02, 0xc0, 0x00, 0xff, | |
733 | 0x00, 0x03, 0x08, 0xc8, 0x00, 0x00, 0x00, 0x00 }; | |
734 | #define SIZEOF_SKELETON (sizeof(aes_cipher_key_skeleton)) | |
735 | ||
736 | /* | |
737 | * Generate (random) CCA AES CIPHER secure key. | |
738 | */ | |
739 | int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, | |
740 | u8 *keybuf, size_t *keybufsize) | |
741 | { | |
742 | int rc; | |
74ecbef7 | 743 | u8 *mem, *ptr; |
4bc123b1 HF |
744 | struct CPRBX *preqcblk, *prepcblk; |
745 | struct ica_xcRB xcrb; | |
746 | struct gkreqparm { | |
747 | u8 subfunc_code[2]; | |
748 | u16 rule_array_len; | |
2004b57c | 749 | char rule_array[2 * 8]; |
4bc123b1 HF |
750 | struct { |
751 | u16 len; | |
752 | u8 key_type_1[8]; | |
753 | u8 key_type_2[8]; | |
754 | u16 clear_key_bit_len; | |
755 | u16 key_name_1_len; | |
756 | u16 key_name_2_len; | |
757 | u16 user_data_1_len; | |
758 | u16 user_data_2_len; | |
3b42877c HF |
759 | /* u8 key_name_1[]; */ |
760 | /* u8 key_name_2[]; */ | |
761 | /* u8 user_data_1[]; */ | |
762 | /* u8 user_data_2[]; */ | |
4bc123b1 HF |
763 | } vud; |
764 | struct { | |
765 | u16 len; | |
766 | struct { | |
767 | u16 len; | |
768 | u16 flag; | |
3b42877c | 769 | /* u8 kek_id_1[]; */ |
4bc123b1 HF |
770 | } tlv1; |
771 | struct { | |
772 | u16 len; | |
773 | u16 flag; | |
3b42877c | 774 | /* u8 kek_id_2[]; */ |
4bc123b1 HF |
775 | } tlv2; |
776 | struct { | |
777 | u16 len; | |
778 | u16 flag; | |
779 | u8 gen_key_id_1[SIZEOF_SKELETON]; | |
780 | } tlv3; | |
781 | struct { | |
782 | u16 len; | |
783 | u16 flag; | |
3b42877c | 784 | /* u8 gen_key_id_1_label[]; */ |
4bc123b1 HF |
785 | } tlv4; |
786 | struct { | |
787 | u16 len; | |
788 | u16 flag; | |
3b42877c | 789 | /* u8 gen_key_id_2[]; */ |
4bc123b1 HF |
790 | } tlv5; |
791 | struct { | |
792 | u16 len; | |
793 | u16 flag; | |
3b42877c | 794 | /* u8 gen_key_id_2_label[]; */ |
4bc123b1 HF |
795 | } tlv6; |
796 | } kb; | |
797 | } __packed * preqparm; | |
798 | struct gkrepparm { | |
799 | u8 subfunc_code[2]; | |
800 | u16 rule_array_len; | |
801 | struct { | |
802 | u16 len; | |
803 | } vud; | |
804 | struct { | |
805 | u16 len; | |
806 | struct { | |
807 | u16 len; | |
808 | u16 flag; | |
3b42877c | 809 | u8 gen_key[]; /* 120-136 bytes */ |
4bc123b1 HF |
810 | } tlv1; |
811 | } kb; | |
812 | } __packed * prepparm; | |
813 | struct cipherkeytoken *t; | |
814 | ||
815 | /* get already prepared memory for 2 cprbs with param block each */ | |
816 | rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); | |
817 | if (rc) | |
818 | return rc; | |
819 | ||
820 | /* fill request cprb struct */ | |
821 | preqcblk->domain = domain; | |
822 | preqcblk->req_parml = sizeof(struct gkreqparm); | |
823 | ||
824 | /* prepare request param block with GK request */ | |
2004b57c | 825 | preqparm = (struct gkreqparm __force *)preqcblk->req_parmb; |
4bc123b1 HF |
826 | memcpy(preqparm->subfunc_code, "GK", 2); |
827 | preqparm->rule_array_len = sizeof(uint16_t) + 2 * 8; | |
2004b57c | 828 | memcpy(preqparm->rule_array, "AES OP ", 2 * 8); |
4bc123b1 HF |
829 | |
830 | /* prepare vud block */ | |
831 | preqparm->vud.len = sizeof(preqparm->vud); | |
832 | switch (keybitsize) { | |
833 | case 128: | |
834 | case 192: | |
835 | case 256: | |
836 | break; | |
837 | default: | |
88e4c0da HF |
838 | ZCRYPT_DBF_ERR("%s unknown/unsupported keybitsize %d\n", |
839 | __func__, keybitsize); | |
4bc123b1 HF |
840 | rc = -EINVAL; |
841 | goto out; | |
842 | } | |
843 | preqparm->vud.clear_key_bit_len = keybitsize; | |
844 | memcpy(preqparm->vud.key_type_1, "TOKEN ", 8); | |
845 | memset(preqparm->vud.key_type_2, ' ', sizeof(preqparm->vud.key_type_2)); | |
846 | ||
847 | /* prepare kb block */ | |
848 | preqparm->kb.len = sizeof(preqparm->kb); | |
849 | preqparm->kb.tlv1.len = sizeof(preqparm->kb.tlv1); | |
850 | preqparm->kb.tlv1.flag = 0x0030; | |
851 | preqparm->kb.tlv2.len = sizeof(preqparm->kb.tlv2); | |
852 | preqparm->kb.tlv2.flag = 0x0030; | |
853 | preqparm->kb.tlv3.len = sizeof(preqparm->kb.tlv3); | |
854 | preqparm->kb.tlv3.flag = 0x0030; | |
855 | memcpy(preqparm->kb.tlv3.gen_key_id_1, | |
856 | aes_cipher_key_skeleton, SIZEOF_SKELETON); | |
857 | preqparm->kb.tlv4.len = sizeof(preqparm->kb.tlv4); | |
858 | preqparm->kb.tlv4.flag = 0x0030; | |
859 | preqparm->kb.tlv5.len = sizeof(preqparm->kb.tlv5); | |
860 | preqparm->kb.tlv5.flag = 0x0030; | |
861 | preqparm->kb.tlv6.len = sizeof(preqparm->kb.tlv6); | |
862 | preqparm->kb.tlv6.flag = 0x0030; | |
863 | ||
864 | /* patch the skeleton key token export flags inside the kb block */ | |
865 | if (keygenflags) { | |
2004b57c HF |
866 | t = (struct cipherkeytoken *)preqparm->kb.tlv3.gen_key_id_1; |
867 | t->kmf1 |= (u16)(keygenflags & 0x0000FF00); | |
868 | t->kmf1 &= (u16)~(keygenflags & 0x000000FF); | |
4bc123b1 HF |
869 | } |
870 | ||
871 | /* prepare xcrb struct */ | |
872 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
873 | ||
874 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
52f72feb | 875 | rc = zcrypt_send_cprb(&xcrb); |
4bc123b1 | 876 | if (rc) { |
88e4c0da HF |
877 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", |
878 | __func__, (int)cardnr, (int)domain, rc); | |
4bc123b1 HF |
879 | goto out; |
880 | } | |
881 | ||
882 | /* check response returncode and reasoncode */ | |
883 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
884 | ZCRYPT_DBF_ERR("%s cipher key generate failure, card response %d/%d\n", |
885 | __func__, | |
886 | (int)prepcblk->ccp_rtcode, | |
887 | (int)prepcblk->ccp_rscode); | |
4bc123b1 HF |
888 | rc = -EIO; |
889 | goto out; | |
890 | } | |
891 | ||
892 | /* process response cprb param block */ | |
2004b57c HF |
893 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
894 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
895 | prepparm = (struct gkrepparm *)ptr; | |
4bc123b1 HF |
896 | |
897 | /* do some plausibility checks on the key block */ | |
898 | if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) || | |
899 | prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) { | |
88e4c0da HF |
900 | ZCRYPT_DBF_ERR("%s reply with invalid or unknown key block\n", |
901 | __func__); | |
4bc123b1 HF |
902 | rc = -EIO; |
903 | goto out; | |
904 | } | |
905 | ||
906 | /* and some checks on the generated key */ | |
907 | rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR, | |
908 | prepparm->kb.tlv1.gen_key, | |
909 | keybitsize, 1); | |
910 | if (rc) { | |
911 | rc = -EIO; | |
912 | goto out; | |
913 | } | |
914 | ||
915 | /* copy the generated vlsc key token */ | |
2004b57c | 916 | t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key; |
4bc123b1 HF |
917 | if (keybuf) { |
918 | if (*keybufsize >= t->len) | |
919 | memcpy(keybuf, t, t->len); | |
920 | else | |
921 | rc = -EINVAL; | |
922 | } | |
923 | *keybufsize = t->len; | |
924 | ||
925 | out: | |
926 | free_cprbmem(mem, PARMBSIZE, 0); | |
927 | return rc; | |
928 | } | |
929 | EXPORT_SYMBOL(cca_gencipherkey); | |
930 | ||
931 | /* | |
932 | * Helper function, does a the CSNBKPI2 CPRB. | |
933 | */ | |
934 | static int _ip_cprb_helper(u16 cardnr, u16 domain, | |
935 | const char *rule_array_1, | |
936 | const char *rule_array_2, | |
937 | const char *rule_array_3, | |
938 | const u8 *clr_key_value, | |
939 | int clr_key_bit_size, | |
940 | u8 *key_token, | |
941 | int *key_token_size) | |
942 | { | |
943 | int rc, n; | |
74ecbef7 | 944 | u8 *mem, *ptr; |
4bc123b1 HF |
945 | struct CPRBX *preqcblk, *prepcblk; |
946 | struct ica_xcRB xcrb; | |
947 | struct rule_array_block { | |
948 | u8 subfunc_code[2]; | |
949 | u16 rule_array_len; | |
3b42877c | 950 | char rule_array[]; |
4bc123b1 HF |
951 | } __packed * preq_ra_block; |
952 | struct vud_block { | |
953 | u16 len; | |
954 | struct { | |
955 | u16 len; | |
956 | u16 flag; /* 0x0064 */ | |
957 | u16 clr_key_bit_len; | |
958 | } tlv1; | |
959 | struct { | |
960 | u16 len; | |
961 | u16 flag; /* 0x0063 */ | |
3b42877c | 962 | u8 clr_key[]; /* clear key value bytes */ |
4bc123b1 HF |
963 | } tlv2; |
964 | } __packed * preq_vud_block; | |
965 | struct key_block { | |
966 | u16 len; | |
967 | struct { | |
968 | u16 len; | |
969 | u16 flag; /* 0x0030 */ | |
3b42877c | 970 | u8 key_token[]; /* key skeleton */ |
4bc123b1 HF |
971 | } tlv1; |
972 | } __packed * preq_key_block; | |
973 | struct iprepparm { | |
974 | u8 subfunc_code[2]; | |
975 | u16 rule_array_len; | |
976 | struct { | |
977 | u16 len; | |
978 | } vud; | |
979 | struct { | |
980 | u16 len; | |
981 | struct { | |
982 | u16 len; | |
983 | u16 flag; /* 0x0030 */ | |
3b42877c | 984 | u8 key_token[]; /* key token */ |
4bc123b1 HF |
985 | } tlv1; |
986 | } kb; | |
987 | } __packed * prepparm; | |
988 | struct cipherkeytoken *t; | |
989 | int complete = strncmp(rule_array_2, "COMPLETE", 8) ? 0 : 1; | |
990 | ||
991 | /* get already prepared memory for 2 cprbs with param block each */ | |
992 | rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); | |
993 | if (rc) | |
994 | return rc; | |
995 | ||
996 | /* fill request cprb struct */ | |
997 | preqcblk->domain = domain; | |
998 | preqcblk->req_parml = 0; | |
999 | ||
1000 | /* prepare request param block with IP request */ | |
2004b57c | 1001 | preq_ra_block = (struct rule_array_block __force *)preqcblk->req_parmb; |
4bc123b1 HF |
1002 | memcpy(preq_ra_block->subfunc_code, "IP", 2); |
1003 | preq_ra_block->rule_array_len = sizeof(uint16_t) + 2 * 8; | |
1004 | memcpy(preq_ra_block->rule_array, rule_array_1, 8); | |
1005 | memcpy(preq_ra_block->rule_array + 8, rule_array_2, 8); | |
1006 | preqcblk->req_parml = sizeof(struct rule_array_block) + 2 * 8; | |
1007 | if (rule_array_3) { | |
1008 | preq_ra_block->rule_array_len += 8; | |
1009 | memcpy(preq_ra_block->rule_array + 16, rule_array_3, 8); | |
1010 | preqcblk->req_parml += 8; | |
1011 | } | |
1012 | ||
1013 | /* prepare vud block */ | |
74ecbef7 | 1014 | preq_vud_block = (struct vud_block __force *) |
4bc123b1 HF |
1015 | (preqcblk->req_parmb + preqcblk->req_parml); |
1016 | n = complete ? 0 : (clr_key_bit_size + 7) / 8; | |
1017 | preq_vud_block->len = sizeof(struct vud_block) + n; | |
1018 | preq_vud_block->tlv1.len = sizeof(preq_vud_block->tlv1); | |
1019 | preq_vud_block->tlv1.flag = 0x0064; | |
1020 | preq_vud_block->tlv1.clr_key_bit_len = complete ? 0 : clr_key_bit_size; | |
1021 | preq_vud_block->tlv2.len = sizeof(preq_vud_block->tlv2) + n; | |
1022 | preq_vud_block->tlv2.flag = 0x0063; | |
1023 | if (!complete) | |
1024 | memcpy(preq_vud_block->tlv2.clr_key, clr_key_value, n); | |
1025 | preqcblk->req_parml += preq_vud_block->len; | |
1026 | ||
1027 | /* prepare key block */ | |
74ecbef7 | 1028 | preq_key_block = (struct key_block __force *) |
4bc123b1 HF |
1029 | (preqcblk->req_parmb + preqcblk->req_parml); |
1030 | n = *key_token_size; | |
1031 | preq_key_block->len = sizeof(struct key_block) + n; | |
1032 | preq_key_block->tlv1.len = sizeof(preq_key_block->tlv1) + n; | |
1033 | preq_key_block->tlv1.flag = 0x0030; | |
1034 | memcpy(preq_key_block->tlv1.key_token, key_token, *key_token_size); | |
1035 | preqcblk->req_parml += preq_key_block->len; | |
1036 | ||
1037 | /* prepare xcrb struct */ | |
1038 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
1039 | ||
1040 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
52f72feb | 1041 | rc = zcrypt_send_cprb(&xcrb); |
4bc123b1 | 1042 | if (rc) { |
88e4c0da HF |
1043 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", |
1044 | __func__, (int)cardnr, (int)domain, rc); | |
4bc123b1 HF |
1045 | goto out; |
1046 | } | |
1047 | ||
1048 | /* check response returncode and reasoncode */ | |
1049 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
1050 | ZCRYPT_DBF_ERR("%s CSNBKPI2 failure, card response %d/%d\n", |
1051 | __func__, | |
1052 | (int)prepcblk->ccp_rtcode, | |
1053 | (int)prepcblk->ccp_rscode); | |
4bc123b1 HF |
1054 | rc = -EIO; |
1055 | goto out; | |
1056 | } | |
1057 | ||
1058 | /* process response cprb param block */ | |
2004b57c HF |
1059 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
1060 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
1061 | prepparm = (struct iprepparm *)ptr; | |
4bc123b1 HF |
1062 | |
1063 | /* do some plausibility checks on the key block */ | |
94dd3bad HF |
1064 | if (prepparm->kb.len < 120 + 3 * sizeof(uint16_t) || |
1065 | prepparm->kb.len > 136 + 3 * sizeof(uint16_t)) { | |
88e4c0da HF |
1066 | ZCRYPT_DBF_ERR("%s reply with invalid or unknown key block\n", |
1067 | __func__); | |
4bc123b1 HF |
1068 | rc = -EIO; |
1069 | goto out; | |
1070 | } | |
1071 | ||
1072 | /* do not check the key here, it may be incomplete */ | |
1073 | ||
1074 | /* copy the vlsc key token back */ | |
2004b57c | 1075 | t = (struct cipherkeytoken *)prepparm->kb.tlv1.key_token; |
4bc123b1 HF |
1076 | memcpy(key_token, t, t->len); |
1077 | *key_token_size = t->len; | |
1078 | ||
1079 | out: | |
1080 | free_cprbmem(mem, PARMBSIZE, 0); | |
1081 | return rc; | |
1082 | } | |
1083 | ||
1084 | /* | |
1085 | * Build CCA AES CIPHER secure key with a given clear key value. | |
1086 | */ | |
1087 | int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, | |
1088 | const u8 *clrkey, u8 *keybuf, size_t *keybufsize) | |
1089 | { | |
1090 | int rc; | |
1091 | u8 *token; | |
1092 | int tokensize; | |
1093 | u8 exorbuf[32]; | |
1094 | struct cipherkeytoken *t; | |
1095 | ||
1096 | /* fill exorbuf with random data */ | |
1097 | get_random_bytes(exorbuf, sizeof(exorbuf)); | |
1098 | ||
1099 | /* allocate space for the key token to build */ | |
1100 | token = kmalloc(MAXCCAVLSCTOKENSIZE, GFP_KERNEL); | |
1101 | if (!token) | |
1102 | return -ENOMEM; | |
1103 | ||
1104 | /* prepare the token with the key skeleton */ | |
1105 | tokensize = SIZEOF_SKELETON; | |
1106 | memcpy(token, aes_cipher_key_skeleton, tokensize); | |
1107 | ||
1108 | /* patch the skeleton key token export flags */ | |
1109 | if (keygenflags) { | |
2004b57c HF |
1110 | t = (struct cipherkeytoken *)token; |
1111 | t->kmf1 |= (u16)(keygenflags & 0x0000FF00); | |
1112 | t->kmf1 &= (u16)~(keygenflags & 0x000000FF); | |
4bc123b1 HF |
1113 | } |
1114 | ||
1115 | /* | |
1116 | * Do the key import with the clear key value in 4 steps: | |
1117 | * 1/4 FIRST import with only random data | |
1118 | * 2/4 EXOR the clear key | |
1119 | * 3/4 EXOR the very same random data again | |
1120 | * 4/4 COMPLETE the secure cipher key import | |
1121 | */ | |
1122 | rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART", | |
1123 | exorbuf, keybitsize, token, &tokensize); | |
1124 | if (rc) { | |
88e4c0da HF |
1125 | ZCRYPT_DBF_ERR("%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n", |
1126 | __func__, rc); | |
4bc123b1 HF |
1127 | goto out; |
1128 | } | |
1129 | rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, | |
1130 | clrkey, keybitsize, token, &tokensize); | |
1131 | if (rc) { | |
88e4c0da HF |
1132 | ZCRYPT_DBF_ERR("%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n", |
1133 | __func__, rc); | |
4bc123b1 HF |
1134 | goto out; |
1135 | } | |
1136 | rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, | |
1137 | exorbuf, keybitsize, token, &tokensize); | |
1138 | if (rc) { | |
88e4c0da HF |
1139 | ZCRYPT_DBF_ERR("%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n", |
1140 | __func__, rc); | |
4bc123b1 HF |
1141 | goto out; |
1142 | } | |
1143 | rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL, | |
1144 | NULL, keybitsize, token, &tokensize); | |
1145 | if (rc) { | |
88e4c0da HF |
1146 | ZCRYPT_DBF_ERR("%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n", |
1147 | __func__, rc); | |
4bc123b1 HF |
1148 | goto out; |
1149 | } | |
1150 | ||
1151 | /* copy the generated key token */ | |
1152 | if (keybuf) { | |
1153 | if (tokensize > *keybufsize) | |
1154 | rc = -EINVAL; | |
1155 | else | |
1156 | memcpy(keybuf, token, tokensize); | |
1157 | } | |
1158 | *keybufsize = tokensize; | |
1159 | ||
1160 | out: | |
1161 | kfree(token); | |
1162 | return rc; | |
1163 | } | |
1164 | EXPORT_SYMBOL(cca_clr2cipherkey); | |
1165 | ||
1166 | /* | |
1167 | * Derive proteced key from CCA AES cipher secure key. | |
1168 | */ | |
1169 | int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, | |
1170 | u8 *protkey, u32 *protkeylen, u32 *protkeytype) | |
1171 | { | |
1172 | int rc; | |
74ecbef7 | 1173 | u8 *mem, *ptr; |
4bc123b1 HF |
1174 | struct CPRBX *preqcblk, *prepcblk; |
1175 | struct ica_xcRB xcrb; | |
1176 | struct aureqparm { | |
1177 | u8 subfunc_code[2]; | |
1178 | u16 rule_array_len; | |
1179 | u8 rule_array[8]; | |
1180 | struct { | |
1181 | u16 len; | |
1182 | u16 tk_blob_len; | |
1183 | u16 tk_blob_tag; | |
1184 | u8 tk_blob[66]; | |
1185 | } vud; | |
1186 | struct { | |
1187 | u16 len; | |
1188 | u16 cca_key_token_len; | |
1189 | u16 cca_key_token_flags; | |
3b42877c | 1190 | u8 cca_key_token[]; /* 64 or more */ |
4bc123b1 HF |
1191 | } kb; |
1192 | } __packed * preqparm; | |
1193 | struct aurepparm { | |
1194 | u8 subfunc_code[2]; | |
1195 | u16 rule_array_len; | |
1196 | struct { | |
1197 | u16 len; | |
1198 | u16 sublen; | |
1199 | u16 tag; | |
1200 | struct cpacfkeyblock { | |
1201 | u8 version; /* version of this struct */ | |
1202 | u8 flags[2]; | |
1203 | u8 algo; | |
1204 | u8 form; | |
1205 | u8 pad1[3]; | |
1206 | u16 keylen; | |
1207 | u8 key[64]; /* the key (keylen bytes) */ | |
1208 | u16 keyattrlen; | |
1209 | u8 keyattr[32]; | |
1210 | u8 pad2[1]; | |
1211 | u8 vptype; | |
1212 | u8 vp[32]; /* verification pattern */ | |
1213 | } ckb; | |
1214 | } vud; | |
1215 | struct { | |
1216 | u16 len; | |
1217 | } kb; | |
1218 | } __packed * prepparm; | |
1219 | int keytoklen = ((struct cipherkeytoken *)ckey)->len; | |
1220 | ||
1221 | /* get already prepared memory for 2 cprbs with param block each */ | |
1222 | rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); | |
1223 | if (rc) | |
1224 | return rc; | |
1225 | ||
1226 | /* fill request cprb struct */ | |
1227 | preqcblk->domain = domain; | |
1228 | ||
1229 | /* fill request cprb param block with AU request */ | |
2004b57c | 1230 | preqparm = (struct aureqparm __force *)preqcblk->req_parmb; |
4bc123b1 HF |
1231 | memcpy(preqparm->subfunc_code, "AU", 2); |
1232 | preqparm->rule_array_len = | |
1233 | sizeof(preqparm->rule_array_len) | |
1234 | + sizeof(preqparm->rule_array); | |
1235 | memcpy(preqparm->rule_array, "EXPT-SK ", 8); | |
1236 | /* vud, tk blob */ | |
1237 | preqparm->vud.len = sizeof(preqparm->vud); | |
1238 | preqparm->vud.tk_blob_len = sizeof(preqparm->vud.tk_blob) | |
1239 | + 2 * sizeof(uint16_t); | |
1240 | preqparm->vud.tk_blob_tag = 0x00C2; | |
1241 | /* kb, cca token */ | |
1242 | preqparm->kb.len = keytoklen + 3 * sizeof(uint16_t); | |
1243 | preqparm->kb.cca_key_token_len = keytoklen + 2 * sizeof(uint16_t); | |
1244 | memcpy(preqparm->kb.cca_key_token, ckey, keytoklen); | |
1245 | /* now fill length of param block into cprb */ | |
1246 | preqcblk->req_parml = sizeof(struct aureqparm) + keytoklen; | |
1247 | ||
1248 | /* fill xcrb struct */ | |
1249 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
1250 | ||
1251 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
52f72feb | 1252 | rc = zcrypt_send_cprb(&xcrb); |
4bc123b1 | 1253 | if (rc) { |
88e4c0da HF |
1254 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", |
1255 | __func__, (int)cardnr, (int)domain, rc); | |
4bc123b1 HF |
1256 | goto out; |
1257 | } | |
1258 | ||
1259 | /* check response returncode and reasoncode */ | |
1260 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
1261 | ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n", |
1262 | __func__, | |
1263 | (int)prepcblk->ccp_rtcode, | |
1264 | (int)prepcblk->ccp_rscode); | |
1daafea4 | 1265 | if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290) |
da565832 | 1266 | rc = -EBUSY; |
1daafea4 HF |
1267 | else |
1268 | rc = -EIO; | |
4bc123b1 HF |
1269 | goto out; |
1270 | } | |
1271 | if (prepcblk->ccp_rscode != 0) { | |
88e4c0da HF |
1272 | ZCRYPT_DBF_WARN("%s unwrap secure key warning, card response %d/%d\n", |
1273 | __func__, | |
1274 | (int)prepcblk->ccp_rtcode, | |
1275 | (int)prepcblk->ccp_rscode); | |
4bc123b1 HF |
1276 | } |
1277 | ||
1278 | /* process response cprb param block */ | |
2004b57c HF |
1279 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
1280 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
1281 | prepparm = (struct aurepparm *)ptr; | |
4bc123b1 HF |
1282 | |
1283 | /* check the returned keyblock */ | |
c4f762ff HF |
1284 | if (prepparm->vud.ckb.version != 0x01 && |
1285 | prepparm->vud.ckb.version != 0x02) { | |
88e4c0da HF |
1286 | ZCRYPT_DBF_ERR("%s reply param keyblock version mismatch 0x%02x\n", |
1287 | __func__, (int)prepparm->vud.ckb.version); | |
4bc123b1 HF |
1288 | rc = -EIO; |
1289 | goto out; | |
1290 | } | |
1291 | if (prepparm->vud.ckb.algo != 0x02) { | |
88e4c0da HF |
1292 | ZCRYPT_DBF_ERR("%s reply param keyblock algo mismatch 0x%02x != 0x02\n", |
1293 | __func__, (int)prepparm->vud.ckb.algo); | |
4bc123b1 HF |
1294 | rc = -EIO; |
1295 | goto out; | |
1296 | } | |
1297 | ||
1298 | /* copy the translated protected key */ | |
1299 | switch (prepparm->vud.ckb.keylen) { | |
2004b57c | 1300 | case 16 + 32: |
4bc123b1 HF |
1301 | /* AES 128 protected key */ |
1302 | if (protkeytype) | |
1303 | *protkeytype = PKEY_KEYTYPE_AES_128; | |
1304 | break; | |
2004b57c | 1305 | case 24 + 32: |
4bc123b1 HF |
1306 | /* AES 192 protected key */ |
1307 | if (protkeytype) | |
1308 | *protkeytype = PKEY_KEYTYPE_AES_192; | |
1309 | break; | |
2004b57c | 1310 | case 32 + 32: |
4bc123b1 HF |
1311 | /* AES 256 protected key */ |
1312 | if (protkeytype) | |
1313 | *protkeytype = PKEY_KEYTYPE_AES_256; | |
1314 | break; | |
1315 | default: | |
88e4c0da HF |
1316 | ZCRYPT_DBF_ERR("%s unknown/unsupported keylen %d\n", |
1317 | __func__, prepparm->vud.ckb.keylen); | |
4bc123b1 HF |
1318 | rc = -EIO; |
1319 | goto out; | |
1320 | } | |
1321 | memcpy(protkey, prepparm->vud.ckb.key, prepparm->vud.ckb.keylen); | |
1322 | if (protkeylen) | |
1323 | *protkeylen = prepparm->vud.ckb.keylen; | |
1324 | ||
1325 | out: | |
1326 | free_cprbmem(mem, PARMBSIZE, 0); | |
1327 | return rc; | |
1328 | } | |
1329 | EXPORT_SYMBOL(cca_cipher2protkey); | |
1330 | ||
fa6999e3 HF |
1331 | /* |
1332 | * Derive protected key from CCA ECC secure private key. | |
1333 | */ | |
1334 | int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key, | |
1335 | u8 *protkey, u32 *protkeylen, u32 *protkeytype) | |
1336 | { | |
1337 | int rc; | |
1338 | u8 *mem, *ptr; | |
1339 | struct CPRBX *preqcblk, *prepcblk; | |
1340 | struct ica_xcRB xcrb; | |
1341 | struct aureqparm { | |
1342 | u8 subfunc_code[2]; | |
1343 | u16 rule_array_len; | |
1344 | u8 rule_array[8]; | |
1345 | struct { | |
1346 | u16 len; | |
1347 | u16 tk_blob_len; | |
1348 | u16 tk_blob_tag; | |
1349 | u8 tk_blob[66]; | |
1350 | } vud; | |
1351 | struct { | |
1352 | u16 len; | |
1353 | u16 cca_key_token_len; | |
1354 | u16 cca_key_token_flags; | |
3b42877c | 1355 | u8 cca_key_token[]; |
fa6999e3 HF |
1356 | } kb; |
1357 | } __packed * preqparm; | |
1358 | struct aurepparm { | |
1359 | u8 subfunc_code[2]; | |
1360 | u16 rule_array_len; | |
1361 | struct { | |
1362 | u16 len; | |
1363 | u16 sublen; | |
1364 | u16 tag; | |
1365 | struct cpacfkeyblock { | |
1366 | u8 version; /* version of this struct */ | |
1367 | u8 flags[2]; | |
1368 | u8 algo; | |
1369 | u8 form; | |
1370 | u8 pad1[3]; | |
1371 | u16 keylen; | |
3b42877c HF |
1372 | u8 key[]; /* the key (keylen bytes) */ |
1373 | /* u16 keyattrlen; */ | |
1374 | /* u8 keyattr[32]; */ | |
1375 | /* u8 pad2[1]; */ | |
1376 | /* u8 vptype; */ | |
1377 | /* u8 vp[32]; verification pattern */ | |
fa6999e3 HF |
1378 | } ckb; |
1379 | } vud; | |
3b42877c | 1380 | /* followed by a key block */ |
fa6999e3 HF |
1381 | } __packed * prepparm; |
1382 | int keylen = ((struct eccprivkeytoken *)key)->len; | |
1383 | ||
1384 | /* get already prepared memory for 2 cprbs with param block each */ | |
1385 | rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); | |
1386 | if (rc) | |
1387 | return rc; | |
1388 | ||
1389 | /* fill request cprb struct */ | |
1390 | preqcblk->domain = domain; | |
1391 | ||
1392 | /* fill request cprb param block with AU request */ | |
2004b57c | 1393 | preqparm = (struct aureqparm __force *)preqcblk->req_parmb; |
fa6999e3 HF |
1394 | memcpy(preqparm->subfunc_code, "AU", 2); |
1395 | preqparm->rule_array_len = | |
1396 | sizeof(preqparm->rule_array_len) | |
1397 | + sizeof(preqparm->rule_array); | |
1398 | memcpy(preqparm->rule_array, "EXPT-SK ", 8); | |
1399 | /* vud, tk blob */ | |
1400 | preqparm->vud.len = sizeof(preqparm->vud); | |
1401 | preqparm->vud.tk_blob_len = sizeof(preqparm->vud.tk_blob) | |
1402 | + 2 * sizeof(uint16_t); | |
1403 | preqparm->vud.tk_blob_tag = 0x00C2; | |
1404 | /* kb, cca token */ | |
1405 | preqparm->kb.len = keylen + 3 * sizeof(uint16_t); | |
1406 | preqparm->kb.cca_key_token_len = keylen + 2 * sizeof(uint16_t); | |
1407 | memcpy(preqparm->kb.cca_key_token, key, keylen); | |
1408 | /* now fill length of param block into cprb */ | |
1409 | preqcblk->req_parml = sizeof(struct aureqparm) + keylen; | |
1410 | ||
1411 | /* fill xcrb struct */ | |
1412 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
1413 | ||
1414 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
1415 | rc = zcrypt_send_cprb(&xcrb); | |
1416 | if (rc) { | |
88e4c0da HF |
1417 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", |
1418 | __func__, (int)cardnr, (int)domain, rc); | |
fa6999e3 HF |
1419 | goto out; |
1420 | } | |
1421 | ||
1422 | /* check response returncode and reasoncode */ | |
1423 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
1424 | ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n", |
1425 | __func__, | |
1426 | (int)prepcblk->ccp_rtcode, | |
1427 | (int)prepcblk->ccp_rscode); | |
1daafea4 | 1428 | if (prepcblk->ccp_rtcode == 8 && prepcblk->ccp_rscode == 2290) |
da565832 | 1429 | rc = -EBUSY; |
1daafea4 HF |
1430 | else |
1431 | rc = -EIO; | |
fa6999e3 HF |
1432 | goto out; |
1433 | } | |
1434 | if (prepcblk->ccp_rscode != 0) { | |
88e4c0da HF |
1435 | ZCRYPT_DBF_WARN("%s unwrap secure key warning, card response %d/%d\n", |
1436 | __func__, | |
1437 | (int)prepcblk->ccp_rtcode, | |
1438 | (int)prepcblk->ccp_rscode); | |
fa6999e3 HF |
1439 | } |
1440 | ||
1441 | /* process response cprb param block */ | |
2004b57c HF |
1442 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
1443 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
1444 | prepparm = (struct aurepparm *)ptr; | |
fa6999e3 HF |
1445 | |
1446 | /* check the returned keyblock */ | |
1447 | if (prepparm->vud.ckb.version != 0x02) { | |
88e4c0da HF |
1448 | ZCRYPT_DBF_ERR("%s reply param keyblock version mismatch 0x%02x != 0x02\n", |
1449 | __func__, (int)prepparm->vud.ckb.version); | |
fa6999e3 HF |
1450 | rc = -EIO; |
1451 | goto out; | |
1452 | } | |
1453 | if (prepparm->vud.ckb.algo != 0x81) { | |
88e4c0da HF |
1454 | ZCRYPT_DBF_ERR("%s reply param keyblock algo mismatch 0x%02x != 0x81\n", |
1455 | __func__, (int)prepparm->vud.ckb.algo); | |
fa6999e3 HF |
1456 | rc = -EIO; |
1457 | goto out; | |
1458 | } | |
1459 | ||
1460 | /* copy the translated protected key */ | |
1461 | if (prepparm->vud.ckb.keylen > *protkeylen) { | |
88e4c0da HF |
1462 | ZCRYPT_DBF_ERR("%s prot keylen mismatch %d > buffersize %u\n", |
1463 | __func__, prepparm->vud.ckb.keylen, *protkeylen); | |
fa6999e3 HF |
1464 | rc = -EIO; |
1465 | goto out; | |
1466 | } | |
1467 | memcpy(protkey, prepparm->vud.ckb.key, prepparm->vud.ckb.keylen); | |
1468 | *protkeylen = prepparm->vud.ckb.keylen; | |
1469 | if (protkeytype) | |
1470 | *protkeytype = PKEY_KEYTYPE_ECC; | |
1471 | ||
1472 | out: | |
1473 | free_cprbmem(mem, PARMBSIZE, 0); | |
1474 | return rc; | |
1475 | } | |
1476 | EXPORT_SYMBOL(cca_ecc2protkey); | |
1477 | ||
efc598e6 HF |
1478 | /* |
1479 | * query cryptographic facility from CCA adapter | |
1480 | */ | |
1481 | int cca_query_crypto_facility(u16 cardnr, u16 domain, | |
1482 | const char *keyword, | |
1483 | u8 *rarray, size_t *rarraylen, | |
1484 | u8 *varray, size_t *varraylen) | |
1485 | { | |
1486 | int rc; | |
1487 | u16 len; | |
1488 | u8 *mem, *ptr; | |
1489 | struct CPRBX *preqcblk, *prepcblk; | |
1490 | struct ica_xcRB xcrb; | |
1491 | struct fqreqparm { | |
1492 | u8 subfunc_code[2]; | |
1493 | u16 rule_array_len; | |
1494 | char rule_array[8]; | |
1495 | struct lv1 { | |
1496 | u16 len; | |
1497 | u8 data[VARDATASIZE]; | |
1498 | } lv1; | |
1499 | u16 dummylen; | |
1500 | } __packed * preqparm; | |
1501 | size_t parmbsize = sizeof(struct fqreqparm); | |
1502 | struct fqrepparm { | |
1503 | u8 subfunc_code[2]; | |
3b42877c | 1504 | u8 lvdata[]; |
efc598e6 HF |
1505 | } __packed * prepparm; |
1506 | ||
1507 | /* get already prepared memory for 2 cprbs with param block each */ | |
1508 | rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk); | |
1509 | if (rc) | |
1510 | return rc; | |
1511 | ||
1512 | /* fill request cprb struct */ | |
1513 | preqcblk->domain = domain; | |
1514 | ||
1515 | /* fill request cprb param block with FQ request */ | |
2004b57c | 1516 | preqparm = (struct fqreqparm __force *)preqcblk->req_parmb; |
efc598e6 HF |
1517 | memcpy(preqparm->subfunc_code, "FQ", 2); |
1518 | memcpy(preqparm->rule_array, keyword, sizeof(preqparm->rule_array)); | |
1519 | preqparm->rule_array_len = | |
1520 | sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); | |
1521 | preqparm->lv1.len = sizeof(preqparm->lv1); | |
1522 | preqparm->dummylen = sizeof(preqparm->dummylen); | |
1523 | preqcblk->req_parml = parmbsize; | |
1524 | ||
1525 | /* fill xcrb struct */ | |
1526 | prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); | |
1527 | ||
1528 | /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ | |
52f72feb | 1529 | rc = zcrypt_send_cprb(&xcrb); |
efc598e6 | 1530 | if (rc) { |
88e4c0da HF |
1531 | ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", |
1532 | __func__, (int)cardnr, (int)domain, rc); | |
efc598e6 HF |
1533 | goto out; |
1534 | } | |
1535 | ||
1536 | /* check response returncode and reasoncode */ | |
1537 | if (prepcblk->ccp_rtcode != 0) { | |
88e4c0da HF |
1538 | ZCRYPT_DBF_ERR("%s unwrap secure key failure, card response %d/%d\n", |
1539 | __func__, | |
1540 | (int)prepcblk->ccp_rtcode, | |
1541 | (int)prepcblk->ccp_rscode); | |
efc598e6 HF |
1542 | rc = -EIO; |
1543 | goto out; | |
1544 | } | |
1545 | ||
1546 | /* process response cprb param block */ | |
2004b57c HF |
1547 | ptr = ((u8 *)prepcblk) + sizeof(struct CPRBX); |
1548 | prepcblk->rpl_parmb = (u8 __user *)ptr; | |
1549 | prepparm = (struct fqrepparm *)ptr; | |
efc598e6 HF |
1550 | ptr = prepparm->lvdata; |
1551 | ||
1552 | /* check and possibly copy reply rule array */ | |
2004b57c | 1553 | len = *((u16 *)ptr); |
efc598e6 HF |
1554 | if (len > sizeof(u16)) { |
1555 | ptr += sizeof(u16); | |
1556 | len -= sizeof(u16); | |
1557 | if (rarray && rarraylen && *rarraylen > 0) { | |
1558 | *rarraylen = (len > *rarraylen ? *rarraylen : len); | |
1559 | memcpy(rarray, ptr, *rarraylen); | |
1560 | } | |
1561 | ptr += len; | |
1562 | } | |
1563 | /* check and possible copy reply var array */ | |
2004b57c | 1564 | len = *((u16 *)ptr); |
efc598e6 HF |
1565 | if (len > sizeof(u16)) { |
1566 | ptr += sizeof(u16); | |
1567 | len -= sizeof(u16); | |
1568 | if (varray && varraylen && *varraylen > 0) { | |
1569 | *varraylen = (len > *varraylen ? *varraylen : len); | |
1570 | memcpy(varray, ptr, *varraylen); | |
1571 | } | |
1572 | ptr += len; | |
1573 | } | |
1574 | ||
1575 | out: | |
1576 | free_cprbmem(mem, parmbsize, 0); | |
1577 | return rc; | |
1578 | } | |
1579 | EXPORT_SYMBOL(cca_query_crypto_facility); | |
1580 | ||
94bbd34e | 1581 | static int cca_info_cache_fetch(u16 cardnr, u16 domain, struct cca_info *ci) |
efc598e6 HF |
1582 | { |
1583 | int rc = -ENOENT; | |
94bbd34e | 1584 | struct cca_info_list_entry *ptr; |
efc598e6 | 1585 | |
94bbd34e HF |
1586 | spin_lock_bh(&cca_info_list_lock); |
1587 | list_for_each_entry(ptr, &cca_info_list, list) { | |
1588 | if (ptr->cardnr == cardnr && ptr->domain == domain) { | |
1589 | memcpy(ci, &ptr->info, sizeof(*ci)); | |
efc598e6 HF |
1590 | rc = 0; |
1591 | break; | |
1592 | } | |
1593 | } | |
94bbd34e | 1594 | spin_unlock_bh(&cca_info_list_lock); |
efc598e6 HF |
1595 | |
1596 | return rc; | |
1597 | } | |
1598 | ||
94bbd34e HF |
1599 | static void cca_info_cache_update(u16 cardnr, u16 domain, |
1600 | const struct cca_info *ci) | |
efc598e6 HF |
1601 | { |
1602 | int found = 0; | |
94bbd34e | 1603 | struct cca_info_list_entry *ptr; |
efc598e6 | 1604 | |
94bbd34e HF |
1605 | spin_lock_bh(&cca_info_list_lock); |
1606 | list_for_each_entry(ptr, &cca_info_list, list) { | |
efc598e6 HF |
1607 | if (ptr->cardnr == cardnr && |
1608 | ptr->domain == domain) { | |
94bbd34e | 1609 | memcpy(&ptr->info, ci, sizeof(*ci)); |
efc598e6 HF |
1610 | found = 1; |
1611 | break; | |
1612 | } | |
1613 | } | |
1614 | if (!found) { | |
1615 | ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); | |
1616 | if (!ptr) { | |
94bbd34e | 1617 | spin_unlock_bh(&cca_info_list_lock); |
efc598e6 HF |
1618 | return; |
1619 | } | |
1620 | ptr->cardnr = cardnr; | |
1621 | ptr->domain = domain; | |
94bbd34e HF |
1622 | memcpy(&ptr->info, ci, sizeof(*ci)); |
1623 | list_add(&ptr->list, &cca_info_list); | |
efc598e6 | 1624 | } |
94bbd34e | 1625 | spin_unlock_bh(&cca_info_list_lock); |
efc598e6 HF |
1626 | } |
1627 | ||
94bbd34e | 1628 | static void cca_info_cache_scrub(u16 cardnr, u16 domain) |
efc598e6 | 1629 | { |
94bbd34e | 1630 | struct cca_info_list_entry *ptr; |
efc598e6 | 1631 | |
94bbd34e HF |
1632 | spin_lock_bh(&cca_info_list_lock); |
1633 | list_for_each_entry(ptr, &cca_info_list, list) { | |
efc598e6 HF |
1634 | if (ptr->cardnr == cardnr && |
1635 | ptr->domain == domain) { | |
1636 | list_del(&ptr->list); | |
1637 | kfree(ptr); | |
1638 | break; | |
1639 | } | |
1640 | } | |
94bbd34e | 1641 | spin_unlock_bh(&cca_info_list_lock); |
efc598e6 HF |
1642 | } |
1643 | ||
1644 | static void __exit mkvp_cache_free(void) | |
1645 | { | |
94bbd34e | 1646 | struct cca_info_list_entry *ptr, *pnext; |
efc598e6 | 1647 | |
94bbd34e HF |
1648 | spin_lock_bh(&cca_info_list_lock); |
1649 | list_for_each_entry_safe(ptr, pnext, &cca_info_list, list) { | |
efc598e6 HF |
1650 | list_del(&ptr->list); |
1651 | kfree(ptr); | |
1652 | } | |
94bbd34e | 1653 | spin_unlock_bh(&cca_info_list_lock); |
efc598e6 HF |
1654 | } |
1655 | ||
1656 | /* | |
94bbd34e | 1657 | * Fetch cca_info values via query_crypto_facility from adapter. |
efc598e6 | 1658 | */ |
94bbd34e | 1659 | static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) |
efc598e6 HF |
1660 | { |
1661 | int rc, found = 0; | |
1662 | size_t rlen, vlen; | |
1663 | u8 *rarray, *varray, *pg; | |
4da57a2f | 1664 | struct zcrypt_device_status_ext devstat; |
efc598e6 | 1665 | |
4da57a2f HF |
1666 | memset(ci, 0, sizeof(*ci)); |
1667 | ||
1668 | /* get first info from zcrypt device driver about this apqn */ | |
1669 | rc = zcrypt_device_status_ext(cardnr, domain, &devstat); | |
1670 | if (rc) | |
1671 | return rc; | |
1672 | ci->hwtype = devstat.hwtype; | |
1673 | ||
1674 | /* prep page for rule array and var array use */ | |
2004b57c | 1675 | pg = (u8 *)__get_free_page(GFP_KERNEL); |
efc598e6 HF |
1676 | if (!pg) |
1677 | return -ENOMEM; | |
1678 | rarray = pg; | |
2004b57c HF |
1679 | varray = pg + PAGE_SIZE / 2; |
1680 | rlen = vlen = PAGE_SIZE / 2; | |
efc598e6 | 1681 | |
4da57a2f | 1682 | /* QF for this card/domain */ |
efc598e6 HF |
1683 | rc = cca_query_crypto_facility(cardnr, domain, "STATICSA", |
1684 | rarray, &rlen, varray, &vlen); | |
2004b57c | 1685 | if (rc == 0 && rlen >= 10 * 8 && vlen >= 204) { |
94bbd34e | 1686 | memcpy(ci->serial, rarray, 8); |
2004b57c HF |
1687 | ci->new_asym_mk_state = (char)rarray[4 * 8]; |
1688 | ci->cur_asym_mk_state = (char)rarray[5 * 8]; | |
1689 | ci->old_asym_mk_state = (char)rarray[6 * 8]; | |
28d3417a HF |
1690 | if (ci->old_asym_mk_state == '2') |
1691 | memcpy(ci->old_asym_mkvp, varray + 64, 16); | |
1692 | if (ci->cur_asym_mk_state == '2') | |
1693 | memcpy(ci->cur_asym_mkvp, varray + 84, 16); | |
1694 | if (ci->new_asym_mk_state == '3') | |
1695 | memcpy(ci->new_asym_mkvp, varray + 104, 16); | |
2004b57c HF |
1696 | ci->new_aes_mk_state = (char)rarray[7 * 8]; |
1697 | ci->cur_aes_mk_state = (char)rarray[8 * 8]; | |
1698 | ci->old_aes_mk_state = (char)rarray[9 * 8]; | |
32ca04bb HF |
1699 | if (ci->old_aes_mk_state == '2') |
1700 | memcpy(&ci->old_aes_mkvp, varray + 172, 8); | |
1701 | if (ci->cur_aes_mk_state == '2') | |
1702 | memcpy(&ci->cur_aes_mkvp, varray + 184, 8); | |
1703 | if (ci->new_aes_mk_state == '3') | |
1704 | memcpy(&ci->new_aes_mkvp, varray + 196, 8); | |
1705 | found++; | |
1706 | } | |
1707 | if (!found) | |
1708 | goto out; | |
2004b57c | 1709 | rlen = vlen = PAGE_SIZE / 2; |
32ca04bb HF |
1710 | rc = cca_query_crypto_facility(cardnr, domain, "STATICSB", |
1711 | rarray, &rlen, varray, &vlen); | |
2004b57c HF |
1712 | if (rc == 0 && rlen >= 13 * 8 && vlen >= 240) { |
1713 | ci->new_apka_mk_state = (char)rarray[10 * 8]; | |
1714 | ci->cur_apka_mk_state = (char)rarray[11 * 8]; | |
1715 | ci->old_apka_mk_state = (char)rarray[12 * 8]; | |
32ca04bb HF |
1716 | if (ci->old_apka_mk_state == '2') |
1717 | memcpy(&ci->old_apka_mkvp, varray + 208, 8); | |
1718 | if (ci->cur_apka_mk_state == '2') | |
1719 | memcpy(&ci->cur_apka_mkvp, varray + 220, 8); | |
1720 | if (ci->new_apka_mk_state == '3') | |
1721 | memcpy(&ci->new_apka_mkvp, varray + 232, 8); | |
1722 | found++; | |
efc598e6 HF |
1723 | } |
1724 | ||
32ca04bb | 1725 | out: |
2004b57c | 1726 | free_page((unsigned long)pg); |
32ca04bb | 1727 | return found == 2 ? 0 : -ENOENT; |
efc598e6 HF |
1728 | } |
1729 | ||
7c4e91c0 HF |
1730 | /* |
1731 | * Fetch cca information about a CCA queue. | |
1732 | */ | |
1733 | int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify) | |
1734 | { | |
1735 | int rc; | |
1736 | ||
1737 | rc = cca_info_cache_fetch(card, dom, ci); | |
1738 | if (rc || verify) { | |
1739 | rc = fetch_cca_info(card, dom, ci); | |
1740 | if (rc == 0) | |
1741 | cca_info_cache_update(card, dom, ci); | |
1742 | } | |
1743 | ||
1744 | return rc; | |
1745 | } | |
1746 | EXPORT_SYMBOL(cca_get_info); | |
1747 | ||
efc598e6 | 1748 | /* |
4da57a2f HF |
1749 | * Search for a matching crypto card based on the |
1750 | * Master Key Verification Pattern given. | |
efc598e6 | 1751 | */ |
4da57a2f HF |
1752 | static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, |
1753 | int verify, int minhwtype) | |
efc598e6 | 1754 | { |
efc598e6 HF |
1755 | struct zcrypt_device_status_ext *device_status; |
1756 | u16 card, dom; | |
94bbd34e | 1757 | struct cca_info ci; |
efc598e6 HF |
1758 | int i, rc, oi = -1; |
1759 | ||
4da57a2f HF |
1760 | /* mkvp must not be zero, minhwtype needs to be >= 0 */ |
1761 | if (mkvp == 0 || minhwtype < 0) | |
efc598e6 HF |
1762 | return -EINVAL; |
1763 | ||
1764 | /* fetch status of all crypto cards */ | |
c1248638 HC |
1765 | device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT, |
1766 | sizeof(struct zcrypt_device_status_ext), | |
1767 | GFP_KERNEL); | |
efc598e6 HF |
1768 | if (!device_status) |
1769 | return -ENOMEM; | |
1770 | zcrypt_device_status_mask_ext(device_status); | |
1771 | ||
1772 | /* walk through all crypto cards */ | |
1773 | for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { | |
1774 | card = AP_QID_CARD(device_status[i].qid); | |
1775 | dom = AP_QID_QUEUE(device_status[i].qid); | |
1776 | if (device_status[i].online && | |
1777 | device_status[i].functions & 0x04) { | |
94bbd34e HF |
1778 | /* enabled CCA card, check current mkvp from cache */ |
1779 | if (cca_info_cache_fetch(card, dom, &ci) == 0 && | |
4da57a2f | 1780 | ci.hwtype >= minhwtype && |
32ca04bb HF |
1781 | ci.cur_aes_mk_state == '2' && |
1782 | ci.cur_aes_mkvp == mkvp) { | |
efc598e6 HF |
1783 | if (!verify) |
1784 | break; | |
94bbd34e HF |
1785 | /* verify: refresh card info */ |
1786 | if (fetch_cca_info(card, dom, &ci) == 0) { | |
1787 | cca_info_cache_update(card, dom, &ci); | |
4da57a2f | 1788 | if (ci.hwtype >= minhwtype && |
32ca04bb HF |
1789 | ci.cur_aes_mk_state == '2' && |
1790 | ci.cur_aes_mkvp == mkvp) | |
efc598e6 HF |
1791 | break; |
1792 | } | |
1793 | } | |
1794 | } else { | |
1795 | /* Card is offline and/or not a CCA card. */ | |
1796 | /* del mkvp entry from cache if it exists */ | |
94bbd34e | 1797 | cca_info_cache_scrub(card, dom); |
efc598e6 HF |
1798 | } |
1799 | } | |
1800 | if (i >= MAX_ZDEV_ENTRIES_EXT) { | |
1801 | /* nothing found, so this time without cache */ | |
1802 | for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { | |
1803 | if (!(device_status[i].online && | |
1804 | device_status[i].functions & 0x04)) | |
1805 | continue; | |
1806 | card = AP_QID_CARD(device_status[i].qid); | |
1807 | dom = AP_QID_QUEUE(device_status[i].qid); | |
1808 | /* fresh fetch mkvp from adapter */ | |
94bbd34e HF |
1809 | if (fetch_cca_info(card, dom, &ci) == 0) { |
1810 | cca_info_cache_update(card, dom, &ci); | |
4da57a2f | 1811 | if (ci.hwtype >= minhwtype && |
32ca04bb HF |
1812 | ci.cur_aes_mk_state == '2' && |
1813 | ci.cur_aes_mkvp == mkvp) | |
efc598e6 | 1814 | break; |
4da57a2f | 1815 | if (ci.hwtype >= minhwtype && |
32ca04bb HF |
1816 | ci.old_aes_mk_state == '2' && |
1817 | ci.old_aes_mkvp == mkvp && | |
94bbd34e | 1818 | oi < 0) |
efc598e6 HF |
1819 | oi = i; |
1820 | } | |
1821 | } | |
1822 | if (i >= MAX_ZDEV_ENTRIES_EXT && oi >= 0) { | |
1823 | /* old mkvp matched, use this card then */ | |
1824 | card = AP_QID_CARD(device_status[oi].qid); | |
1825 | dom = AP_QID_QUEUE(device_status[oi].qid); | |
1826 | } | |
1827 | } | |
1828 | if (i < MAX_ZDEV_ENTRIES_EXT || oi >= 0) { | |
1829 | if (pcardnr) | |
1830 | *pcardnr = card; | |
1831 | if (pdomain) | |
1832 | *pdomain = dom; | |
1833 | rc = (i < MAX_ZDEV_ENTRIES_EXT ? 0 : 1); | |
2004b57c | 1834 | } else { |
efc598e6 | 1835 | rc = -ENODEV; |
2004b57c | 1836 | } |
efc598e6 | 1837 | |
34515df2 | 1838 | kvfree(device_status); |
efc598e6 HF |
1839 | return rc; |
1840 | } | |
4da57a2f HF |
1841 | |
1842 | /* | |
1843 | * Search for a matching crypto card based on the Master Key | |
1844 | * Verification Pattern provided inside a secure key token. | |
1845 | */ | |
1846 | int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) | |
1847 | { | |
1848 | u64 mkvp; | |
f2bbc96e | 1849 | int minhwtype = 0; |
2004b57c | 1850 | const struct keytoken_header *hdr = (struct keytoken_header *)key; |
4da57a2f HF |
1851 | |
1852 | if (hdr->type != TOKTYPE_CCA_INTERNAL) | |
1853 | return -EINVAL; | |
1854 | ||
1855 | switch (hdr->version) { | |
1856 | case TOKVER_CCA_AES: | |
1857 | mkvp = ((struct secaeskeytoken *)key)->mkvp; | |
1858 | break; | |
f2bbc96e HF |
1859 | case TOKVER_CCA_VLSC: |
1860 | mkvp = ((struct cipherkeytoken *)key)->mkvp0; | |
1861 | minhwtype = AP_DEVICE_TYPE_CEX6; | |
1862 | break; | |
4da57a2f HF |
1863 | default: |
1864 | return -EINVAL; | |
1865 | } | |
1866 | ||
f2bbc96e | 1867 | return findcard(mkvp, pcardnr, pdomain, verify, minhwtype); |
4da57a2f | 1868 | } |
efc598e6 HF |
1869 | EXPORT_SYMBOL(cca_findcard); |
1870 | ||
4bc123b1 | 1871 | int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, |
32ca04bb HF |
1872 | int minhwtype, int mktype, u64 cur_mkvp, u64 old_mkvp, |
1873 | int verify) | |
4bc123b1 HF |
1874 | { |
1875 | struct zcrypt_device_status_ext *device_status; | |
0d574ad3 HF |
1876 | u32 *_apqns = NULL, _nr_apqns = 0; |
1877 | int i, card, dom, curmatch, oldmatch, rc = 0; | |
4bc123b1 HF |
1878 | struct cca_info ci; |
1879 | ||
4bc123b1 | 1880 | /* fetch status of all crypto cards */ |
c1248638 HC |
1881 | device_status = kvcalloc(MAX_ZDEV_ENTRIES_EXT, |
1882 | sizeof(struct zcrypt_device_status_ext), | |
1883 | GFP_KERNEL); | |
4bc123b1 HF |
1884 | if (!device_status) |
1885 | return -ENOMEM; | |
1886 | zcrypt_device_status_mask_ext(device_status); | |
1887 | ||
0d574ad3 HF |
1888 | /* allocate 1k space for up to 256 apqns */ |
1889 | _apqns = kmalloc_array(256, sizeof(u32), GFP_KERNEL); | |
1890 | if (!_apqns) { | |
1891 | kvfree(device_status); | |
1892 | return -ENOMEM; | |
1893 | } | |
1894 | ||
1895 | /* walk through all the crypto apqnss */ | |
1896 | for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { | |
1897 | card = AP_QID_CARD(device_status[i].qid); | |
1898 | dom = AP_QID_QUEUE(device_status[i].qid); | |
1899 | /* check online state */ | |
1900 | if (!device_status[i].online) | |
1901 | continue; | |
1902 | /* check for cca functions */ | |
1903 | if (!(device_status[i].functions & 0x04)) | |
1904 | continue; | |
1905 | /* check cardnr */ | |
1906 | if (cardnr != 0xFFFF && card != cardnr) | |
1907 | continue; | |
1908 | /* check domain */ | |
1909 | if (domain != 0xFFFF && dom != domain) | |
1910 | continue; | |
1911 | /* get cca info on this apqn */ | |
1912 | if (cca_get_info(card, dom, &ci, verify)) | |
1913 | continue; | |
1914 | /* current master key needs to be valid */ | |
32ca04bb HF |
1915 | if (mktype == AES_MK_SET && ci.cur_aes_mk_state != '2') |
1916 | continue; | |
1917 | if (mktype == APKA_MK_SET && ci.cur_apka_mk_state != '2') | |
0d574ad3 HF |
1918 | continue; |
1919 | /* check min hardware type */ | |
1920 | if (minhwtype > 0 && minhwtype > ci.hwtype) | |
1921 | continue; | |
1922 | if (cur_mkvp || old_mkvp) { | |
1923 | /* check mkvps */ | |
1924 | curmatch = oldmatch = 0; | |
32ca04bb HF |
1925 | if (mktype == AES_MK_SET) { |
1926 | if (cur_mkvp && cur_mkvp == ci.cur_aes_mkvp) | |
1927 | curmatch = 1; | |
1928 | if (old_mkvp && ci.old_aes_mk_state == '2' && | |
1929 | old_mkvp == ci.old_aes_mkvp) | |
1930 | oldmatch = 1; | |
1931 | } else { | |
1932 | if (cur_mkvp && cur_mkvp == ci.cur_apka_mkvp) | |
4bc123b1 | 1933 | curmatch = 1; |
32ca04bb HF |
1934 | if (old_mkvp && ci.old_apka_mk_state == '2' && |
1935 | old_mkvp == ci.old_apka_mkvp) | |
4bc123b1 | 1936 | oldmatch = 1; |
4bc123b1 | 1937 | } |
32ca04bb | 1938 | if (curmatch + oldmatch < 1) |
4bc123b1 | 1939 | continue; |
4bc123b1 | 1940 | } |
0d574ad3 HF |
1941 | /* apqn passed all filtering criterons, add to the array */ |
1942 | if (_nr_apqns < 256) | |
2004b57c | 1943 | _apqns[_nr_apqns++] = (((u16)card) << 16) | ((u16)dom); |
0d574ad3 HF |
1944 | } |
1945 | ||
1946 | /* nothing found ? */ | |
1947 | if (!_nr_apqns) { | |
1948 | kfree(_apqns); | |
1949 | rc = -ENODEV; | |
1950 | } else { | |
1951 | /* no re-allocation, simple return the _apqns array */ | |
1952 | *apqns = _apqns; | |
1953 | *nr_apqns = _nr_apqns; | |
1954 | rc = 0; | |
4bc123b1 HF |
1955 | } |
1956 | ||
b6186d7f | 1957 | kvfree(device_status); |
4bc123b1 HF |
1958 | return rc; |
1959 | } | |
1960 | EXPORT_SYMBOL(cca_findcard2); | |
1961 | ||
efc598e6 HF |
1962 | void __exit zcrypt_ccamisc_exit(void) |
1963 | { | |
1964 | mkvp_cache_free(); | |
1965 | } |