1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright IBM Corp. 2001, 2023 |
4 | * Author(s): Robert Burroughs |
5 | * Eric Rossman (edrossma@us.ibm.com) |
6 | * |
7 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
8 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> |
9 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
10 | * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com> |
11 | */ |
12 | |
13 | #define KMSG_COMPONENT "zcrypt" |
14 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
15 | |
16 | #include <linux/module.h> |
17 | #include <linux/init.h> |
18 | #include <linux/err.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/slab.h> |
21 | #include <linux/atomic.h> |
22 | #include <linux/uaccess.h> |
23 | |
24 | #include "ap_bus.h" |
25 | #include "zcrypt_api.h" |
26 | #include "zcrypt_error.h" |
27 | #include "zcrypt_msgtype6.h" |
28 | #include "zcrypt_cca_key.h" |
29 | |
30 | #define CEXXC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ |
31 | |
32 | #define CEIL4(x) ((((x) + 3) / 4) * 4) |
33 | |
34 | struct response_type { |
35 | struct completion work; |
36 | int type; |
37 | }; |
38 | |
39 | #define CEXXC_RESPONSE_TYPE_ICA 0 |
40 | #define CEXXC_RESPONSE_TYPE_XCRB 1 |
41 | #define CEXXC_RESPONSE_TYPE_EP11 2 |
42 | |
43 | MODULE_AUTHOR("IBM Corporation" ); |
44 | MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ |
45 | "Copyright IBM Corp. 2001, 2023" ); |
46 | MODULE_LICENSE("GPL" ); |
47 | |
48 | struct function_and_rules_block { |
49 | unsigned char function_code[2]; |
50 | unsigned short ulen; |
51 | unsigned char only_rule[8]; |
52 | } __packed; |
53 | |
54 | /* |
55 | * The following is used to initialize the CPRBX passed to the CEXxC/CEXxP |
56 | * card in a type6 message. The 3 fields that must be filled in at execution |
57 | * time are req_parml, rpl_parml and usage_domain. |
58 | * Everything about this interface is ascii/big-endian, since the |
59 | * device does *not* have 'Intel inside'. |
60 | * |
61 | * The CPRBX is followed immediately by the parm block. |
62 | * The parm block contains: |
63 | * - function code ('PD' 0x5044 or 'PK' 0x504B) |
64 | * - rule block (one of:) |
65 | * + 0x000A 'PKCS-1.2' (MCL2 'PD') |
66 | * + 0x000A 'ZERO-PAD' (MCL2 'PK') |
67 | * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD') |
68 | * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK') |
69 | * - VUD block |
70 | */ |
71 | static const struct CPRBX static_cprbx = { |
72 | .cprb_len = 0x00DC, |
73 | .cprb_ver_id = 0x02, |
74 | .func_id = {0x54, 0x32}, |
75 | }; |
76 | |
77 | int speed_idx_cca(int req_type) |
78 | { |
79 | switch (req_type) { |
80 | case 0x4142: |
81 | case 0x4149: |
82 | case 0x414D: |
83 | case 0x4341: |
84 | case 0x4344: |
85 | case 0x4354: |
86 | case 0x4358: |
87 | case 0x444B: |
88 | case 0x4558: |
89 | case 0x4643: |
90 | case 0x4651: |
91 | case 0x4C47: |
92 | case 0x4C4B: |
93 | case 0x4C51: |
94 | case 0x4F48: |
95 | case 0x504F: |
96 | case 0x5053: |
97 | case 0x5058: |
98 | case 0x5343: |
99 | case 0x5344: |
100 | case 0x5345: |
101 | case 0x5350: |
102 | return LOW; |
103 | case 0x414B: |
104 | case 0x4345: |
105 | case 0x4349: |
106 | case 0x434D: |
107 | case 0x4847: |
108 | case 0x4849: |
109 | case 0x484D: |
110 | case 0x4850: |
111 | case 0x4851: |
112 | case 0x4954: |
113 | case 0x4958: |
114 | case 0x4B43: |
115 | case 0x4B44: |
116 | case 0x4B45: |
117 | case 0x4B47: |
118 | case 0x4B48: |
119 | case 0x4B49: |
120 | case 0x4B4E: |
121 | case 0x4B50: |
122 | case 0x4B52: |
123 | case 0x4B54: |
124 | case 0x4B58: |
125 | case 0x4D50: |
126 | case 0x4D53: |
127 | case 0x4D56: |
128 | case 0x4D58: |
129 | case 0x5044: |
130 | case 0x5045: |
131 | case 0x5046: |
132 | case 0x5047: |
133 | case 0x5049: |
134 | case 0x504B: |
135 | case 0x504D: |
136 | case 0x5254: |
137 | case 0x5347: |
138 | case 0x5349: |
139 | case 0x534B: |
140 | case 0x534D: |
141 | case 0x5356: |
142 | case 0x5358: |
143 | case 0x5443: |
144 | case 0x544B: |
145 | case 0x5647: |
146 | return HIGH; |
147 | default: |
148 | return MEDIUM; |
149 | } |
150 | } |
151 | |
152 | int speed_idx_ep11(int req_type) |
153 | { |
154 | switch (req_type) { |
155 | case 1: |
156 | case 2: |
157 | case 36: |
158 | case 37: |
159 | case 38: |
160 | case 39: |
161 | case 40: |
162 | return LOW; |
163 | case 17: |
164 | case 18: |
165 | case 19: |
166 | case 20: |
167 | case 21: |
168 | case 22: |
169 | case 26: |
170 | case 30: |
171 | case 31: |
172 | case 32: |
173 | case 33: |
174 | case 34: |
175 | case 35: |
176 | return HIGH; |
177 | default: |
178 | return MEDIUM; |
179 | } |
180 | } |
181 | |
182 | /* |
183 | * Convert a ICAMEX message to a type6 MEX message. |
184 | * |
185 | * @zq: crypto device pointer |
186 | * @ap_msg: pointer to AP message |
187 | * @mex: pointer to user input data |
188 | * |
189 | * Returns 0 on success or negative errno value. |
190 | */ |
191 | static int icamex_msg_to_type6mex_msgx(struct zcrypt_queue *zq, |
192 | struct ap_message *ap_msg, |
193 | struct ica_rsa_modexpo *mex) |
194 | { |
195 | static struct type6_hdr static_type6_hdrX = { |
196 | .type = 0x06, |
197 | .offset1 = 0x00000058, |
198 | .agent_id = {'C', 'A',}, |
199 | .function_code = {'P', 'K'}, |
200 | }; |
201 | static struct function_and_rules_block static_pke_fnr = { |
202 | .function_code = {'P', 'K'}, |
203 | .ulen = 10, |
204 | .only_rule = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '} |
205 | }; |
206 | struct { |
207 | struct type6_hdr hdr; |
208 | struct CPRBX cprbx; |
209 | struct function_and_rules_block fr; |
210 | unsigned short length; |
211 | char text[]; |
212 | } __packed * msg = ap_msg->msg; |
213 | int size; |
214 | |
215 | /* |
216 | * The inputdatalength was a selection criteria in the dispatching |
217 | * function zcrypt_rsa_modexpo(). However, make sure the following |
218 | * copy_from_user() never exceeds the allocated buffer space. |
219 | */ |
220 | if (WARN_ON_ONCE(mex->inputdatalength > PAGE_SIZE)) |
221 | return -EINVAL; |
222 | |
223 | /* VUD.ciphertext */ |
224 | msg->length = mex->inputdatalength + 2; |
225 | if (copy_from_user(to: msg->text, from: mex->inputdata, n: mex->inputdatalength)) |
226 | return -EFAULT; |
227 | |
228 | /* Set up key which is located after the variable length text. */ |
229 | size = zcrypt_type6_mex_key_en(mex, p: msg->text + mex->inputdatalength); |
230 | if (size < 0) |
231 | return size; |
232 | size += sizeof(*msg) + mex->inputdatalength; |
233 | |
234 | /* message header, cprbx and f&r */ |
235 | msg->hdr = static_type6_hdrX; |
236 | msg->hdr.tocardlen1 = size - sizeof(msg->hdr); |
237 | msg->hdr.fromcardlen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); |
238 | |
239 | msg->cprbx = static_cprbx; |
240 | msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); |
241 | msg->cprbx.rpl_msgbl = msg->hdr.fromcardlen1; |
242 | |
243 | msg->fr = static_pke_fnr; |
244 | |
245 | msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx); |
246 | |
247 | ap_msg->len = size; |
248 | return 0; |
249 | } |
250 | |
251 | /* |
252 | * Convert a ICACRT message to a type6 CRT message. |
253 | * |
254 | * @zq: crypto device pointer |
255 | * @ap_msg: pointer to AP message |
256 | * @crt: pointer to user input data |
257 | * |
258 | * Returns 0 on success or negative errno value. |
259 | */ |
260 | static int icacrt_msg_to_type6crt_msgx(struct zcrypt_queue *zq, |
261 | struct ap_message *ap_msg, |
262 | struct ica_rsa_modexpo_crt *crt) |
263 | { |
264 | static struct type6_hdr static_type6_hdrX = { |
265 | .type = 0x06, |
266 | .offset1 = 0x00000058, |
267 | .agent_id = {'C', 'A',}, |
268 | .function_code = {'P', 'D'}, |
269 | }; |
270 | static struct function_and_rules_block static_pkd_fnr = { |
271 | .function_code = {'P', 'D'}, |
272 | .ulen = 10, |
273 | .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} |
274 | }; |
275 | |
276 | struct { |
277 | struct type6_hdr hdr; |
278 | struct CPRBX cprbx; |
279 | struct function_and_rules_block fr; |
280 | unsigned short length; |
281 | char text[]; |
282 | } __packed * msg = ap_msg->msg; |
283 | int size; |
284 | |
285 | /* |
286 | * The inputdatalength was a selection criteria in the dispatching |
287 | * function zcrypt_rsa_crt(). However, make sure the following |
288 | * copy_from_user() never exceeds the allocated buffer space. |
289 | */ |
290 | if (WARN_ON_ONCE(crt->inputdatalength > PAGE_SIZE)) |
291 | return -EINVAL; |
292 | |
293 | /* VUD.ciphertext */ |
294 | msg->length = crt->inputdatalength + 2; |
295 | if (copy_from_user(to: msg->text, from: crt->inputdata, n: crt->inputdatalength)) |
296 | return -EFAULT; |
297 | |
298 | /* Set up key which is located after the variable length text. */ |
299 | size = zcrypt_type6_crt_key(crt, p: msg->text + crt->inputdatalength); |
300 | if (size < 0) |
301 | return size; |
302 | size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */ |
303 | |
304 | /* message header, cprbx and f&r */ |
305 | msg->hdr = static_type6_hdrX; |
306 | msg->hdr.tocardlen1 = size - sizeof(msg->hdr); |
307 | msg->hdr.fromcardlen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); |
308 | |
309 | msg->cprbx = static_cprbx; |
310 | msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); |
311 | msg->cprbx.req_parml = msg->cprbx.rpl_msgbl = |
312 | size - sizeof(msg->hdr) - sizeof(msg->cprbx); |
313 | |
314 | msg->fr = static_pkd_fnr; |
315 | |
316 | ap_msg->len = size; |
317 | return 0; |
318 | } |
319 | |
320 | /* |
321 | * Convert a XCRB message to a type6 CPRB message. |
322 | * |
323 | * @zq: crypto device pointer |
324 | * @ap_msg: pointer to AP message |
325 | * @xcRB: pointer to user input data |
326 | * |
327 | * Returns 0 on success or -EFAULT, -EINVAL. |
328 | */ |
329 | struct type86_fmt2_msg { |
330 | struct type86_hdr hdr; |
331 | struct type86_fmt2_ext fmt2; |
332 | } __packed; |
333 | |
334 | static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg, |
335 | struct ica_xcRB *xcrb, |
336 | unsigned int *fcode, |
337 | unsigned short **dom) |
338 | { |
339 | static struct type6_hdr static_type6_hdrX = { |
340 | .type = 0x06, |
341 | .offset1 = 0x00000058, |
342 | }; |
343 | struct { |
344 | struct type6_hdr hdr; |
345 | union { |
346 | struct CPRBX cprbx; |
347 | DECLARE_FLEX_ARRAY(u8, userdata); |
348 | }; |
349 | } __packed * msg = ap_msg->msg; |
350 | |
351 | int rcblen = CEIL4(xcrb->request_control_blk_length); |
352 | int req_sumlen, resp_sumlen; |
353 | char *req_data = ap_msg->msg + sizeof(struct type6_hdr) + rcblen; |
354 | char *function_code; |
355 | |
356 | if (CEIL4(xcrb->request_control_blk_length) < |
357 | xcrb->request_control_blk_length) |
358 | return -EINVAL; /* overflow after alignment*/ |
359 | |
360 | /* length checks */ |
361 | ap_msg->len = sizeof(struct type6_hdr) + |
362 | CEIL4(xcrb->request_control_blk_length) + |
363 | xcrb->request_data_length; |
364 | if (ap_msg->len > ap_msg->bufsize) |
365 | return -EINVAL; |
366 | |
367 | /* |
368 | * Overflow check |
369 | * sum must be greater (or equal) than the largest operand |
370 | */ |
371 | req_sumlen = CEIL4(xcrb->request_control_blk_length) + |
372 | xcrb->request_data_length; |
373 | if ((CEIL4(xcrb->request_control_blk_length) <= |
374 | xcrb->request_data_length) ? |
375 | req_sumlen < xcrb->request_data_length : |
376 | req_sumlen < CEIL4(xcrb->request_control_blk_length)) { |
377 | return -EINVAL; |
378 | } |
379 | |
380 | if (CEIL4(xcrb->reply_control_blk_length) < |
381 | xcrb->reply_control_blk_length) |
382 | return -EINVAL; /* overflow after alignment*/ |
383 | |
384 | /* |
385 | * Overflow check |
386 | * sum must be greater (or equal) than the largest operand |
387 | */ |
388 | resp_sumlen = CEIL4(xcrb->reply_control_blk_length) + |
389 | xcrb->reply_data_length; |
390 | if ((CEIL4(xcrb->reply_control_blk_length) <= |
391 | xcrb->reply_data_length) ? |
392 | resp_sumlen < xcrb->reply_data_length : |
393 | resp_sumlen < CEIL4(xcrb->reply_control_blk_length)) { |
394 | return -EINVAL; |
395 | } |
396 | |
397 | /* prepare type6 header */ |
398 | msg->hdr = static_type6_hdrX; |
399 | memcpy(msg->hdr.agent_id, &xcrb->agent_ID, sizeof(xcrb->agent_ID)); |
400 | msg->hdr.tocardlen1 = xcrb->request_control_blk_length; |
401 | if (xcrb->request_data_length) { |
402 | msg->hdr.offset2 = msg->hdr.offset1 + rcblen; |
403 | msg->hdr.tocardlen2 = xcrb->request_data_length; |
404 | } |
405 | msg->hdr.fromcardlen1 = xcrb->reply_control_blk_length; |
406 | msg->hdr.fromcardlen2 = xcrb->reply_data_length; |
407 | |
408 | /* prepare CPRB */ |
409 | if (z_copy_from_user(userspace, to: msg->userdata, |
410 | from: xcrb->request_control_blk_addr, |
411 | n: xcrb->request_control_blk_length)) |
412 | return -EFAULT; |
413 | if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > |
414 | xcrb->request_control_blk_length) |
415 | return -EINVAL; |
416 | function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; |
417 | memcpy(msg->hdr.function_code, function_code, |
418 | sizeof(msg->hdr.function_code)); |
419 | |
420 | *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1]; |
421 | *dom = (unsigned short *)&msg->cprbx.domain; |
422 | |
423 | /* check subfunction, US and AU need special flag with NQAP */ |
424 | if (memcmp(p: function_code, q: "US" , size: 2) == 0 || |
425 | memcmp(p: function_code, q: "AU" , size: 2) == 0) |
426 | ap_msg->flags |= AP_MSG_FLAG_SPECIAL; |
427 | |
428 | /* check CPRB minor version, set info bits in ap_message flag field */ |
429 | switch (*(unsigned short *)(&msg->cprbx.func_id[0])) { |
430 | case 0x5432: /* "T2" */ |
431 | ap_msg->flags |= AP_MSG_FLAG_USAGE; |
432 | break; |
433 | case 0x5433: /* "T3" */ |
434 | case 0x5435: /* "T5" */ |
435 | case 0x5436: /* "T6" */ |
436 | case 0x5437: /* "T7" */ |
437 | ap_msg->flags |= AP_MSG_FLAG_ADMIN; |
438 | break; |
439 | default: |
440 | ZCRYPT_DBF_DBG("%s unknown CPRB minor version '%c%c'\n" , |
441 | __func__, msg->cprbx.func_id[0], |
442 | msg->cprbx.func_id[1]); |
443 | } |
444 | |
445 | /* copy data block */ |
446 | if (xcrb->request_data_length && |
447 | z_copy_from_user(userspace, to: req_data, from: xcrb->request_data_address, |
448 | n: xcrb->request_data_length)) |
449 | return -EFAULT; |
450 | |
451 | return 0; |
452 | } |
453 | |
454 | static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap_msg, |
455 | struct ep11_urb *xcrb, |
456 | unsigned int *fcode, |
457 | unsigned int *domain) |
458 | { |
459 | unsigned int lfmt; |
460 | static struct type6_hdr static_type6_ep11_hdr = { |
461 | .type = 0x06, |
462 | .rqid = {0x00, 0x01}, |
463 | .function_code = {0x00, 0x00}, |
464 | .agent_id[0] = 0x58, /* {'X'} */ |
465 | .agent_id[1] = 0x43, /* {'C'} */ |
466 | .offset1 = 0x00000058, |
467 | }; |
468 | |
469 | struct { |
470 | struct type6_hdr hdr; |
471 | union { |
472 | struct { |
473 | struct ep11_cprb cprbx; |
474 | unsigned char pld_tag; /* fixed value 0x30 */ |
475 | unsigned char pld_lenfmt; /* length format */ |
476 | } __packed; |
477 | DECLARE_FLEX_ARRAY(u8, userdata); |
478 | }; |
479 | } __packed * msg = ap_msg->msg; |
480 | |
481 | struct pld_hdr { |
482 | unsigned char func_tag; /* fixed value 0x4 */ |
483 | unsigned char func_len; /* fixed value 0x4 */ |
484 | unsigned int func_val; /* function ID */ |
485 | unsigned char dom_tag; /* fixed value 0x4 */ |
486 | unsigned char dom_len; /* fixed value 0x4 */ |
487 | unsigned int dom_val; /* domain id */ |
488 | } __packed * payload_hdr = NULL; |
489 | |
490 | if (CEIL4(xcrb->req_len) < xcrb->req_len) |
491 | return -EINVAL; /* overflow after alignment*/ |
492 | |
493 | /* length checks */ |
494 | ap_msg->len = sizeof(struct type6_hdr) + CEIL4(xcrb->req_len); |
495 | if (ap_msg->len > ap_msg->bufsize) |
496 | return -EINVAL; |
497 | |
498 | if (CEIL4(xcrb->resp_len) < xcrb->resp_len) |
499 | return -EINVAL; /* overflow after alignment*/ |
500 | |
501 | /* prepare type6 header */ |
502 | msg->hdr = static_type6_ep11_hdr; |
503 | msg->hdr.tocardlen1 = xcrb->req_len; |
504 | msg->hdr.fromcardlen1 = xcrb->resp_len; |
505 | |
506 | /* Import CPRB data from the ioctl input parameter */ |
507 | if (z_copy_from_user(userspace, to: msg->userdata, |
508 | from: (char __force __user *)xcrb->req, n: xcrb->req_len)) { |
509 | return -EFAULT; |
510 | } |
511 | |
512 | if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ |
513 | switch (msg->pld_lenfmt & 0x03) { |
514 | case 1: |
515 | lfmt = 2; |
516 | break; |
517 | case 2: |
518 | lfmt = 3; |
519 | break; |
520 | default: |
521 | return -EINVAL; |
522 | } |
523 | } else { |
524 | lfmt = 1; /* length format #1 */ |
525 | } |
526 | payload_hdr = (struct pld_hdr *)((&msg->pld_lenfmt) + lfmt); |
527 | *fcode = payload_hdr->func_val & 0xFFFF; |
528 | |
529 | /* enable special processing based on the cprbs flags special bit */ |
530 | if (msg->cprbx.flags & 0x20) |
531 | ap_msg->flags |= AP_MSG_FLAG_SPECIAL; |
532 | |
533 | /* set info bits in ap_message flag field */ |
534 | if (msg->cprbx.flags & 0x80) |
535 | ap_msg->flags |= AP_MSG_FLAG_ADMIN; |
536 | else |
537 | ap_msg->flags |= AP_MSG_FLAG_USAGE; |
538 | |
539 | *domain = msg->cprbx.target_id; |
540 | |
541 | return 0; |
542 | } |
543 | |
544 | /* |
545 | * Copy results from a type 86 ICA reply message back to user space. |
546 | * |
547 | * @zq: crypto device pointer |
548 | * @reply: reply AP message. |
549 | * @data: pointer to user output data |
550 | * @length: size of user output data |
551 | * |
552 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. |
553 | */ |
554 | struct type86x_reply { |
555 | struct type86_hdr hdr; |
556 | struct type86_fmt2_ext fmt2; |
557 | struct CPRBX cprbx; |
558 | unsigned char pad[4]; /* 4 byte function code/rules block ? */ |
559 | unsigned short length; /* length of data including length field size */ |
560 | char data[]; |
561 | } __packed; |
562 | |
563 | struct type86_ep11_reply { |
564 | struct type86_hdr hdr; |
565 | struct type86_fmt2_ext fmt2; |
566 | struct ep11_cprb cprbx; |
567 | } __packed; |
568 | |
569 | static int convert_type86_ica(struct zcrypt_queue *zq, |
570 | struct ap_message *reply, |
571 | char __user *outputdata, |
572 | unsigned int outputdatalength) |
573 | { |
574 | struct type86x_reply *msg = reply->msg; |
575 | unsigned short service_rc, service_rs; |
576 | unsigned int data_len; |
577 | |
578 | service_rc = msg->cprbx.ccp_rtcode; |
579 | if (unlikely(service_rc != 0)) { |
580 | service_rs = msg->cprbx.ccp_rscode; |
581 | if ((service_rc == 8 && service_rs == 66) || |
582 | (service_rc == 8 && service_rs == 65) || |
583 | (service_rc == 8 && service_rs == 72) || |
584 | (service_rc == 8 && service_rs == 770) || |
585 | (service_rc == 12 && service_rs == 769)) { |
586 | ZCRYPT_DBF_WARN("%s dev=%02x.%04x rc/rs=%d/%d => rc=EINVAL\n" , |
587 | __func__, AP_QID_CARD(zq->queue->qid), |
588 | AP_QID_QUEUE(zq->queue->qid), |
589 | (int)service_rc, (int)service_rs); |
590 | return -EINVAL; |
591 | } |
592 | zq->online = 0; |
593 | pr_err("Crypto dev=%02x.%04x rc/rs=%d/%d online=0 rc=EAGAIN\n" , |
594 | AP_QID_CARD(zq->queue->qid), |
595 | AP_QID_QUEUE(zq->queue->qid), |
596 | (int)service_rc, (int)service_rs); |
597 | ZCRYPT_DBF_ERR("%s dev=%02x.%04x rc/rs=%d/%d => online=0 rc=EAGAIN\n" , |
598 | __func__, AP_QID_CARD(zq->queue->qid), |
599 | AP_QID_QUEUE(zq->queue->qid), |
600 | (int)service_rc, (int)service_rs); |
601 | ap_send_online_uevent(ap_dev: &zq->queue->ap_dev, online: zq->online); |
602 | return -EAGAIN; |
603 | } |
604 | data_len = msg->length - sizeof(msg->length); |
605 | if (data_len > outputdatalength) |
606 | return -EMSGSIZE; |
607 | |
608 | /* Copy the crypto response to user space. */ |
609 | if (copy_to_user(to: outputdata, from: msg->data, n: data_len)) |
610 | return -EFAULT; |
611 | return 0; |
612 | } |
613 | |
614 | /* |
615 | * Copy results from a type 86 XCRB reply message back to user space. |
616 | * |
617 | * @zq: crypto device pointer |
618 | * @reply: reply AP message. |
619 | * @xcrb: pointer to XCRB |
620 | * |
621 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. |
622 | */ |
623 | static int convert_type86_xcrb(bool userspace, struct zcrypt_queue *zq, |
624 | struct ap_message *reply, |
625 | struct ica_xcRB *xcrb) |
626 | { |
627 | struct type86_fmt2_msg *msg = reply->msg; |
628 | char *data = reply->msg; |
629 | |
630 | /* Copy CPRB to user */ |
631 | if (xcrb->reply_control_blk_length < msg->fmt2.count1) { |
632 | ZCRYPT_DBF_DBG("%s reply_control_blk_length %u < required %u => EMSGSIZE\n" , |
633 | __func__, xcrb->reply_control_blk_length, |
634 | msg->fmt2.count1); |
635 | return -EMSGSIZE; |
636 | } |
637 | if (z_copy_to_user(userspace, to: xcrb->reply_control_blk_addr, |
638 | from: data + msg->fmt2.offset1, n: msg->fmt2.count1)) |
639 | return -EFAULT; |
640 | xcrb->reply_control_blk_length = msg->fmt2.count1; |
641 | |
642 | /* Copy data buffer to user */ |
643 | if (msg->fmt2.count2) { |
644 | if (xcrb->reply_data_length < msg->fmt2.count2) { |
645 | ZCRYPT_DBF_DBG("%s reply_data_length %u < required %u => EMSGSIZE\n" , |
646 | __func__, xcrb->reply_data_length, |
647 | msg->fmt2.count2); |
648 | return -EMSGSIZE; |
649 | } |
650 | if (z_copy_to_user(userspace, to: xcrb->reply_data_addr, |
651 | from: data + msg->fmt2.offset2, n: msg->fmt2.count2)) |
652 | return -EFAULT; |
653 | } |
654 | xcrb->reply_data_length = msg->fmt2.count2; |
655 | |
656 | return 0; |
657 | } |
658 | |
659 | /* |
660 | * Copy results from a type 86 EP11 XCRB reply message back to user space. |
661 | * |
662 | * @zq: crypto device pointer |
663 | * @reply: reply AP message. |
664 | * @xcrb: pointer to EP11 user request block |
665 | * |
666 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. |
667 | */ |
668 | static int convert_type86_ep11_xcrb(bool userspace, struct zcrypt_queue *zq, |
669 | struct ap_message *reply, |
670 | struct ep11_urb *xcrb) |
671 | { |
672 | struct type86_fmt2_msg *msg = reply->msg; |
673 | char *data = reply->msg; |
674 | |
675 | if (xcrb->resp_len < msg->fmt2.count1) { |
676 | ZCRYPT_DBF_DBG("%s resp_len %u < required %u => EMSGSIZE\n" , |
677 | __func__, (unsigned int)xcrb->resp_len, |
678 | msg->fmt2.count1); |
679 | return -EMSGSIZE; |
680 | } |
681 | |
682 | /* Copy response CPRB to user */ |
683 | if (z_copy_to_user(userspace, to: (char __force __user *)xcrb->resp, |
684 | from: data + msg->fmt2.offset1, n: msg->fmt2.count1)) |
685 | return -EFAULT; |
686 | xcrb->resp_len = msg->fmt2.count1; |
687 | return 0; |
688 | } |
689 | |
690 | static int convert_type86_rng(struct zcrypt_queue *zq, |
691 | struct ap_message *reply, |
692 | char *buffer) |
693 | { |
694 | struct { |
695 | struct type86_hdr hdr; |
696 | struct type86_fmt2_ext fmt2; |
697 | struct CPRBX cprbx; |
698 | } __packed * msg = reply->msg; |
699 | char *data = reply->msg; |
700 | |
701 | if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) |
702 | return -EINVAL; |
703 | memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); |
704 | return msg->fmt2.count2; |
705 | } |
706 | |
707 | static int convert_response_ica(struct zcrypt_queue *zq, |
708 | struct ap_message *reply, |
709 | char __user *outputdata, |
710 | unsigned int outputdatalength) |
711 | { |
712 | struct type86x_reply *msg = reply->msg; |
713 | |
714 | switch (msg->hdr.type) { |
715 | case TYPE82_RSP_CODE: |
716 | case TYPE88_RSP_CODE: |
717 | return convert_error(zq, reply); |
718 | case TYPE86_RSP_CODE: |
719 | if (msg->cprbx.ccp_rtcode && |
720 | msg->cprbx.ccp_rscode == 0x14f && |
721 | outputdatalength > 256) { |
722 | if (zq->zcard->max_exp_bit_length <= 17) { |
723 | zq->zcard->max_exp_bit_length = 17; |
724 | return -EAGAIN; |
725 | } else { |
726 | return -EINVAL; |
727 | } |
728 | } |
729 | if (msg->hdr.reply_code) |
730 | return convert_error(zq, reply); |
731 | if (msg->cprbx.cprb_ver_id == 0x02) |
732 | return convert_type86_ica(zq, reply, |
733 | outputdata, outputdatalength); |
734 | fallthrough; /* wrong cprb version is an unknown response */ |
735 | default: |
736 | /* Unknown response type, this should NEVER EVER happen */ |
737 | zq->online = 0; |
738 | pr_err("Crypto dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
739 | AP_QID_CARD(zq->queue->qid), |
740 | AP_QID_QUEUE(zq->queue->qid), |
741 | (int)msg->hdr.type); |
742 | ZCRYPT_DBF_ERR( |
743 | "%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
744 | __func__, AP_QID_CARD(zq->queue->qid), |
745 | AP_QID_QUEUE(zq->queue->qid), (int)msg->hdr.type); |
746 | ap_send_online_uevent(ap_dev: &zq->queue->ap_dev, online: zq->online); |
747 | return -EAGAIN; |
748 | } |
749 | } |
750 | |
751 | static int convert_response_xcrb(bool userspace, struct zcrypt_queue *zq, |
752 | struct ap_message *reply, |
753 | struct ica_xcRB *xcrb) |
754 | { |
755 | struct type86x_reply *msg = reply->msg; |
756 | |
757 | switch (msg->hdr.type) { |
758 | case TYPE82_RSP_CODE: |
759 | case TYPE88_RSP_CODE: |
760 | xcrb->status = 0x0008044DL; /* HDD_InvalidParm */ |
761 | return convert_error(zq, reply); |
762 | case TYPE86_RSP_CODE: |
763 | if (msg->hdr.reply_code) { |
764 | memcpy(&xcrb->status, msg->fmt2.apfs, sizeof(u32)); |
765 | return convert_error(zq, reply); |
766 | } |
767 | if (msg->cprbx.cprb_ver_id == 0x02) |
768 | return convert_type86_xcrb(userspace, zq, reply, xcrb); |
769 | fallthrough; /* wrong cprb version is an unknown response */ |
770 | default: /* Unknown response type, this should NEVER EVER happen */ |
771 | xcrb->status = 0x0008044DL; /* HDD_InvalidParm */ |
772 | zq->online = 0; |
773 | pr_err("Crypto dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
774 | AP_QID_CARD(zq->queue->qid), |
775 | AP_QID_QUEUE(zq->queue->qid), |
776 | (int)msg->hdr.type); |
777 | ZCRYPT_DBF_ERR( |
778 | "%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
779 | __func__, AP_QID_CARD(zq->queue->qid), |
780 | AP_QID_QUEUE(zq->queue->qid), (int)msg->hdr.type); |
781 | ap_send_online_uevent(ap_dev: &zq->queue->ap_dev, online: zq->online); |
782 | return -EAGAIN; |
783 | } |
784 | } |
785 | |
786 | static int convert_response_ep11_xcrb(bool userspace, struct zcrypt_queue *zq, |
787 | struct ap_message *reply, struct ep11_urb *xcrb) |
788 | { |
789 | struct type86_ep11_reply *msg = reply->msg; |
790 | |
791 | switch (msg->hdr.type) { |
792 | case TYPE82_RSP_CODE: |
793 | case TYPE87_RSP_CODE: |
794 | return convert_error(zq, reply); |
795 | case TYPE86_RSP_CODE: |
796 | if (msg->hdr.reply_code) |
797 | return convert_error(zq, reply); |
798 | if (msg->cprbx.cprb_ver_id == 0x04) |
799 | return convert_type86_ep11_xcrb(userspace, zq, reply, xcrb); |
800 | fallthrough; /* wrong cprb version is an unknown resp */ |
801 | default: /* Unknown response type, this should NEVER EVER happen */ |
802 | zq->online = 0; |
803 | pr_err("Crypto dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
804 | AP_QID_CARD(zq->queue->qid), |
805 | AP_QID_QUEUE(zq->queue->qid), |
806 | (int)msg->hdr.type); |
807 | ZCRYPT_DBF_ERR( |
808 | "%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
809 | __func__, AP_QID_CARD(zq->queue->qid), |
810 | AP_QID_QUEUE(zq->queue->qid), (int)msg->hdr.type); |
811 | ap_send_online_uevent(ap_dev: &zq->queue->ap_dev, online: zq->online); |
812 | return -EAGAIN; |
813 | } |
814 | } |
815 | |
816 | static int convert_response_rng(struct zcrypt_queue *zq, |
817 | struct ap_message *reply, |
818 | char *data) |
819 | { |
820 | struct type86x_reply *msg = reply->msg; |
821 | |
822 | switch (msg->hdr.type) { |
823 | case TYPE82_RSP_CODE: |
824 | case TYPE88_RSP_CODE: |
825 | return -EINVAL; |
826 | case TYPE86_RSP_CODE: |
827 | if (msg->hdr.reply_code) |
828 | return -EINVAL; |
829 | if (msg->cprbx.cprb_ver_id == 0x02) |
830 | return convert_type86_rng(zq, reply, buffer: data); |
831 | fallthrough; /* wrong cprb version is an unknown response */ |
832 | default: /* Unknown response type, this should NEVER EVER happen */ |
833 | zq->online = 0; |
834 | pr_err("Crypto dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
835 | AP_QID_CARD(zq->queue->qid), |
836 | AP_QID_QUEUE(zq->queue->qid), |
837 | (int)msg->hdr.type); |
838 | ZCRYPT_DBF_ERR( |
839 | "%s dev=%02x.%04x unknown response type 0x%02x => online=0 rc=EAGAIN\n" , |
840 | __func__, AP_QID_CARD(zq->queue->qid), |
841 | AP_QID_QUEUE(zq->queue->qid), (int)msg->hdr.type); |
842 | ap_send_online_uevent(ap_dev: &zq->queue->ap_dev, online: zq->online); |
843 | return -EAGAIN; |
844 | } |
845 | } |
846 | |
847 | /* |
848 | * This function is called from the AP bus code after a crypto request |
849 | * "msg" has finished with the reply message "reply". |
850 | * It is called from tasklet context. |
851 | * @aq: pointer to the AP queue |
852 | * @msg: pointer to the AP message |
853 | * @reply: pointer to the AP reply message |
854 | */ |
855 | static void zcrypt_msgtype6_receive(struct ap_queue *aq, |
856 | struct ap_message *msg, |
857 | struct ap_message *reply) |
858 | { |
859 | static struct error_hdr error_reply = { |
860 | .type = TYPE82_RSP_CODE, |
861 | .reply_code = REP82_ERROR_MACHINE_FAILURE, |
862 | }; |
863 | struct response_type *resp_type = msg->private; |
864 | struct type86x_reply *t86r; |
865 | int len; |
866 | |
867 | /* Copy the reply message to the request message buffer. */ |
868 | if (!reply) |
869 | goto out; /* ap_msg->rc indicates the error */ |
870 | t86r = reply->msg; |
871 | if (t86r->hdr.type == TYPE86_RSP_CODE && |
872 | t86r->cprbx.cprb_ver_id == 0x02) { |
873 | switch (resp_type->type) { |
874 | case CEXXC_RESPONSE_TYPE_ICA: |
875 | len = sizeof(struct type86x_reply) + t86r->length; |
876 | if (len > reply->bufsize || len > msg->bufsize || |
877 | len != reply->len) { |
878 | ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n" , __func__); |
879 | msg->rc = -EMSGSIZE; |
880 | goto out; |
881 | } |
882 | memcpy(msg->msg, reply->msg, len); |
883 | msg->len = len; |
884 | break; |
885 | case CEXXC_RESPONSE_TYPE_XCRB: |
886 | if (t86r->fmt2.count2) |
887 | len = t86r->fmt2.offset2 + t86r->fmt2.count2; |
888 | else |
889 | len = t86r->fmt2.offset1 + t86r->fmt2.count1; |
890 | if (len > reply->bufsize || len > msg->bufsize || |
891 | len != reply->len) { |
892 | ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n" , __func__); |
893 | msg->rc = -EMSGSIZE; |
894 | goto out; |
895 | } |
896 | memcpy(msg->msg, reply->msg, len); |
897 | msg->len = len; |
898 | break; |
899 | default: |
900 | memcpy(msg->msg, &error_reply, sizeof(error_reply)); |
901 | msg->len = sizeof(error_reply); |
902 | } |
903 | } else { |
904 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); |
905 | msg->len = sizeof(error_reply); |
906 | } |
907 | out: |
908 | complete(&resp_type->work); |
909 | } |
910 | |
911 | /* |
912 | * This function is called from the AP bus code after a crypto request |
913 | * "msg" has finished with the reply message "reply". |
914 | * It is called from tasklet context. |
915 | * @aq: pointer to the AP queue |
916 | * @msg: pointer to the AP message |
917 | * @reply: pointer to the AP reply message |
918 | */ |
919 | static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, |
920 | struct ap_message *msg, |
921 | struct ap_message *reply) |
922 | { |
923 | static struct error_hdr error_reply = { |
924 | .type = TYPE82_RSP_CODE, |
925 | .reply_code = REP82_ERROR_MACHINE_FAILURE, |
926 | }; |
927 | struct response_type *resp_type = msg->private; |
928 | struct type86_ep11_reply *t86r; |
929 | int len; |
930 | |
931 | /* Copy the reply message to the request message buffer. */ |
932 | if (!reply) |
933 | goto out; /* ap_msg->rc indicates the error */ |
934 | t86r = reply->msg; |
935 | if (t86r->hdr.type == TYPE86_RSP_CODE && |
936 | t86r->cprbx.cprb_ver_id == 0x04) { |
937 | switch (resp_type->type) { |
938 | case CEXXC_RESPONSE_TYPE_EP11: |
939 | len = t86r->fmt2.offset1 + t86r->fmt2.count1; |
940 | if (len > reply->bufsize || len > msg->bufsize || |
941 | len != reply->len) { |
942 | ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n" , __func__); |
943 | msg->rc = -EMSGSIZE; |
944 | goto out; |
945 | } |
946 | memcpy(msg->msg, reply->msg, len); |
947 | msg->len = len; |
948 | break; |
949 | default: |
950 | memcpy(msg->msg, &error_reply, sizeof(error_reply)); |
951 | msg->len = sizeof(error_reply); |
952 | } |
953 | } else { |
954 | memcpy(msg->msg, reply->msg, sizeof(error_reply)); |
955 | msg->len = sizeof(error_reply); |
956 | } |
957 | out: |
958 | complete(&resp_type->work); |
959 | } |
960 | |
961 | static atomic_t zcrypt_step = ATOMIC_INIT(0); |
962 | |
963 | /* |
964 | * The request distributor calls this function if it picked the CEXxC |
965 | * device to handle a modexpo request. |
966 | * @zq: pointer to zcrypt_queue structure that identifies the |
967 | * CEXxC device to the request distributor |
968 | * @mex: pointer to the modexpo request buffer |
969 | */ |
970 | static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, |
971 | struct ica_rsa_modexpo *mex, |
972 | struct ap_message *ap_msg) |
973 | { |
974 | struct response_type resp_type = { |
975 | .type = CEXXC_RESPONSE_TYPE_ICA, |
976 | }; |
977 | int rc; |
978 | |
979 | ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL); |
980 | if (!ap_msg->msg) |
981 | return -ENOMEM; |
982 | ap_msg->bufsize = PAGE_SIZE; |
983 | ap_msg->receive = zcrypt_msgtype6_receive; |
984 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
985 | atomic_inc_return(v: &zcrypt_step); |
986 | ap_msg->private = &resp_type; |
987 | rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex); |
988 | if (rc) |
989 | goto out_free; |
990 | init_completion(x: &resp_type.work); |
991 | rc = ap_queue_message(aq: zq->queue, ap_msg); |
992 | if (rc) |
993 | goto out_free; |
994 | rc = wait_for_completion_interruptible(x: &resp_type.work); |
995 | if (rc == 0) { |
996 | rc = ap_msg->rc; |
997 | if (rc == 0) |
998 | rc = convert_response_ica(zq, reply: ap_msg, |
999 | outputdata: mex->outputdata, |
1000 | outputdatalength: mex->outputdatalength); |
1001 | } else { |
1002 | /* Signal pending. */ |
1003 | ap_cancel_message(aq: zq->queue, ap_msg); |
1004 | } |
1005 | |
1006 | out_free: |
1007 | free_page((unsigned long)ap_msg->msg); |
1008 | ap_msg->private = NULL; |
1009 | ap_msg->msg = NULL; |
1010 | return rc; |
1011 | } |
1012 | |
1013 | /* |
1014 | * The request distributor calls this function if it picked the CEXxC |
1015 | * device to handle a modexpo_crt request. |
1016 | * @zq: pointer to zcrypt_queue structure that identifies the |
1017 | * CEXxC device to the request distributor |
1018 | * @crt: pointer to the modexpoc_crt request buffer |
1019 | */ |
1020 | static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, |
1021 | struct ica_rsa_modexpo_crt *crt, |
1022 | struct ap_message *ap_msg) |
1023 | { |
1024 | struct response_type resp_type = { |
1025 | .type = CEXXC_RESPONSE_TYPE_ICA, |
1026 | }; |
1027 | int rc; |
1028 | |
1029 | ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL); |
1030 | if (!ap_msg->msg) |
1031 | return -ENOMEM; |
1032 | ap_msg->bufsize = PAGE_SIZE; |
1033 | ap_msg->receive = zcrypt_msgtype6_receive; |
1034 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
1035 | atomic_inc_return(v: &zcrypt_step); |
1036 | ap_msg->private = &resp_type; |
1037 | rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt); |
1038 | if (rc) |
1039 | goto out_free; |
1040 | init_completion(x: &resp_type.work); |
1041 | rc = ap_queue_message(aq: zq->queue, ap_msg); |
1042 | if (rc) |
1043 | goto out_free; |
1044 | rc = wait_for_completion_interruptible(x: &resp_type.work); |
1045 | if (rc == 0) { |
1046 | rc = ap_msg->rc; |
1047 | if (rc == 0) |
1048 | rc = convert_response_ica(zq, reply: ap_msg, |
1049 | outputdata: crt->outputdata, |
1050 | outputdatalength: crt->outputdatalength); |
1051 | } else { |
1052 | /* Signal pending. */ |
1053 | ap_cancel_message(aq: zq->queue, ap_msg); |
1054 | } |
1055 | |
1056 | out_free: |
1057 | free_page((unsigned long)ap_msg->msg); |
1058 | ap_msg->private = NULL; |
1059 | ap_msg->msg = NULL; |
1060 | return rc; |
1061 | } |
1062 | |
1063 | /* |
1064 | * Prepare a CCA AP msg request. |
1065 | * Prepare a CCA AP msg: fetch the required data from userspace, |
1066 | * prepare the AP msg, fill some info into the ap_message struct, |
1067 | * extract some data from the CPRB and give back to the caller. |
1068 | * This function allocates memory and needs an ap_msg prepared |
1069 | * by the caller with ap_init_message(). Also the caller has to |
1070 | * make sure ap_release_message() is always called even on failure. |
1071 | */ |
1072 | int prep_cca_ap_msg(bool userspace, struct ica_xcRB *xcrb, |
1073 | struct ap_message *ap_msg, |
1074 | unsigned int *func_code, unsigned short **dom) |
1075 | { |
1076 | struct response_type resp_type = { |
1077 | .type = CEXXC_RESPONSE_TYPE_XCRB, |
1078 | }; |
1079 | |
1080 | ap_msg->bufsize = atomic_read(v: &ap_max_msg_size); |
1081 | ap_msg->msg = kmalloc(size: ap_msg->bufsize, GFP_KERNEL); |
1082 | if (!ap_msg->msg) |
1083 | return -ENOMEM; |
1084 | ap_msg->receive = zcrypt_msgtype6_receive; |
1085 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
1086 | atomic_inc_return(v: &zcrypt_step); |
1087 | ap_msg->private = kmemdup(p: &resp_type, size: sizeof(resp_type), GFP_KERNEL); |
1088 | if (!ap_msg->private) |
1089 | return -ENOMEM; |
1090 | return xcrb_msg_to_type6cprb_msgx(userspace, ap_msg, xcrb, fcode: func_code, dom); |
1091 | } |
1092 | |
1093 | /* |
1094 | * The request distributor calls this function if it picked the CEXxC |
1095 | * device to handle a send_cprb request. |
1096 | * @zq: pointer to zcrypt_queue structure that identifies the |
1097 | * CEXxC device to the request distributor |
1098 | * @xcrb: pointer to the send_cprb request buffer |
1099 | */ |
1100 | static long zcrypt_msgtype6_send_cprb(bool userspace, struct zcrypt_queue *zq, |
1101 | struct ica_xcRB *xcrb, |
1102 | struct ap_message *ap_msg) |
1103 | { |
1104 | struct response_type *rtype = ap_msg->private; |
1105 | struct { |
1106 | struct type6_hdr hdr; |
1107 | struct CPRBX cprbx; |
1108 | /* ... more data blocks ... */ |
1109 | } __packed * msg = ap_msg->msg; |
1110 | unsigned int max_payload_size; |
1111 | int rc, delta; |
1112 | |
1113 | /* calculate maximum payload for this card and msg type */ |
1114 | max_payload_size = zq->reply.bufsize - sizeof(struct type86_fmt2_msg); |
1115 | |
1116 | /* limit each of the two from fields to the maximum payload size */ |
1117 | msg->hdr.fromcardlen1 = min(msg->hdr.fromcardlen1, max_payload_size); |
1118 | msg->hdr.fromcardlen2 = min(msg->hdr.fromcardlen2, max_payload_size); |
1119 | |
1120 | /* calculate delta if the sum of both exceeds max payload size */ |
1121 | delta = msg->hdr.fromcardlen1 + msg->hdr.fromcardlen2 |
1122 | - max_payload_size; |
1123 | if (delta > 0) { |
1124 | /* |
1125 | * Sum exceeds maximum payload size, prune fromcardlen1 |
1126 | * (always trust fromcardlen2) |
1127 | */ |
1128 | if (delta > msg->hdr.fromcardlen1) { |
1129 | rc = -EINVAL; |
1130 | goto out; |
1131 | } |
1132 | msg->hdr.fromcardlen1 -= delta; |
1133 | } |
1134 | |
1135 | init_completion(x: &rtype->work); |
1136 | rc = ap_queue_message(aq: zq->queue, ap_msg); |
1137 | if (rc) |
1138 | goto out; |
1139 | rc = wait_for_completion_interruptible(x: &rtype->work); |
1140 | if (rc == 0) { |
1141 | rc = ap_msg->rc; |
1142 | if (rc == 0) |
1143 | rc = convert_response_xcrb(userspace, zq, reply: ap_msg, xcrb); |
1144 | } else { |
1145 | /* Signal pending. */ |
1146 | ap_cancel_message(aq: zq->queue, ap_msg); |
1147 | } |
1148 | |
1149 | if (rc == -EAGAIN && ap_msg->flags & AP_MSG_FLAG_ADMIN) |
1150 | rc = -EIO; /* do not retry administrative requests */ |
1151 | |
1152 | out: |
1153 | if (rc) |
1154 | ZCRYPT_DBF_DBG("%s send cprb at dev=%02x.%04x rc=%d\n" , |
1155 | __func__, AP_QID_CARD(zq->queue->qid), |
1156 | AP_QID_QUEUE(zq->queue->qid), rc); |
1157 | return rc; |
1158 | } |
1159 | |
1160 | /* |
1161 | * Prepare an EP11 AP msg request. |
1162 | * Prepare an EP11 AP msg: fetch the required data from userspace, |
1163 | * prepare the AP msg, fill some info into the ap_message struct, |
1164 | * extract some data from the CPRB and give back to the caller. |
1165 | * This function allocates memory and needs an ap_msg prepared |
1166 | * by the caller with ap_init_message(). Also the caller has to |
1167 | * make sure ap_release_message() is always called even on failure. |
1168 | */ |
1169 | int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb, |
1170 | struct ap_message *ap_msg, |
1171 | unsigned int *func_code, unsigned int *domain) |
1172 | { |
1173 | struct response_type resp_type = { |
1174 | .type = CEXXC_RESPONSE_TYPE_EP11, |
1175 | }; |
1176 | |
1177 | ap_msg->bufsize = atomic_read(v: &ap_max_msg_size); |
1178 | ap_msg->msg = kmalloc(size: ap_msg->bufsize, GFP_KERNEL); |
1179 | if (!ap_msg->msg) |
1180 | return -ENOMEM; |
1181 | ap_msg->receive = zcrypt_msgtype6_receive_ep11; |
1182 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
1183 | atomic_inc_return(v: &zcrypt_step); |
1184 | ap_msg->private = kmemdup(p: &resp_type, size: sizeof(resp_type), GFP_KERNEL); |
1185 | if (!ap_msg->private) |
1186 | return -ENOMEM; |
1187 | return xcrb_msg_to_type6_ep11cprb_msgx(userspace, ap_msg, xcrb, |
1188 | fcode: func_code, domain); |
1189 | } |
1190 | |
1191 | /* |
1192 | * The request distributor calls this function if it picked the CEX4P |
1193 | * device to handle a send_ep11_cprb request. |
1194 | * @zq: pointer to zcrypt_queue structure that identifies the |
1195 | * CEX4P device to the request distributor |
1196 | * @xcrb: pointer to the ep11 user request block |
1197 | */ |
1198 | static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue *zq, |
1199 | struct ep11_urb *xcrb, |
1200 | struct ap_message *ap_msg) |
1201 | { |
1202 | int rc; |
1203 | unsigned int lfmt; |
1204 | struct response_type *rtype = ap_msg->private; |
1205 | struct { |
1206 | struct type6_hdr hdr; |
1207 | struct ep11_cprb cprbx; |
1208 | unsigned char pld_tag; /* fixed value 0x30 */ |
1209 | unsigned char pld_lenfmt; /* payload length format */ |
1210 | } __packed * msg = ap_msg->msg; |
1211 | struct pld_hdr { |
1212 | unsigned char func_tag; /* fixed value 0x4 */ |
1213 | unsigned char func_len; /* fixed value 0x4 */ |
1214 | unsigned int func_val; /* function ID */ |
1215 | unsigned char dom_tag; /* fixed value 0x4 */ |
1216 | unsigned char dom_len; /* fixed value 0x4 */ |
1217 | unsigned int dom_val; /* domain id */ |
1218 | } __packed * payload_hdr = NULL; |
1219 | |
1220 | /* |
1221 | * The target domain field within the cprb body/payload block will be |
1222 | * replaced by the usage domain for non-management commands only. |
1223 | * Therefore we check the first bit of the 'flags' parameter for |
1224 | * management command indication. |
1225 | * 0 - non management command |
1226 | * 1 - management command |
1227 | */ |
1228 | if (!((msg->cprbx.flags & 0x80) == 0x80)) { |
1229 | msg->cprbx.target_id = (unsigned int) |
1230 | AP_QID_QUEUE(zq->queue->qid); |
1231 | |
1232 | if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ |
1233 | switch (msg->pld_lenfmt & 0x03) { |
1234 | case 1: |
1235 | lfmt = 2; |
1236 | break; |
1237 | case 2: |
1238 | lfmt = 3; |
1239 | break; |
1240 | default: |
1241 | return -EINVAL; |
1242 | } |
1243 | } else { |
1244 | lfmt = 1; /* length format #1 */ |
1245 | } |
1246 | payload_hdr = (struct pld_hdr *)((&msg->pld_lenfmt) + lfmt); |
1247 | payload_hdr->dom_val = (unsigned int) |
1248 | AP_QID_QUEUE(zq->queue->qid); |
1249 | } |
1250 | |
1251 | /* |
1252 | * Set the queue's reply buffer length minus the two prepend headers |
1253 | * as reply limit for the card firmware. |
1254 | */ |
1255 | msg->hdr.fromcardlen1 = zq->reply.bufsize - |
1256 | sizeof(struct type86_hdr) - sizeof(struct type86_fmt2_ext); |
1257 | |
1258 | init_completion(x: &rtype->work); |
1259 | rc = ap_queue_message(aq: zq->queue, ap_msg); |
1260 | if (rc) |
1261 | goto out; |
1262 | rc = wait_for_completion_interruptible(x: &rtype->work); |
1263 | if (rc == 0) { |
1264 | rc = ap_msg->rc; |
1265 | if (rc == 0) |
1266 | rc = convert_response_ep11_xcrb(userspace, zq, reply: ap_msg, xcrb); |
1267 | } else { |
1268 | /* Signal pending. */ |
1269 | ap_cancel_message(aq: zq->queue, ap_msg); |
1270 | } |
1271 | |
1272 | if (rc == -EAGAIN && ap_msg->flags & AP_MSG_FLAG_ADMIN) |
1273 | rc = -EIO; /* do not retry administrative requests */ |
1274 | |
1275 | out: |
1276 | if (rc) |
1277 | ZCRYPT_DBF_DBG("%s send cprb at dev=%02x.%04x rc=%d\n" , |
1278 | __func__, AP_QID_CARD(zq->queue->qid), |
1279 | AP_QID_QUEUE(zq->queue->qid), rc); |
1280 | return rc; |
1281 | } |
1282 | |
1283 | int prep_rng_ap_msg(struct ap_message *ap_msg, int *func_code, |
1284 | unsigned int *domain) |
1285 | { |
1286 | struct response_type resp_type = { |
1287 | .type = CEXXC_RESPONSE_TYPE_XCRB, |
1288 | }; |
1289 | |
1290 | ap_msg->bufsize = AP_DEFAULT_MAX_MSG_SIZE; |
1291 | ap_msg->msg = kmalloc(size: ap_msg->bufsize, GFP_KERNEL); |
1292 | if (!ap_msg->msg) |
1293 | return -ENOMEM; |
1294 | ap_msg->receive = zcrypt_msgtype6_receive; |
1295 | ap_msg->psmid = (((unsigned long)current->pid) << 32) + |
1296 | atomic_inc_return(v: &zcrypt_step); |
1297 | ap_msg->private = kmemdup(p: &resp_type, size: sizeof(resp_type), GFP_KERNEL); |
1298 | if (!ap_msg->private) |
1299 | return -ENOMEM; |
1300 | |
1301 | rng_type6cprb_msgx(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain); |
1302 | |
1303 | *func_code = HWRNG; |
1304 | return 0; |
1305 | } |
1306 | |
1307 | /* |
1308 | * The request distributor calls this function if it picked the CEXxC |
1309 | * device to generate random data. |
1310 | * @zq: pointer to zcrypt_queue structure that identifies the |
1311 | * CEXxC device to the request distributor |
1312 | * @buffer: pointer to a memory page to return random data |
1313 | */ |
1314 | static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, |
1315 | char *buffer, struct ap_message *ap_msg) |
1316 | { |
1317 | struct { |
1318 | struct type6_hdr hdr; |
1319 | struct CPRBX cprbx; |
1320 | char function_code[2]; |
1321 | short int rule_length; |
1322 | char rule[8]; |
1323 | short int verb_length; |
1324 | short int key_length; |
1325 | } __packed * msg = ap_msg->msg; |
1326 | struct response_type *rtype = ap_msg->private; |
1327 | int rc; |
1328 | |
1329 | msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); |
1330 | |
1331 | init_completion(x: &rtype->work); |
1332 | rc = ap_queue_message(aq: zq->queue, ap_msg); |
1333 | if (rc) |
1334 | goto out; |
1335 | rc = wait_for_completion_interruptible(x: &rtype->work); |
1336 | if (rc == 0) { |
1337 | rc = ap_msg->rc; |
1338 | if (rc == 0) |
1339 | rc = convert_response_rng(zq, reply: ap_msg, data: buffer); |
1340 | } else { |
1341 | /* Signal pending. */ |
1342 | ap_cancel_message(aq: zq->queue, ap_msg); |
1343 | } |
1344 | out: |
1345 | return rc; |
1346 | } |
1347 | |
1348 | /* |
1349 | * The crypto operations for a CEXxC card. |
1350 | */ |
1351 | |
1352 | static struct zcrypt_ops zcrypt_msgtype6_ops = { |
1353 | .owner = THIS_MODULE, |
1354 | .name = MSGTYPE06_NAME, |
1355 | .variant = MSGTYPE06_VARIANT_DEFAULT, |
1356 | .rsa_modexpo = zcrypt_msgtype6_modexpo, |
1357 | .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt, |
1358 | .send_cprb = zcrypt_msgtype6_send_cprb, |
1359 | .rng = zcrypt_msgtype6_rng, |
1360 | }; |
1361 | |
1362 | static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = { |
1363 | .owner = THIS_MODULE, |
1364 | .name = MSGTYPE06_NAME, |
1365 | .variant = MSGTYPE06_VARIANT_EP11, |
1366 | .rsa_modexpo = NULL, |
1367 | .rsa_modexpo_crt = NULL, |
1368 | .send_ep11_cprb = zcrypt_msgtype6_send_ep11_cprb, |
1369 | }; |
1370 | |
1371 | void __init zcrypt_msgtype6_init(void) |
1372 | { |
1373 | zcrypt_msgtype_register(&zcrypt_msgtype6_ops); |
1374 | zcrypt_msgtype_register(&zcrypt_msgtype6_ep11_ops); |
1375 | } |
1376 | |
1377 | void __exit zcrypt_msgtype6_exit(void) |
1378 | { |
1379 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops); |
1380 | zcrypt_msgtype_unregister(&zcrypt_msgtype6_ep11_ops); |
1381 | } |
1382 | |