1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2018-2021, 2024 NXP
4 *
5 * Implementation of ECC functions
6 */
7 #include <caam_acipher.h>
8 #include <caam_common.h>
9 #include <caam_hal_ctrl.h>
10 #include <caam_jr.h>
11 #include <caam_key.h>
12 #include <caam_trace.h>
13 #include <caam_utils_mem.h>
14 #include <caam_utils_status.h>
15 #include <drvcrypt.h>
16 #include <drvcrypt_acipher.h>
17 #include <mm/core_memprot.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <tee/cache.h>
21 #include <utee_types.h>
22
23 #ifdef CFG_CAAM_64BIT
24 #define MAX_DESC_KEY_GEN 8
25 #define MAX_DESC_SIGN 13
26 #define MAX_DESC_VERIFY 15
27 #define MAX_DESC_SHARED 10
28 #else
29 #define MAX_DESC_KEY_GEN 6
30 #define MAX_DESC_SIGN 9
31 #define MAX_DESC_VERIFY 10
32 #define MAX_DESC_SHARED 7
33 #endif
34
35 /*
36 * Definition of the local ECC Keypair
37 * Public Key format (x, y)
38 * Private Key format (d)
39 */
40 struct caam_ecc_keypair {
41 struct caambuf xy;
42 struct caamkey d;
43 };
44
45 /*
46 * Free local ECC keypair
47 *
48 * @key ECC keypair
49 */
do_keypair_free(struct caam_ecc_keypair * key)50 static void do_keypair_free(struct caam_ecc_keypair *key)
51 {
52 caam_free_buf(&key->xy);
53 caam_key_free(&key->d);
54 }
55
56 /*
57 * Convert Crypto ECC Key to local ECC Public Key
58 *
59 * @outkey [out] Output keypair in local format
60 * @inkey Input key in TEE Crypto format
61 * @size_sec Security size in bytes
62 */
do_keypub_conv(struct caam_ecc_keypair * outkey,const struct ecc_public_key * inkey,size_t size_sec)63 static enum caam_status do_keypub_conv(struct caam_ecc_keypair *outkey,
64 const struct ecc_public_key *inkey,
65 size_t size_sec)
66 {
67 enum caam_status retstatus = CAAM_OUT_MEMORY;
68 size_t x_size = 0;
69 size_t y_size = 0;
70
71 ECC_TRACE("ECC Convert Public Key size %zu bytes", size_sec);
72
73 /* Point (x y) is twice security key size */
74 retstatus = caam_calloc_buf(&outkey->xy, 2 * size_sec);
75 if (retstatus != CAAM_NO_ERROR)
76 return retstatus;
77
78 /* Copy x and y and get the number of bytes to pad with 0's */
79 x_size = crypto_bignum_num_bytes(inkey->x);
80 crypto_bignum_bn2bin(inkey->x, outkey->xy.data + size_sec - x_size);
81
82 y_size = crypto_bignum_num_bytes(inkey->y);
83 crypto_bignum_bn2bin(inkey->y, outkey->xy.data + 2 * size_sec - y_size);
84
85 cache_operation(TEE_CACHECLEAN, outkey->xy.data, outkey->xy.length);
86
87 return CAAM_NO_ERROR;
88 }
89
90 /*
91 * Convert Crypto ECC Key to local ECC Keypair Key
92 * Don't convert the exponent e not used in decryption
93 *
94 * @outkey [out] Output keypair in local format
95 * @inkey Input key in TEE Crypto format
96 * @size_sec Security size in bytes
97 */
do_keypair_conv(struct caam_ecc_keypair * outkey,const struct ecc_keypair * inkey,size_t size_sec)98 static enum caam_status do_keypair_conv(struct caam_ecc_keypair *outkey,
99 const struct ecc_keypair *inkey,
100 size_t size_sec)
101 {
102 enum caam_status retstatus = CAAM_OUT_MEMORY;
103
104 ECC_TRACE("ECC Convert Keypair size %zu bytes", size_sec);
105
106 /* Private key is only scalar d of sec_size bytes */
107 retstatus = caam_key_deserialize_from_bn(inkey->d, &outkey->d,
108 size_sec);
109 if (retstatus)
110 return retstatus;
111
112 caam_key_cache_op(TEE_CACHEFLUSH, &outkey->d);
113
114 ECC_DUMPBUF("Outkey", outkey->d.buf.data, outkey->d.buf.length);
115
116 return CAAM_NO_ERROR;
117 }
118
119 /*
120 * Convert TEE ECC Curve to CAAM ECC Curve
121 *
122 * @tee_curve TEE ECC Curve
123 */
get_caam_curve(uint32_t tee_curve)124 static enum caam_ecc_curve get_caam_curve(uint32_t tee_curve)
125 {
126 enum caam_ecc_curve caam_curve = CAAM_ECC_UNKNOWN;
127
128 if (tee_curve > 0 &&
129 tee_curve < CAAM_ECC_MAX + TEE_ECC_CURVE_NIST_P192) {
130 /*
131 * Realign TEE Curve assuming NIST_P192 is the first entry in
132 * the list of supported ECC curves.
133 */
134 caam_curve = tee_curve - TEE_ECC_CURVE_NIST_P192
135 + CAAM_ECC_P192;
136 }
137
138 return caam_curve;
139 }
140
141 /*
142 * Allocate a ECC keypair
143 *
144 * @key Keypair
145 * @type Type of ECC key
146 * @size_bits Key size in bits
147 */
do_allocate_keypair(struct ecc_keypair * key,uint32_t type,size_t size_bits)148 static TEE_Result do_allocate_keypair(struct ecc_keypair *key,
149 uint32_t type,
150 size_t size_bits)
151 {
152 ECC_TRACE("Allocate Keypair of %zu bits", size_bits);
153
154 switch (type) {
155 case TEE_TYPE_SM2_PKE_KEYPAIR:
156 case TEE_TYPE_SM2_DSA_KEYPAIR:
157 /* Software fallback */
158 return TEE_ERROR_NOT_IMPLEMENTED;
159 default:
160 break;
161 }
162
163 /* Initialize the key fields to NULL */
164 memset(key, 0, sizeof(*key));
165
166 /* Allocate Secure Scalar */
167 key->d = crypto_bignum_allocate(CFG_CORE_BIGNUM_MAX_BITS);
168 if (!key->d)
169 goto err;
170
171 /* Allocate Public coordinate X */
172 key->x = crypto_bignum_allocate(size_bits);
173 if (!key->x)
174 goto err;
175
176 /* Allocate Public coordinate Y */
177 key->y = crypto_bignum_allocate(size_bits);
178 if (!key->y)
179 goto err;
180
181 return TEE_SUCCESS;
182
183 err:
184 ECC_TRACE("Allocation error");
185
186 crypto_bignum_free(&key->d);
187 crypto_bignum_free(&key->x);
188
189 return TEE_ERROR_OUT_OF_MEMORY;
190 }
191
192 /*
193 * Allocate an ECC Public Key
194 *
195 * @key Public Key
196 * @type Type of ECC key
197 * @size_bits Key size in bits
198 */
do_allocate_publickey(struct ecc_public_key * key,uint32_t type,size_t size_bits)199 static TEE_Result do_allocate_publickey(struct ecc_public_key *key,
200 uint32_t type,
201 size_t size_bits)
202 {
203 ECC_TRACE("Allocate Public Key of %zu bits", size_bits);
204
205 switch (type) {
206 case TEE_TYPE_SM2_PKE_PUBLIC_KEY:
207 case TEE_TYPE_SM2_DSA_PUBLIC_KEY:
208 /* Software fallback */
209 return TEE_ERROR_NOT_IMPLEMENTED;
210 default:
211 break;
212 }
213
214 /* Initialize the key fields to NULL */
215 memset(key, 0, sizeof(*key));
216
217 /* Allocate Public coordinate X */
218 key->x = crypto_bignum_allocate(size_bits);
219 if (!key->x)
220 goto err;
221
222 /* Allocate Public coordinate Y */
223 key->y = crypto_bignum_allocate(size_bits);
224 if (!key->y)
225 goto err;
226
227 return TEE_SUCCESS;
228
229 err:
230 ECC_TRACE("Allocation error");
231
232 crypto_bignum_free(&key->x);
233
234 return TEE_ERROR_OUT_OF_MEMORY;
235 }
236
237 /*
238 * Free an ECC public key
239 *
240 * @key Public Key
241 */
do_free_publickey(struct ecc_public_key * key)242 static void do_free_publickey(struct ecc_public_key *key)
243 {
244 crypto_bignum_free(&key->x);
245 crypto_bignum_free(&key->y);
246 }
247
248 /*
249 * Generate ECC keypair
250 *
251 * @key [out] Keypair
252 * @key_size Key size in bits multiple of 8 bits
253 */
do_gen_keypair(struct ecc_keypair * key,size_t key_size)254 static TEE_Result do_gen_keypair(struct ecc_keypair *key, size_t key_size)
255 {
256 TEE_Result ret = TEE_ERROR_GENERIC;
257 enum caam_status retstatus = CAAM_FAILURE;
258 enum caam_ecc_curve curve = CAAM_ECC_UNKNOWN;
259 struct caamkey d = { };
260 struct caambuf xy = { };
261 struct caam_jobctx jobctx = { };
262 uint32_t *desc = NULL;
263 uint32_t desclen = 0;
264 enum caam_key_type key_type = caam_key_default_key_gen_type();
265
266 ECC_TRACE("Generate Keypair of %zu bits", key_size);
267
268 /* The key size must be a multiple of 8 bits */
269 key_size = ROUNDUP(key_size, 8);
270
271 /* Verify first if the curve is supported */
272 curve = get_caam_curve(key->curve);
273 if (curve == CAAM_ECC_UNKNOWN)
274 return TEE_ERROR_BAD_PARAMETERS;
275
276 /* Allocate the job used to prepare the operation */
277 desc = caam_calloc_desc(MAX_DESC_KEY_GEN);
278 if (!desc) {
279 ret = TEE_ERROR_OUT_OF_MEMORY;
280 goto out;
281 }
282
283 /*
284 * Allocate secure and public keys in two buffers
285 * Secure key size = key_size align in bytes
286 * Public key size = (key_size * 2) align in bytes
287 */
288 d.key_type = key_type;
289 d.sec_size = ROUNDUP_DIV(key_size, 8);
290 d.is_blob = false;
291
292 retstatus = caam_key_alloc(&d);
293 if (retstatus != CAAM_NO_ERROR) {
294 ret = caam_status_to_tee_result(retstatus);
295 goto out;
296 }
297
298 retstatus = caam_alloc_align_buf(&xy, (key_size / 8) * 2);
299 if (retstatus != CAAM_NO_ERROR) {
300 ret = caam_status_to_tee_result(retstatus);
301 goto out;
302 }
303
304 /* Build the descriptor using Predefined ECC curve */
305 caam_desc_init(desc);
306 caam_desc_add_word(desc, DESC_HEADER(0));
307 caam_desc_add_word(desc, PDB_PKGEN_PD1 | PDB_ECC_ECDSEL(curve));
308 caam_desc_add_ptr(desc, d.buf.paddr);
309 caam_desc_add_ptr(desc, xy.paddr);
310
311 switch (key_type) {
312 case CAAM_KEY_PLAIN_TEXT:
313 caam_desc_add_word(desc, PK_KEYPAIR_GEN(ECC, NONE));
314 break;
315 case CAAM_KEY_BLACK_ECB:
316 caam_desc_add_word(desc, PK_KEYPAIR_GEN(ECC, ECB));
317 break;
318 case CAAM_KEY_BLACK_CCM:
319 caam_desc_add_word(desc, PK_KEYPAIR_GEN(ECC, CCM));
320 break;
321 default:
322 ret = TEE_ERROR_GENERIC;
323 goto out;
324 }
325
326 desclen = caam_desc_get_len(desc);
327 caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
328
329 ECC_DUMPDESC(desc);
330
331 jobctx.desc = desc;
332 caam_key_cache_op(TEE_CACHEFLUSH, &d);
333 cache_operation(TEE_CACHEFLUSH, xy.data, xy.length);
334
335 retstatus = caam_jr_enqueue(&jobctx, NULL);
336
337 if (retstatus == CAAM_NO_ERROR) {
338 caam_key_cache_op(TEE_CACHEINVALIDATE, &d);
339 cache_operation(TEE_CACHEINVALIDATE, xy.data, xy.length);
340
341 /* Copy all keypair parameters */
342 retstatus = caam_key_serialize_to_bn(key->d, &d);
343 if (retstatus) {
344 ret = caam_status_to_tee_result(retstatus);
345 goto out;
346 }
347
348 ret = crypto_bignum_bin2bn(xy.data, xy.length / 2, key->x);
349 if (ret != TEE_SUCCESS)
350 goto out;
351
352 ret = crypto_bignum_bin2bn(xy.data + xy.length / 2,
353 xy.length / 2, key->y);
354 if (ret != TEE_SUCCESS)
355 goto out;
356
357 ECC_DUMPBUF("D", d.buf.data, key_size / 8);
358 ECC_DUMPBUF("X", xy.data, xy.length / 2);
359 ECC_DUMPBUF("Y", xy.data + xy.length / 2, xy.length / 2);
360 } else {
361 ECC_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
362 ret = job_status_to_tee_result(jobctx.status);
363 }
364
365 out:
366 caam_free_desc(&desc);
367 caam_key_free(&d);
368 caam_free_buf(&xy);
369
370 return ret;
371 }
372
373 /*
374 * Check if MES_REP to be sent in descriptor is 00.
375 * Only required in case message length and key size is more than 40bytes
376 * because of limitation of Class 2 context register size on i.MX8M series.
377 * Example case below:
378 * When we try to do signature with P384-SHA384, in this case the key size
379 * will be 48bytes and Message size will also be 48bytes.
380 * This will work only when we set MES_REP = 0 in descriptor,
381 * but in this case, we don't need the padding to be done on the message.
382 *
383 * @msg_length: Message Length in bytes
384 * @key_size: Key size in bytes
385 */
msg_mes_rep(size_t msg_length,size_t key_size)386 static bool msg_mes_rep(size_t msg_length, size_t key_size)
387 {
388 return IS_ENABLED(CFG_NXP_CAAM_C2_CTX_REG_WA) && msg_length > 40 &&
389 key_size > 40;
390 }
391
392 /*
393 * Check if padding is required on message to make it of same length
394 * as that of key size.
395 * Only required in case message length and key size is more than 40bytes
396 * because of limitation of Class 2 context register size on i.MX8M series.
397 * So this will be applicable on P384 and P521 ECC curves because these
398 * curves have key_size more than 40bytes.
399 *
400 * @msg_length: Message Length in bytes
401 * @key_size: Key size in bytes
402 */
padding_required(size_t msg_length,size_t key_size)403 static bool padding_required(size_t msg_length, size_t key_size)
404 {
405 return msg_mes_rep(msg_length, key_size) && msg_length < key_size;
406 }
407
408 /*
409 * Add padding of 00s in start of message
410 *
411 * @buf: Buffer in which padded message will be placed.
412 * @data: Original message
413 * @msg_length: Message Length in bytes
414 * @key_size: Key Size in bytes
415 */
add_padding(struct caambuf * buf,uint8_t * data,size_t msg_length,size_t key_size)416 static TEE_Result add_padding(struct caambuf *buf, uint8_t *data,
417 size_t msg_length, size_t key_size)
418 {
419 enum caam_status retstatus = CAAM_FAILURE;
420
421 retstatus = caam_calloc_align_buf(buf, key_size);
422 if (retstatus != CAAM_NO_ERROR)
423 return caam_status_to_tee_result(retstatus);
424
425 memcpy(buf->data + key_size - msg_length, data, msg_length);
426
427 return TEE_SUCCESS;
428 }
429
430 /*
431 * Signature of ECC message
432 * Note the message to sign is already hashed
433 *
434 * @sdata [in/out] ECC data to sign / Signature
435 */
do_sign(struct drvcrypt_sign_data * sdata)436 static TEE_Result do_sign(struct drvcrypt_sign_data *sdata)
437 {
438 TEE_Result ret = TEE_ERROR_GENERIC;
439 enum caam_status retstatus = CAAM_FAILURE;
440 enum caam_ecc_curve curve = CAAM_ECC_UNKNOWN;
441 struct ecc_keypair *inkey = sdata->key;
442 struct caam_ecc_keypair ecckey = { };
443 struct caam_jobctx jobctx = { };
444 uint32_t *desc = NULL;
445 uint32_t desclen = 0;
446 struct caamdmaobj msg = { };
447 size_t sign_len = 0;
448 struct caamdmaobj sign_c = { };
449 struct caamdmaobj sign_d = { };
450 uint32_t pdb_sgt_flags = 0;
451 struct caambuf caambuf_msg = { };
452
453 ECC_TRACE("ECC Signature");
454
455 /* Verify first if the curve is supported */
456 curve = get_caam_curve(inkey->curve);
457 if (curve == CAAM_ECC_UNKNOWN)
458 return TEE_ERROR_BAD_PARAMETERS;
459
460 /* Allocate the job descriptor */
461 desc = caam_calloc_desc(MAX_DESC_SIGN);
462 if (!desc) {
463 ret = TEE_ERROR_OUT_OF_MEMORY;
464 goto out;
465 }
466
467 /* Convert the private key to a local key */
468 retstatus = do_keypair_conv(&ecckey, inkey, sdata->size_sec);
469 if (retstatus != CAAM_NO_ERROR) {
470 ret = caam_status_to_tee_result(retstatus);
471 goto out;
472 }
473
474 ECC_DUMPBUF("Message", sdata->message.data, sdata->message.length);
475
476 if (padding_required(sdata->message.length, sdata->size_sec)) {
477 ret = add_padding(&caambuf_msg, sdata->message.data,
478 sdata->message.length, sdata->size_sec);
479 if (ret)
480 goto out;
481
482 /* Prepare the input message CAAM Descriptor entry */
483 ret = caam_dmaobj_input_sgtbuf(&msg, caambuf_msg.data,
484 caambuf_msg.length);
485 if (ret)
486 goto out;
487
488 ECC_DUMPBUF("Padded Message", caambuf_msg.data,
489 caambuf_msg.length);
490 } else {
491 /* Prepare the input message CAAM Descriptor entry */
492 ret = caam_dmaobj_input_sgtbuf(&msg, sdata->message.data,
493 sdata->message.length);
494 if (ret)
495 goto out;
496 }
497
498 if (msg.sgtbuf.sgt_type)
499 pdb_sgt_flags |= PDB_SGT_PKSIGN_MSG;
500
501 caam_dmaobj_cache_push(&msg);
502
503 /*
504 * ReAllocate the signature result buffer with a maximum size
505 * of the roundup to 16 bytes of the secure size in bytes if
506 * the signature buffer is not aligned or too short.
507 *
508 * - 1st Part: size_sec
509 * - 2nd Part: size_sec roundup to 16 bytes
510 */
511 sign_len = ROUNDUP(sdata->size_sec, 16) + sdata->size_sec;
512
513 ret = caam_dmaobj_output_sgtbuf(&sign_c, sdata->signature.data,
514 sdata->signature.length, sign_len);
515 if (ret)
516 goto out;
517
518 if (sign_c.sgtbuf.sgt_type)
519 pdb_sgt_flags |= PDB_SGT_PKSIGN_SIGN_C;
520
521 /* Derive sign_d from created sign_c DMA object */
522 ret = caam_dmaobj_derive_sgtbuf(&sign_d, &sign_c, sdata->size_sec,
523 ROUNDUP(sdata->size_sec, 16));
524 if (ret)
525 goto out;
526
527 if (sign_d.sgtbuf.sgt_type)
528 pdb_sgt_flags |= PDB_SGT_PKSIGN_SIGN_D;
529
530 caam_dmaobj_cache_push(&sign_c);
531
532 /* Build the descriptor using Predefined ECC curve */
533 caam_desc_init(desc);
534 caam_desc_add_word(desc, DESC_HEADER(0));
535 caam_desc_add_word(desc, PDB_PKSIGN_PD1 | PDB_ECC_ECDSEL(curve) |
536 pdb_sgt_flags);
537 /* Secret key */
538 caam_desc_add_ptr(desc, ecckey.d.buf.paddr);
539 /* Input message */
540 caam_desc_add_ptr(desc, msg.sgtbuf.paddr);
541 /* Signature 1st part */
542 caam_desc_add_ptr(desc, sign_c.sgtbuf.paddr);
543 /* Signature 2nd part */
544 caam_desc_add_ptr(desc, sign_d.sgtbuf.paddr);
545
546 if (msg_mes_rep(sdata->message.length, sdata->size_sec)) {
547 switch (ecckey.d.key_type) {
548 case CAAM_KEY_PLAIN_TEXT:
549 caam_desc_add_word(desc, DSA_SIGN(ECC, MES_REP, NONE));
550 break;
551 case CAAM_KEY_BLACK_ECB:
552 caam_desc_add_word(desc, DSA_SIGN(ECC, MES_REP, ECB));
553 break;
554 case CAAM_KEY_BLACK_CCM:
555 caam_desc_add_word(desc, DSA_SIGN(ECC, MES_REP, CCM));
556 break;
557 default:
558 ret = TEE_ERROR_GENERIC;
559 goto out;
560 }
561 } else {
562 /* Message length */
563 caam_desc_add_word(desc, sdata->message.length);
564
565 switch (ecckey.d.key_type) {
566 case CAAM_KEY_PLAIN_TEXT:
567 caam_desc_add_word(desc, DSA_SIGN(ECC, HASHED, NONE));
568 break;
569 case CAAM_KEY_BLACK_ECB:
570 caam_desc_add_word(desc, DSA_SIGN(ECC, HASHED, ECB));
571 break;
572 case CAAM_KEY_BLACK_CCM:
573 caam_desc_add_word(desc, DSA_SIGN(ECC, HASHED, CCM));
574 break;
575 default:
576 ret = TEE_ERROR_GENERIC;
577 goto out;
578 }
579 }
580
581 desclen = caam_desc_get_len(desc);
582 caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
583
584 ECC_DUMPDESC(desc);
585
586 jobctx.desc = desc;
587
588 retstatus = caam_jr_enqueue(&jobctx, NULL);
589 if (retstatus == CAAM_NO_ERROR) {
590 sign_c.orig.length = 2 * sdata->size_sec;
591 sdata->signature.length = caam_dmaobj_copy_to_orig(&sign_c);
592
593 ECC_DUMPBUF("Signature", sdata->signature.data,
594 sdata->signature.length);
595
596 ret = caam_status_to_tee_result(retstatus);
597 } else {
598 ECC_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
599 ret = job_status_to_tee_result(jobctx.status);
600 }
601
602 out:
603 caam_free_desc(&desc);
604 do_keypair_free(&ecckey);
605 caam_dmaobj_free(&msg);
606 caam_dmaobj_free(&sign_d);
607 caam_dmaobj_free(&sign_c);
608 caam_free_buf(&caambuf_msg);
609
610 return ret;
611 }
612
613 /*
614 * Verification of the Signature of ECC message
615 * Note the message is already hashed
616 *
617 * @sdata [in/out] ECC Signature to verify
618 */
do_verify(struct drvcrypt_sign_data * sdata)619 static TEE_Result do_verify(struct drvcrypt_sign_data *sdata)
620 {
621 TEE_Result ret = TEE_ERROR_GENERIC;
622 enum caam_status retstatus = CAAM_FAILURE;
623 enum caam_ecc_curve curve = CAAM_ECC_UNKNOWN;
624 struct ecc_public_key *inkey = sdata->key;
625 struct caam_ecc_keypair ecckey = { };
626 struct caambuf tmp = { };
627 struct caam_jobctx jobctx = { };
628 uint32_t *desc = NULL;
629 uint32_t desclen = 0;
630 struct caamdmaobj msg = { };
631 struct caamdmaobj sign_c = { };
632 struct caamdmaobj sign_d = { };
633 uint32_t pdb_sgt_flags = 0;
634 struct caambuf caambuf_msg = { };
635
636 ECC_TRACE("ECC Verify");
637 ECC_DUMPBUF("Message", sdata->message.data, sdata->message.length);
638 ECC_DUMPBUF("Signature", sdata->signature.data,
639 sdata->signature.length);
640
641 /* Verify first if the curve is supported */
642 curve = get_caam_curve(inkey->curve);
643 if (curve == CAAM_ECC_UNKNOWN)
644 return TEE_ERROR_BAD_PARAMETERS;
645
646 /* Allocate the job descriptor */
647 desc = caam_calloc_desc(MAX_DESC_VERIFY);
648 if (!desc) {
649 ret = TEE_ERROR_OUT_OF_MEMORY;
650 goto out;
651 }
652
653 /* Convert the Public key to local key */
654 retstatus = do_keypub_conv(&ecckey, inkey, sdata->size_sec);
655 if (retstatus != CAAM_NO_ERROR) {
656 ret = caam_status_to_tee_result(retstatus);
657 goto out;
658 }
659
660 if (padding_required(sdata->message.length, sdata->size_sec)) {
661 ret = add_padding(&caambuf_msg, sdata->message.data,
662 sdata->message.length, sdata->size_sec);
663 if (ret)
664 goto out;
665
666 /* Prepare the input message CAAM Descriptor entry */
667 ret = caam_dmaobj_input_sgtbuf(&msg, caambuf_msg.data,
668 caambuf_msg.length);
669 if (ret)
670 goto out;
671 } else {
672 /* Prepare the input message CAAM Descriptor entry */
673 ret = caam_dmaobj_input_sgtbuf(&msg, sdata->message.data,
674 sdata->message.length);
675 if (ret)
676 goto out;
677 }
678
679 if (msg.sgtbuf.sgt_type)
680 pdb_sgt_flags |= PDB_SGT_PKVERIF_MSG;
681
682 caam_dmaobj_cache_push(&msg);
683
684 /*
685 * Prepare the 1st Part of the signature
686 * Handle the full signature in case signature buffer needs to
687 * be reallocated.
688 */
689 ret = caam_dmaobj_input_sgtbuf(&sign_c, sdata->signature.data,
690 sdata->signature.length);
691 if (ret)
692 goto out;
693
694 if (sign_c.sgtbuf.sgt_type)
695 pdb_sgt_flags |= PDB_SGT_PKVERIF_SIGN_C;
696
697 /* Prepare the 2nd Part of the signature, derived from sign_c */
698 ret = caam_dmaobj_derive_sgtbuf(&sign_d, &sign_c, sdata->size_sec,
699 sdata->size_sec);
700 if (ret)
701 goto out;
702
703 if (sign_d.sgtbuf.sgt_type)
704 pdb_sgt_flags |= PDB_SGT_PKVERIF_SIGN_D;
705
706 caam_dmaobj_cache_push(&sign_c);
707
708 /* Allocate a Temporary buffer used by the CAAM */
709 retstatus = caam_alloc_align_buf(&tmp, 2 * sdata->size_sec);
710 if (retstatus != CAAM_NO_ERROR) {
711 ret = caam_status_to_tee_result(retstatus);
712 goto out;
713 }
714
715 /* Build the descriptor using Predefined ECC curve */
716 caam_desc_init(desc);
717 caam_desc_add_word(desc, DESC_HEADER(0));
718 caam_desc_add_word(desc, PDB_PKVERIFY_PD1 | PDB_ECC_ECDSEL(curve) |
719 pdb_sgt_flags);
720 /* Public key */
721 caam_desc_add_ptr(desc, ecckey.xy.paddr);
722 /* Input message */
723 caam_desc_add_ptr(desc, msg.sgtbuf.paddr);
724 /* Signature 1st part */
725 caam_desc_add_ptr(desc, sign_c.sgtbuf.paddr);
726 /* Signature 2nd part */
727 caam_desc_add_ptr(desc, sign_d.sgtbuf.paddr);
728 /* Temporary buffer */
729 caam_desc_add_ptr(desc, tmp.paddr);
730
731 if (msg_mes_rep(sdata->message.length, sdata->size_sec)) {
732 caam_desc_add_word(desc, DSA_VERIFY(ECC, MES_REP));
733 } else {
734 /* Message length */
735 caam_desc_add_word(desc, sdata->message.length);
736
737 caam_desc_add_word(desc, DSA_VERIFY(ECC, HASHED));
738 }
739
740 desclen = caam_desc_get_len(desc);
741 caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
742
743 ECC_DUMPDESC(desc);
744
745 jobctx.desc = desc;
746
747 cache_operation(TEE_CACHEFLUSH, tmp.data, tmp.length);
748 cache_operation(TEE_CACHEFLUSH, ecckey.xy.data, ecckey.xy.length);
749
750 retstatus = caam_jr_enqueue(&jobctx, NULL);
751
752 if (retstatus == CAAM_JOB_STATUS && !jobctx.status) {
753 ECC_TRACE("ECC Verify Status 0x%08" PRIx32, jobctx.status);
754 ret = TEE_ERROR_SIGNATURE_INVALID;
755 } else if (retstatus != CAAM_NO_ERROR) {
756 ECC_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
757 ret = job_status_to_tee_result(jobctx.status);
758 } else {
759 ret = caam_status_to_tee_result(retstatus);
760 }
761
762 out:
763 caam_free_desc(&desc);
764 do_keypair_free(&ecckey);
765 caam_free_buf(&tmp);
766 caam_dmaobj_free(&msg);
767 caam_dmaobj_free(&sign_c);
768 caam_dmaobj_free(&sign_d);
769 caam_free_buf(&caambuf_msg);
770
771 return ret;
772 }
773
774 /*
775 * Compute the shared secret data from ECC Private key and Public Key
776 *
777 * @sdata [in/out] ECC Shared Secret data
778 */
do_shared_secret(struct drvcrypt_secret_data * sdata)779 static TEE_Result do_shared_secret(struct drvcrypt_secret_data *sdata)
780 {
781 TEE_Result ret = TEE_ERROR_GENERIC;
782 enum caam_status retstatus = CAAM_FAILURE;
783 enum caam_ecc_curve curve = CAAM_ECC_UNKNOWN;
784 struct ecc_keypair *inprivkey = sdata->key_priv;
785 struct ecc_public_key *inpubkey = sdata->key_pub;
786 struct caam_ecc_keypair ecckey = { };
787 struct caam_jobctx jobctx = { };
788 uint32_t *desc = NULL;
789 uint32_t desclen = 0;
790 struct caamdmaobj secret = { };
791 uint32_t pdb_sgt_flags = 0;
792
793 ECC_TRACE("ECC Shared Secret");
794
795 /* Verify first if the curve is supported */
796 curve = get_caam_curve(inpubkey->curve);
797 if (curve == CAAM_ECC_UNKNOWN)
798 return TEE_ERROR_BAD_PARAMETERS;
799
800 /* Allocate the job descriptor */
801 desc = caam_calloc_desc(MAX_DESC_SHARED);
802 if (!desc) {
803 ret = TEE_ERROR_OUT_OF_MEMORY;
804 goto out;
805 }
806
807 /* Convert the Private key to local key */
808 retstatus = do_keypair_conv(&ecckey, inprivkey, sdata->size_sec);
809 if (retstatus != CAAM_NO_ERROR) {
810 ret = caam_status_to_tee_result(retstatus);
811 goto out;
812 }
813
814 /* Convert the Public key to local key */
815 retstatus = do_keypub_conv(&ecckey, inpubkey, sdata->size_sec);
816 if (retstatus != CAAM_NO_ERROR) {
817 ret = caam_status_to_tee_result(retstatus);
818 goto out;
819 }
820
821 /*
822 * Re-allocate the secret result buffer with a maximum size
823 * of the secret size if not cache aligned
824 */
825 ret = caam_dmaobj_output_sgtbuf(&secret, sdata->secret.data,
826 sdata->secret.length, sdata->size_sec);
827 if (ret)
828 goto out;
829
830 if (secret.sgtbuf.sgt_type)
831 pdb_sgt_flags |= PDB_SGT_PKDH_SECRET;
832
833 caam_dmaobj_cache_push(&secret);
834
835 /* Build the descriptor using Predefined ECC curve */
836 caam_desc_init(desc);
837 caam_desc_add_word(desc, DESC_HEADER(0));
838 caam_desc_add_word(desc, PDB_SHARED_SECRET_PD1 | PDB_ECC_ECDSEL(curve) |
839 pdb_sgt_flags);
840 /* Public key */
841 caam_desc_add_ptr(desc, ecckey.xy.paddr);
842 /* Private key */
843 caam_desc_add_ptr(desc, ecckey.d.buf.paddr);
844 /* Output secret */
845 caam_desc_add_ptr(desc, secret.sgtbuf.paddr);
846
847 switch (ecckey.d.key_type) {
848 case CAAM_KEY_PLAIN_TEXT:
849 caam_desc_add_word(desc, SHARED_SECRET(ECC, NONE));
850 break;
851 case CAAM_KEY_BLACK_ECB:
852 caam_desc_add_word(desc, SHARED_SECRET(ECC, ECB));
853 break;
854 case CAAM_KEY_BLACK_CCM:
855 caam_desc_add_word(desc, SHARED_SECRET(ECC, CCM));
856 break;
857 default:
858 ret = TEE_ERROR_GENERIC;
859 goto out;
860 }
861
862 desclen = caam_desc_get_len(desc);
863 caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
864
865 ECC_DUMPDESC(desc);
866
867 jobctx.desc = desc;
868
869 retstatus = caam_jr_enqueue(&jobctx, NULL);
870
871 if (retstatus == CAAM_NO_ERROR) {
872 sdata->secret.length = caam_dmaobj_copy_to_orig(&secret);
873
874 ECC_DUMPBUF("Secret", sdata->secret.data, sdata->secret.length);
875
876 ret = caam_status_to_tee_result(retstatus);
877 } else {
878 ECC_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
879 ret = job_status_to_tee_result(jobctx.status);
880 }
881
882 out:
883 caam_free_desc(&desc);
884 do_keypair_free(&ecckey);
885 caam_dmaobj_free(&secret);
886
887 return ret;
888 }
889
890 /*
891 * Registration of the ECC Driver
892 */
893 static struct drvcrypt_ecc driver_ecc = {
894 .alloc_keypair = do_allocate_keypair,
895 .alloc_publickey = do_allocate_publickey,
896 .free_publickey = do_free_publickey,
897 .gen_keypair = do_gen_keypair,
898 .sign = do_sign,
899 .verify = do_verify,
900 .shared_secret = do_shared_secret,
901 };
902
caam_ecc_init(struct caam_jrcfg * caam_jrcfg)903 enum caam_status caam_ecc_init(struct caam_jrcfg *caam_jrcfg)
904 {
905 enum caam_status retstatus = CAAM_FAILURE;
906 vaddr_t jr_base = caam_jrcfg->base + caam_jrcfg->offset;
907
908 if (caam_hal_ctrl_pknum(jr_base))
909 if (drvcrypt_register_ecc(&driver_ecc) == TEE_SUCCESS)
910 retstatus = CAAM_NO_ERROR;
911
912 return retstatus;
913 }
914