xref: /optee_os/core/drivers/crypto/caam/cipher/caam_cipher_mac.c (revision e4b1172625af43092b8742144113b64375190b71)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2018-2021 NXP
4  *
5  * Implementation of CMAC functions
6  */
7 #include <caam_cipher.h>
8 #include <caam_common.h>
9 #include <caam_jr.h>
10 #include <caam_utils_mem.h>
11 #include <caam_utils_status.h>
12 #include <drvcrypt_mac.h>
13 #include <mm/core_memprot.h>
14 #include <string.h>
15 #include <tee/cache.h>
16 #include <utee_defines.h>
17 
18 #include "local.h"
19 
20 static TEE_Result do_update_mac(struct drvcrypt_cipher_update *dupdate);
21 static TEE_Result do_update_cmac(struct drvcrypt_cipher_update *dupdate);
22 
23 /*
24  * Constant definitions of AES MAC algorithms
25  */
26 static const struct cipheralg aes_cbc_mac_alg = {
27 	.type = OP_ALGO(AES) | ALGO_AAI(AES_CBC),
28 	.size_block = TEE_AES_BLOCK_SIZE,
29 	.size_ctx = 2 * sizeof(uint64_t),
30 	.ctx_offset = 0,
31 	.require_key = NEED_KEY1 | NEED_IV,
32 	.def_key = {
33 		.min = 16,
34 		.max = 32,
35 		.mod = 8
36 	},
37 	.update = do_update_mac,
38 };
39 
40 static const struct cipheralg aes_cmac_alg = {
41 	.type = OP_ALGO(AES) | ALGO_AAI(AES_CMAC),
42 	.size_block = TEE_AES_BLOCK_SIZE,
43 	.size_ctx = 4 * sizeof(uint64_t),
44 	.ctx_offset = 0,
45 	.require_key = NEED_KEY1,
46 	.def_key = {
47 		.min = 16,
48 		.max = 32,
49 		.mod = 8
50 	},
51 	.update = do_update_cmac,
52 };
53 
54 /*
55  * Constant definitions of DES MAC algorithm
56  */
57 static const struct cipheralg des_mac_alg = {
58 	.type = OP_ALGO(DES) | ALGO_AAI(DES_CBC),
59 	.size_block = TEE_DES_BLOCK_SIZE,
60 	.size_ctx = sizeof(uint64_t),
61 	.ctx_offset = 0,
62 	.require_key = NEED_KEY1 | NEED_IV,
63 	.def_key = {
64 		.min = 8,
65 		.max = 8,
66 		.mod = 8
67 	},
68 	.update = do_update_mac,
69 };
70 
71 /*
72  * Constant definitions of DES3 MAC algorithm
73  */
74 static const struct cipheralg des3_mac_alg = {
75 	.type = OP_ALGO(3DES) | ALGO_AAI(DES_CBC),
76 	.size_block = TEE_DES_BLOCK_SIZE,
77 	.size_ctx = sizeof(uint64_t),
78 	.ctx_offset = 0,
79 	.require_key = NEED_KEY1 | NEED_IV,
80 	.def_key = {
81 		.min = 16,
82 		.max = 24,
83 		.mod = 8
84 	},
85 	.update = do_update_mac,
86 };
87 
88 static const struct crypto_mac_ops cmac_ops;
89 
90 /*
91  * Format the MAC context to keep the reference to the operation driver
92  */
93 struct crypto_mac {
94 	struct crypto_mac_ctx mac_ctx; /* Crypto MAC API context */
95 	struct cipherdata *ctx;	       /* CMAC context */
96 };
97 
98 /*
99  * Returns the reference to the driver context
100  *
101  * @ctx  API context
102  */
to_mac_ctx(struct crypto_mac_ctx * ctx)103 static struct crypto_mac *to_mac_ctx(struct crypto_mac_ctx *ctx)
104 {
105 	assert(ctx && ctx->ops == &cmac_ops);
106 
107 	return container_of(ctx, struct crypto_mac, mac_ctx);
108 }
109 
110 /*
111  * Checks if the algorithm @algo is supported and returns the
112  * local algorithm entry in the corresponding cipher array.
113  *
114  * @algo  Algorithm ID
115  */
get_macalgo(uint32_t algo)116 static const struct cipheralg *get_macalgo(uint32_t algo)
117 {
118 	switch (algo) {
119 	case TEE_ALG_AES_CBC_MAC_NOPAD:
120 	case TEE_ALG_AES_CBC_MAC_PKCS5:
121 		return &aes_cbc_mac_alg;
122 	case TEE_ALG_AES_CMAC:
123 		return &aes_cmac_alg;
124 	case TEE_ALG_DES_CBC_MAC_NOPAD:
125 	case TEE_ALG_DES_CBC_MAC_PKCS5:
126 		return &des_mac_alg;
127 	case TEE_ALG_DES3_CBC_MAC_NOPAD:
128 	case TEE_ALG_DES3_CBC_MAC_PKCS5:
129 		return &des3_mac_alg;
130 	default:
131 		return NULL;
132 	}
133 }
134 
135 /*
136  * MAC update of the cipher operation of complete block except
137  * if last block. Last block can be partial block.
138  *
139  * @dupdate  Data update object
140  */
do_update_mac(struct drvcrypt_cipher_update * dupdate)141 static TEE_Result do_update_mac(struct drvcrypt_cipher_update *dupdate)
142 {
143 	TEE_Result ret = TEE_ERROR_BAD_PARAMETERS;
144 	enum caam_status retstatus = CAAM_FAILURE;
145 	struct cipherdata *ctx = dupdate->ctx;
146 	struct caamdmaobj src = { };
147 	struct caamdmaobj dst = { };
148 	size_t full_size = 0;
149 	size_t size_topost = 0;
150 	size_t size_todo = 0;
151 	size_t size_done = 0;
152 	size_t size_inmade = 0;
153 	size_t offset = 0;
154 
155 	CIPHER_TRACE("Length=%zu - %s", dupdate->src.length,
156 		     ctx->encrypt ? "Encrypt" : "Decrypt");
157 
158 	/* Calculate the total data to be handled */
159 	full_size = ctx->blockbuf.filled + dupdate->src.length;
160 	if (full_size < ctx->alg->size_block) {
161 		size_topost = dupdate->src.length;
162 	} else {
163 		size_topost = full_size % ctx->alg->size_block;
164 		size_inmade = dupdate->src.length - size_topost;
165 		/* Total size that is a cipher block multiple */
166 		size_todo = full_size - size_topost;
167 	}
168 
169 	CIPHER_TRACE("FullSize %zu - posted %zu - todo %zu", full_size,
170 		     size_topost, size_todo);
171 
172 	if (!size_todo) {
173 		/*
174 		 * There is no complete block to do:
175 		 *   - either input size + already saved data < block size
176 		 *   - or no input data and this is the last block
177 		 */
178 		if (dupdate->last)
179 			memcpy(dupdate->dst.data, ctx->ctx.data,
180 			       MIN(dupdate->dst.length, ctx->alg->size_ctx));
181 
182 		ret = TEE_SUCCESS;
183 		goto end_mac_post;
184 	}
185 
186 	if (dupdate->src.length) {
187 		ret = caam_dmaobj_init_input(&src, dupdate->src.data,
188 					     dupdate->src.length);
189 		if (ret)
190 			goto end_mac;
191 
192 		ret = caam_dmaobj_prepare(&src, NULL, ctx->alg->size_block);
193 		if (ret)
194 			goto end_mac;
195 	}
196 
197 	if (dupdate->last) {
198 		ret = caam_dmaobj_output_sgtbuf(&dst, dupdate->dst.data,
199 						dupdate->dst.length,
200 						dupdate->dst.length);
201 		if (ret)
202 			goto end_mac;
203 
204 		/* Remove a block of data to do the last block */
205 		if (size_todo > ctx->alg->size_block)
206 			size_todo -= ctx->alg->size_block;
207 		else
208 			size_todo = 0;
209 	}
210 
211 	/* Check if there is some data saved to complete the buffer */
212 	if (ctx->blockbuf.filled) {
213 		ret = caam_dmaobj_add_first_block(&src, &ctx->blockbuf);
214 		if (ret)
215 			goto end_mac;
216 		ctx->blockbuf.filled = 0;
217 	}
218 
219 	size_done = ctx->alg->size_block;
220 	for (offset = 0; size_todo;
221 	     offset += size_done, size_todo -= size_done) {
222 		CIPHER_TRACE("Do input %zu bytes, offset %zu", size_done,
223 			     offset);
224 
225 		ret = caam_dmaobj_sgtbuf_build(&src, &size_done, offset,
226 					       ctx->alg->size_block);
227 		if (ret)
228 			goto end_mac;
229 
230 		if (size_done != ctx->alg->size_block) {
231 			ret = TEE_ERROR_GENERIC;
232 			goto end_mac;
233 		}
234 
235 		retstatus = caam_cipher_block(ctx, true, NEED_KEY1, true, &src,
236 					      NULL);
237 
238 		if (retstatus != CAAM_NO_ERROR) {
239 			ret = caam_status_to_tee_result(retstatus);
240 			goto end_mac;
241 		}
242 	}
243 
244 	if (dupdate->last) {
245 		CIPHER_TRACE("Do input %zu bytes, offset %zu", size_done,
246 			     offset);
247 
248 		ret = caam_dmaobj_sgtbuf_build(&src, &size_done, offset,
249 					       ctx->alg->size_block);
250 		if (ret)
251 			goto end_mac;
252 
253 		if (size_done != ctx->alg->size_block) {
254 			ret = TEE_ERROR_GENERIC;
255 			goto end_mac;
256 		}
257 
258 		retstatus = caam_cipher_block(ctx, true, NEED_KEY1, true, &src,
259 					      &dst);
260 
261 		if (retstatus == CAAM_NO_ERROR)
262 			caam_dmaobj_copy_to_orig(&dst);
263 
264 		ret = caam_status_to_tee_result(retstatus);
265 	}
266 
267 end_mac_post:
268 	if (size_topost) {
269 		struct caambuf cpysrc = {
270 			.data = dupdate->src.data,
271 			.length = dupdate->src.length
272 		};
273 
274 		CIPHER_TRACE("Save input data %zu bytes of %zu (%zu)",
275 			     size_topost, dupdate->src.length, size_inmade);
276 
277 		retstatus = caam_cpy_block_src(&ctx->blockbuf, &cpysrc,
278 					       size_inmade);
279 		ret = caam_status_to_tee_result(retstatus);
280 	}
281 
282 end_mac:
283 	caam_dmaobj_free(&src);
284 	caam_dmaobj_free(&dst);
285 
286 	return ret;
287 }
288 
289 /*
290  * Build and run the CMAC descriptor (AES only)
291  *
292  * @ctx     Cipher Data context
293  * @src     Input data
294  * @dstbuf  [out] Output data if last block
295  * @last    Last block flag
296  */
run_cmac_desc(struct cipherdata * ctx,struct caamdmaobj * src,struct caamdmaobj * dst,bool last)297 static TEE_Result run_cmac_desc(struct cipherdata *ctx, struct caamdmaobj *src,
298 				struct caamdmaobj *dst, bool last)
299 {
300 	TEE_Result ret = TEE_ERROR_GENERIC;
301 	enum caam_status retstatus = CAAM_FAILURE;
302 	struct caam_jobctx jobctx = { };
303 	uint32_t *desc = NULL;
304 
305 	desc = ctx->descriptor;
306 	caam_desc_init(desc);
307 	caam_desc_add_word(desc, DESC_HEADER(0));
308 
309 	if (ctx->alg->require_key & NEED_KEY1) {
310 		/* Build the descriptor */
311 		caam_desc_add_word(desc, LD_KEY_PLAIN(CLASS_1, REG,
312 						      ctx->key1.length));
313 		caam_desc_add_ptr(desc, ctx->key1.paddr);
314 	}
315 
316 	/* If context already allocated, this is an update */
317 	if (ctx->ctx.length) {
318 		CIPHER_TRACE("%s operation", last ? "Final" : "Update");
319 		caam_desc_add_word(desc, LD_NOIMM_OFF(CLASS_1, REG_CTX,
320 						      ctx->ctx.length,
321 						      ctx->alg->ctx_offset));
322 		caam_desc_add_ptr(desc, ctx->ctx.paddr);
323 		if (last)
324 			caam_desc_add_word(desc,
325 					   CIPHER_FINAL(ctx->alg->type, true));
326 		else
327 			caam_desc_add_word(desc,
328 					   CIPHER_UPDATE(ctx->alg->type, true));
329 	} else if (last) {
330 		CIPHER_TRACE("Init/Final operation");
331 
332 		caam_desc_add_word(desc,
333 				   CIPHER_INITFINAL(ctx->alg->type, true));
334 	} else {
335 		CIPHER_TRACE("Init operation");
336 
337 		caam_desc_add_word(desc, CIPHER_INIT(ctx->alg->type, true));
338 		if (!ctx->ctx.data) {
339 			retstatus = caam_alloc_align_buf(&ctx->ctx,
340 							 ctx->alg->size_ctx);
341 			if (retstatus != CAAM_NO_ERROR)
342 				return TEE_ERROR_OUT_OF_MEMORY;
343 		}
344 	}
345 
346 	/* Check first if there is some pending data from previous updates */
347 	if (ctx->blockbuf.filled) {
348 		/* Add the temporary buffer */
349 		if (src)
350 			caam_desc_add_word(desc,
351 					   FIFO_LD_EXT(CLASS_1, MSG, NOACTION));
352 		else
353 			caam_desc_add_word(desc,
354 					   FIFO_LD_EXT(CLASS_1, MSG, LAST_C1));
355 
356 		caam_desc_add_ptr(desc, ctx->blockbuf.buf.paddr);
357 		caam_desc_add_word(desc, ctx->blockbuf.filled);
358 
359 		/* Clean the circular buffer data to be loaded */
360 		cache_operation(TEE_CACHECLEAN, ctx->blockbuf.buf.data,
361 				ctx->blockbuf.filled);
362 	}
363 
364 	if (src) {
365 		caam_desc_fifo_load(desc, src, CLASS_1, MSG, LAST_C1);
366 		caam_dmaobj_cache_push(src);
367 	} else {
368 		if (last && !ctx->blockbuf.filled) {
369 			/*
370 			 * Add the input data of 0 bytes to start
371 			 * algorithm by setting the input data size
372 			 */
373 			caam_desc_add_word(desc,
374 					   FIFO_LD(CLASS_1, MSG, LAST_C1, 0));
375 			caam_desc_add_ptr(desc, 0);
376 		}
377 	}
378 
379 	ctx->blockbuf.filled = 0;
380 
381 	if (last) {
382 		caam_desc_store(desc, dst, CLASS_1, REG_CTX);
383 		caam_dmaobj_cache_push(dst);
384 	} else {
385 		/* Store the context */
386 		caam_desc_add_word(desc, ST_NOIMM_OFF(CLASS_1, REG_CTX,
387 						      ctx->ctx.length,
388 						      ctx->alg->ctx_offset));
389 		caam_desc_add_ptr(desc, ctx->ctx.paddr);
390 	}
391 
392 	CIPHER_DUMPDESC(desc);
393 
394 	/* Invalidate Context register */
395 	if (ctx->ctx.length)
396 		cache_operation(TEE_CACHEINVALIDATE, ctx->ctx.data,
397 				ctx->ctx.length);
398 
399 	jobctx.desc = desc;
400 	retstatus = caam_jr_enqueue(&jobctx, NULL);
401 
402 	if (retstatus == CAAM_NO_ERROR) {
403 		ret = TEE_SUCCESS;
404 	} else {
405 		CIPHER_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
406 		ret = job_status_to_tee_result(jobctx.status);
407 	}
408 
409 	return ret;
410 }
411 
412 /*
413  * Update of the CMAC operation of complete block except
414  * if last block. Last block can be a partial block.
415  *
416  * @dupdate  Data update object
417  */
do_update_cmac(struct drvcrypt_cipher_update * dupdate)418 static TEE_Result do_update_cmac(struct drvcrypt_cipher_update *dupdate)
419 {
420 	TEE_Result ret = TEE_ERROR_BAD_PARAMETERS;
421 	enum caam_status retstatus = CAAM_FAILURE;
422 	struct cipherdata *ctx = dupdate->ctx;
423 	size_t full_size = 0;
424 	size_t size_topost = 0;
425 	size_t size_todo = 0;
426 	size_t size_inmade = 0;
427 	size_t size_done = 0;
428 	size_t offset = 0;
429 	struct caamdmaobj src = { };
430 	struct caamdmaobj dst = { };
431 
432 	CIPHER_TRACE("Length=%zu - %s", dupdate->src.length,
433 		     dupdate->encrypt ? "Encrypt" : "Decrypt");
434 
435 	/* Calculate the total data to be handled */
436 	full_size = ctx->blockbuf.filled + dupdate->src.length;
437 	if (!dupdate->last) {
438 		/*
439 		 * In case there is no data to save and because it's
440 		 * not the final operation, ensure that a block of data
441 		 * is kept for the final operation.
442 		 */
443 		if (full_size <= ctx->alg->size_block) {
444 			size_topost = dupdate->src.length;
445 			goto end_cmac_post;
446 		}
447 
448 		size_topost = full_size % ctx->alg->size_block;
449 
450 		if (!size_topost)
451 			size_topost = ctx->alg->size_block;
452 
453 		size_inmade = dupdate->src.length - size_topost;
454 		size_todo = full_size - size_topost;
455 	} else {
456 		ret = caam_dmaobj_output_sgtbuf(&dst, dupdate->dst.data,
457 						dupdate->dst.length,
458 						dupdate->dst.length);
459 		if (ret)
460 			goto end_cmac;
461 
462 		/*
463 		 * If there more than one block to do, keep the last
464 		 * block to build the CMAC output.
465 		 */
466 		if (full_size > ctx->alg->size_block) {
467 			size_todo = full_size - ctx->alg->size_block;
468 			size_inmade = size_todo - ctx->blockbuf.filled;
469 		}
470 	}
471 
472 	if (size_inmade) {
473 		ret = caam_dmaobj_init_input(&src, dupdate->src.data,
474 					     size_inmade);
475 		if (ret)
476 			goto end_cmac;
477 
478 		ret = caam_dmaobj_prepare(&src, NULL, ctx->alg->size_block);
479 		if (ret)
480 			goto end_cmac;
481 	}
482 
483 	CIPHER_TRACE("FullSize %zu - posted %zu - todo %zu", full_size,
484 		     size_topost, size_todo);
485 
486 	for (offset = 0; size_todo;
487 	     offset += size_done, size_todo -= size_done) {
488 		/*
489 		 * At least one block is to be done.
490 		 * At first iteration, we can have less than one block
491 		 * data available from previous update operation which
492 		 * was not block modulus.
493 		 * Remove the previous saved data (blockbuf) from the data to
494 		 * take from input data.
495 		 * Next iteration, blockbuf will be empty.
496 		 */
497 		size_todo -= ctx->blockbuf.filled;
498 		size_done = size_todo;
499 
500 		if (size_inmade) {
501 			ret = caam_dmaobj_sgtbuf_build(&src, &size_done, offset,
502 						       ctx->alg->size_block);
503 			if (ret)
504 				goto end_cmac;
505 
506 			/*
507 			 * Need to re-adjust the length of the data if the
508 			 * posted data block is not empty and the SGT/Buffer
509 			 * is part of the full input data to do.
510 			 */
511 			if (ctx->blockbuf.filled && size_done < size_todo) {
512 				size_done -= ctx->blockbuf.filled;
513 				src.sgtbuf.length = size_done;
514 			}
515 			CIPHER_TRACE("Do input %zu bytes, offset %zu",
516 				     size_done, offset);
517 
518 			ret = run_cmac_desc(ctx, &src, NULL, false);
519 		} else {
520 			CIPHER_TRACE("Do saved blockbuf %zu bytes (done = %zu)",
521 				     ctx->blockbuf.filled, size_done);
522 			ret = run_cmac_desc(ctx, NULL, NULL, false);
523 		}
524 
525 		if (ret)
526 			goto end_cmac;
527 	}
528 
529 	if (dupdate->last) {
530 		if (dupdate->src.length - size_inmade) {
531 			size_done = dupdate->src.length - size_inmade;
532 			ret = caam_dmaobj_sgtbuf_build(&src, &size_done, offset,
533 						       ctx->alg->size_block);
534 			if (ret)
535 				goto end_cmac;
536 
537 			if (size_done != dupdate->src.length - size_inmade) {
538 				ret = TEE_ERROR_GENERIC;
539 				goto end_cmac;
540 			}
541 
542 			ret = run_cmac_desc(ctx, &src, &dst, true);
543 		} else {
544 			ret = run_cmac_desc(ctx, NULL, &dst, true);
545 		}
546 
547 		if (!ret)
548 			caam_dmaobj_copy_to_orig(&dst);
549 	}
550 
551 end_cmac_post:
552 	if (size_topost) {
553 		struct caambuf srcbuf = { .data = dupdate->src.data,
554 					  .length = dupdate->src.length };
555 
556 		CIPHER_TRACE("Post %zu of input len %zu made %zu", size_topost,
557 			     srcbuf.length, size_inmade);
558 
559 		retstatus = caam_cpy_block_src(&ctx->blockbuf, &srcbuf,
560 					       size_inmade);
561 		ret = caam_status_to_tee_result(retstatus);
562 	}
563 
564 end_cmac:
565 	caam_dmaobj_free(&src);
566 	caam_dmaobj_free(&dst);
567 
568 	return ret;
569 }
570 
571 /*
572  * Initialization of the CMAC operation.
573  *
574  * @ctx  Operation software context
575  * @key  Input key to compute
576  * @len  Key length
577  */
do_cmac_init(struct crypto_mac_ctx * ctx,const uint8_t * key,size_t len)578 static TEE_Result do_cmac_init(struct crypto_mac_ctx *ctx, const uint8_t *key,
579 			       size_t len)
580 {
581 	TEE_Result ret = TEE_ERROR_GENERIC;
582 	uint8_t *iv_tmp = NULL;
583 	struct drvcrypt_cipher_init dinit = { };
584 	struct crypto_mac *mac = to_mac_ctx(ctx);
585 	struct cipherdata *macdata = mac->ctx;
586 
587 	if (macdata->mode != TEE_CHAIN_MODE_CMAC) {
588 		/* Allocate temporary IV initialize with 0's */
589 		iv_tmp = caam_calloc(macdata->alg->size_ctx);
590 		if (!iv_tmp)
591 			return TEE_ERROR_OUT_OF_MEMORY;
592 	} else {
593 		/*
594 		 * Check if the context register is allocated to free it,
595 		 * because in case of CMAC mode, the context register
596 		 * is allocated during do_update_cmac() operation if
597 		 * necessary.
598 		 */
599 		if (macdata->ctx.data)
600 			caam_free_buf(&macdata->ctx);
601 	}
602 
603 	macdata->countdata = 0;
604 
605 	/* Prepare the initialization data */
606 	dinit.ctx = macdata;
607 	dinit.encrypt = true;
608 	dinit.key1.data = (uint8_t *)key;
609 	dinit.key1.length = len;
610 	dinit.key2.data = NULL;
611 	dinit.key2.length = 0;
612 	dinit.iv.data = iv_tmp;
613 	dinit.iv.length = macdata->alg->size_ctx;
614 	ret = caam_cipher_initialize(&dinit);
615 
616 	caam_free(iv_tmp);
617 
618 	return ret;
619 }
620 
621 /*
622  * Update of the CMAC operation.
623  *
624  * @ctx   Operation software context
625  * @data  Data to encrypt
626  * @len   Data length
627  */
do_cmac_update(struct crypto_mac_ctx * ctx,const uint8_t * data,size_t len)628 static TEE_Result do_cmac_update(struct crypto_mac_ctx *ctx,
629 				 const uint8_t *data, size_t len)
630 {
631 	TEE_Result ret = TEE_ERROR_GENERIC;
632 	struct crypto_mac *mac = to_mac_ctx(ctx);
633 	struct cipherdata *macdata = mac->ctx;
634 	struct drvcrypt_cipher_update dupdate = { };
635 
636 	/* Prepare the update data */
637 	dupdate.ctx = macdata;
638 	dupdate.encrypt = true;
639 	dupdate.last = false;
640 	dupdate.src.data = (uint8_t *)data;
641 	dupdate.src.length = len;
642 	dupdate.dst.data = NULL;
643 	dupdate.dst.length = 0;
644 
645 	ret = macdata->alg->update(&dupdate);
646 
647 	if (!ret && macdata->mode == TEE_CHAIN_MODE_CBC_MAC_PKCS5)
648 		macdata->countdata += len;
649 
650 	return ret;
651 }
652 
653 /*
654  * Finalize the CMAC operation
655  *
656  * @ctx     Operation software context
657  * @digest  [out] Digest buffer
658  * @len     Digest buffer length
659  */
do_cmac_final(struct crypto_mac_ctx * ctx,uint8_t * digest,size_t len)660 static TEE_Result do_cmac_final(struct crypto_mac_ctx *ctx, uint8_t *digest,
661 				size_t len)
662 {
663 	TEE_Result ret = TEE_ERROR_GENERIC;
664 	uint8_t *pad_src = NULL;
665 	size_t pad_size = 0;
666 	struct crypto_mac *mac = to_mac_ctx(ctx);
667 	struct cipherdata *macdata = mac->ctx;
668 	struct drvcrypt_cipher_update dupdate = { };
669 
670 	if (macdata->mode == TEE_CHAIN_MODE_CBC_MAC_PKCS5) {
671 		/* Calculate the last block PAD size */
672 		pad_size = macdata->alg->size_block -
673 			   (macdata->countdata % macdata->alg->size_block);
674 		CIPHER_TRACE("Pad size = %zu", pad_size);
675 
676 		if (pad_size) {
677 			/* Need to pad the last block */
678 			pad_src = caam_calloc(pad_size);
679 			if (!pad_src) {
680 				CIPHER_TRACE("Pad src allocation error");
681 				return TEE_ERROR_OUT_OF_MEMORY;
682 			}
683 
684 			memset(pad_src, pad_size, pad_size);
685 		}
686 	}
687 
688 	/* Prepare the update data */
689 	dupdate.ctx = macdata;
690 	dupdate.encrypt = true;
691 	dupdate.last = true;
692 	dupdate.src.data = pad_src;
693 	dupdate.src.length = pad_size;
694 	dupdate.dst.data = digest;
695 	dupdate.dst.length = MIN(len, macdata->alg->size_block);
696 
697 	ret = macdata->alg->update(&dupdate);
698 
699 	caam_free(pad_src);
700 
701 	return ret;
702 }
703 
704 /*
705  * Free the software context
706  *
707  * @ctx    [in/out] Caller context variable
708  */
do_cmac_free(struct crypto_mac_ctx * ctx)709 static void do_cmac_free(struct crypto_mac_ctx *ctx)
710 {
711 	struct crypto_mac *mac = to_mac_ctx(ctx);
712 
713 	caam_cipher_free(mac->ctx);
714 	free(mac);
715 }
716 
717 /*
718  * Copy software CMAC context
719  *
720  * @dst_ctx  [out] Reference the context destination
721  * @src_ctx  Reference the context source
722  */
do_cmac_copy_state(struct crypto_mac_ctx * dst_ctx,struct crypto_mac_ctx * src_ctx)723 static void do_cmac_copy_state(struct crypto_mac_ctx *dst_ctx,
724 			       struct crypto_mac_ctx *src_ctx)
725 {
726 	struct crypto_mac *mac_src = to_mac_ctx(src_ctx);
727 	struct crypto_mac *mac_dst = to_mac_ctx(dst_ctx);
728 	struct cipherdata *macdata_dst = mac_dst->ctx;
729 	struct cipherdata *macdata_src = mac_src->ctx;
730 
731 	caam_cipher_copy_state(macdata_dst, macdata_src);
732 
733 	macdata_dst->countdata = macdata_src->countdata;
734 	macdata_dst->mode = macdata_src->mode;
735 }
736 
737 /*
738  * Registration of the CMAC driver
739  */
740 static const struct crypto_mac_ops cmac_ops = {
741 	.init = do_cmac_init,
742 	.update = do_cmac_update,
743 	.final = do_cmac_final,
744 	.free_ctx = do_cmac_free,
745 	.copy_state = do_cmac_copy_state,
746 };
747 
748 /*
749  * Allocate the software context
750  *
751  * @ctx      [out] Caller context variable
752  * @algo     Algorithm ID
753  */
caam_cmac_allocate(struct crypto_mac_ctx ** ctx,uint32_t algo)754 static TEE_Result caam_cmac_allocate(struct crypto_mac_ctx **ctx, uint32_t algo)
755 {
756 	TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
757 	struct crypto_mac *mac = NULL;
758 	const struct cipheralg *alg = NULL;
759 	struct cipherdata *macdata = NULL;
760 
761 	CIPHER_TRACE("Allocate Context (%p) algo %" PRIx32, ctx, algo);
762 
763 	alg = get_macalgo(algo);
764 	if (!alg) {
765 		CIPHER_TRACE("Algorithm not supported");
766 		return TEE_ERROR_NOT_IMPLEMENTED;
767 	}
768 
769 	mac = calloc(1, sizeof(*mac));
770 	if (!mac)
771 		return TEE_ERROR_OUT_OF_MEMORY;
772 
773 	macdata = caam_calloc(sizeof(*macdata));
774 	if (!macdata) {
775 		CIPHER_TRACE("Allocation MAC data error");
776 		ret = TEE_ERROR_OUT_OF_MEMORY;
777 		goto err;
778 	}
779 
780 	/* Allocate the descriptor */
781 	macdata->descriptor = caam_calloc_desc(MAX_DESC_ENTRIES);
782 	if (!macdata->descriptor) {
783 		CIPHER_TRACE("Allocation descriptor error");
784 		ret = TEE_ERROR_OUT_OF_MEMORY;
785 		goto err;
786 	}
787 
788 	/* Setup the algorithm pointer */
789 	macdata->alg = alg;
790 
791 	/* Initialize the block buffer */
792 	macdata->blockbuf.max = alg->size_block;
793 
794 	/* Keep the MAC mode */
795 	macdata->mode = TEE_ALG_GET_CHAIN_MODE(algo);
796 
797 	mac->mac_ctx.ops = &cmac_ops;
798 	mac->ctx = macdata;
799 
800 	*ctx = &mac->mac_ctx;
801 
802 	return TEE_SUCCESS;
803 
804 err:
805 	if (macdata)
806 		caam_free_desc(&macdata->descriptor);
807 
808 	caam_free(macdata);
809 	free(mac);
810 
811 	return ret;
812 }
813 
814 /*
815  * Initialize the CMAC module
816  *
817  * @ctrl_addr   Controller base address
818  */
caam_cmac_init(vaddr_t ctrl_addr __unused)819 enum caam_status caam_cmac_init(vaddr_t ctrl_addr __unused)
820 {
821 	if (drvcrypt_register(CRYPTO_CMAC, &caam_cmac_allocate))
822 		return CAAM_FAILURE;
823 
824 	return CAAM_NO_ERROR;
825 }
826