xref: /optee_os/core/drivers/crypto/caam/acipher/caam_ecc.c (revision 7e29b8214ec8b7d44e995f0834c43b474a8b26f2)
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