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