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 CIPHER_TRACE("Do input %zu bytes, offset %zu",
507 size_done, offset);
508
509 ret = run_cmac_desc(ctx, &src, NULL, false);
510 } else {
511 CIPHER_TRACE("Do saved blockbuf %zu bytes (done = %zu)",
512 ctx->blockbuf.filled, size_done);
513 ret = run_cmac_desc(ctx, NULL, NULL, false);
514 }
515
516 if (ret)
517 goto end_cmac;
518 }
519
520 if (dupdate->last) {
521 if (dupdate->src.length - size_inmade) {
522 size_done = dupdate->src.length - size_inmade;
523 ret = caam_dmaobj_sgtbuf_build(&src, &size_done, offset,
524 ctx->alg->size_block);
525 if (ret)
526 goto end_cmac;
527
528 if (size_done != dupdate->src.length - size_inmade) {
529 ret = TEE_ERROR_GENERIC;
530 goto end_cmac;
531 }
532
533 ret = run_cmac_desc(ctx, &src, &dst, true);
534 } else {
535 ret = run_cmac_desc(ctx, NULL, &dst, true);
536 }
537
538 if (!ret)
539 caam_dmaobj_copy_to_orig(&dst);
540 }
541
542 end_cmac_post:
543 if (size_topost) {
544 struct caambuf srcbuf = { .data = dupdate->src.data,
545 .length = dupdate->src.length };
546
547 CIPHER_TRACE("Post %zu of input len %zu made %zu", size_topost,
548 srcbuf.length, size_inmade);
549
550 retstatus = caam_cpy_block_src(&ctx->blockbuf, &srcbuf,
551 size_inmade);
552 ret = caam_status_to_tee_result(retstatus);
553 }
554
555 end_cmac:
556 caam_dmaobj_free(&src);
557 caam_dmaobj_free(&dst);
558
559 return ret;
560 }
561
562 /*
563 * Initialization of the CMAC operation.
564 *
565 * @ctx Operation software context
566 * @key Input key to compute
567 * @len Key length
568 */
do_cmac_init(struct crypto_mac_ctx * ctx,const uint8_t * key,size_t len)569 static TEE_Result do_cmac_init(struct crypto_mac_ctx *ctx, const uint8_t *key,
570 size_t len)
571 {
572 TEE_Result ret = TEE_ERROR_GENERIC;
573 uint8_t *iv_tmp = NULL;
574 struct drvcrypt_cipher_init dinit = { };
575 struct crypto_mac *mac = to_mac_ctx(ctx);
576 struct cipherdata *macdata = mac->ctx;
577
578 if (macdata->mode != TEE_CHAIN_MODE_CMAC) {
579 /* Allocate temporary IV initialize with 0's */
580 iv_tmp = caam_calloc(macdata->alg->size_ctx);
581 if (!iv_tmp)
582 return TEE_ERROR_OUT_OF_MEMORY;
583 } else {
584 /*
585 * Check if the context register is allocated to free it,
586 * because in case of CMAC mode, the context register
587 * is allocated during do_update_cmac() operation if
588 * necessary.
589 */
590 if (macdata->ctx.data)
591 caam_free_buf(&macdata->ctx);
592 }
593
594 macdata->countdata = 0;
595
596 /* Prepare the initialization data */
597 dinit.ctx = macdata;
598 dinit.encrypt = true;
599 dinit.key1.data = (uint8_t *)key;
600 dinit.key1.length = len;
601 dinit.key2.data = NULL;
602 dinit.key2.length = 0;
603 dinit.iv.data = iv_tmp;
604 dinit.iv.length = macdata->alg->size_ctx;
605 ret = caam_cipher_initialize(&dinit);
606
607 caam_free(iv_tmp);
608
609 return ret;
610 }
611
612 /*
613 * Update of the CMAC operation.
614 *
615 * @ctx Operation software context
616 * @data Data to encrypt
617 * @len Data length
618 */
do_cmac_update(struct crypto_mac_ctx * ctx,const uint8_t * data,size_t len)619 static TEE_Result do_cmac_update(struct crypto_mac_ctx *ctx,
620 const uint8_t *data, size_t len)
621 {
622 TEE_Result ret = TEE_ERROR_GENERIC;
623 struct crypto_mac *mac = to_mac_ctx(ctx);
624 struct cipherdata *macdata = mac->ctx;
625 struct drvcrypt_cipher_update dupdate = { };
626
627 /* Prepare the update data */
628 dupdate.ctx = macdata;
629 dupdate.encrypt = true;
630 dupdate.last = false;
631 dupdate.src.data = (uint8_t *)data;
632 dupdate.src.length = len;
633 dupdate.dst.data = NULL;
634 dupdate.dst.length = 0;
635
636 ret = macdata->alg->update(&dupdate);
637
638 if (!ret && macdata->mode == TEE_CHAIN_MODE_CBC_MAC_PKCS5)
639 macdata->countdata += len;
640
641 return ret;
642 }
643
644 /*
645 * Finalize the CMAC operation
646 *
647 * @ctx Operation software context
648 * @digest [out] Digest buffer
649 * @len Digest buffer length
650 */
do_cmac_final(struct crypto_mac_ctx * ctx,uint8_t * digest,size_t len)651 static TEE_Result do_cmac_final(struct crypto_mac_ctx *ctx, uint8_t *digest,
652 size_t len)
653 {
654 TEE_Result ret = TEE_ERROR_GENERIC;
655 uint8_t *pad_src = NULL;
656 size_t pad_size = 0;
657 struct crypto_mac *mac = to_mac_ctx(ctx);
658 struct cipherdata *macdata = mac->ctx;
659 struct drvcrypt_cipher_update dupdate = { };
660
661 if (macdata->mode == TEE_CHAIN_MODE_CBC_MAC_PKCS5) {
662 /* Calculate the last block PAD size */
663 pad_size = macdata->alg->size_block -
664 (macdata->countdata % macdata->alg->size_block);
665 CIPHER_TRACE("Pad size = %zu", pad_size);
666
667 if (pad_size) {
668 /* Need to pad the last block */
669 pad_src = caam_calloc(pad_size);
670 if (!pad_src) {
671 CIPHER_TRACE("Pad src allocation error");
672 return TEE_ERROR_OUT_OF_MEMORY;
673 }
674
675 memset(pad_src, pad_size, pad_size);
676 }
677 }
678
679 /* Prepare the update data */
680 dupdate.ctx = macdata;
681 dupdate.encrypt = true;
682 dupdate.last = true;
683 dupdate.src.data = pad_src;
684 dupdate.src.length = pad_size;
685 dupdate.dst.data = digest;
686 dupdate.dst.length = MIN(len, macdata->alg->size_block);
687
688 ret = macdata->alg->update(&dupdate);
689
690 caam_free(pad_src);
691
692 return ret;
693 }
694
695 /*
696 * Free the software context
697 *
698 * @ctx [in/out] Caller context variable
699 */
do_cmac_free(struct crypto_mac_ctx * ctx)700 static void do_cmac_free(struct crypto_mac_ctx *ctx)
701 {
702 struct crypto_mac *mac = to_mac_ctx(ctx);
703
704 caam_cipher_free(mac->ctx);
705 free(mac);
706 }
707
708 /*
709 * Copy software CMAC context
710 *
711 * @dst_ctx [out] Reference the context destination
712 * @src_ctx Reference the context source
713 */
do_cmac_copy_state(struct crypto_mac_ctx * dst_ctx,struct crypto_mac_ctx * src_ctx)714 static void do_cmac_copy_state(struct crypto_mac_ctx *dst_ctx,
715 struct crypto_mac_ctx *src_ctx)
716 {
717 struct crypto_mac *mac_src = to_mac_ctx(src_ctx);
718 struct crypto_mac *mac_dst = to_mac_ctx(dst_ctx);
719 struct cipherdata *macdata_dst = mac_dst->ctx;
720 struct cipherdata *macdata_src = mac_src->ctx;
721
722 caam_cipher_copy_state(macdata_dst, macdata_src);
723
724 macdata_dst->countdata = macdata_src->countdata;
725 macdata_dst->mode = macdata_src->mode;
726 }
727
728 /*
729 * Registration of the CMAC driver
730 */
731 static const struct crypto_mac_ops cmac_ops = {
732 .init = do_cmac_init,
733 .update = do_cmac_update,
734 .final = do_cmac_final,
735 .free_ctx = do_cmac_free,
736 .copy_state = do_cmac_copy_state,
737 };
738
739 /*
740 * Allocate the software context
741 *
742 * @ctx [out] Caller context variable
743 * @algo Algorithm ID
744 */
caam_cmac_allocate(struct crypto_mac_ctx ** ctx,uint32_t algo)745 static TEE_Result caam_cmac_allocate(struct crypto_mac_ctx **ctx, uint32_t algo)
746 {
747 TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED;
748 struct crypto_mac *mac = NULL;
749 const struct cipheralg *alg = NULL;
750 struct cipherdata *macdata = NULL;
751
752 CIPHER_TRACE("Allocate Context (%p) algo %" PRIx32, ctx, algo);
753
754 alg = get_macalgo(algo);
755 if (!alg) {
756 CIPHER_TRACE("Algorithm not supported");
757 return TEE_ERROR_NOT_IMPLEMENTED;
758 }
759
760 mac = calloc(1, sizeof(*mac));
761 if (!mac)
762 return TEE_ERROR_OUT_OF_MEMORY;
763
764 macdata = caam_calloc(sizeof(*macdata));
765 if (!macdata) {
766 CIPHER_TRACE("Allocation MAC data error");
767 ret = TEE_ERROR_OUT_OF_MEMORY;
768 goto err;
769 }
770
771 /* Allocate the descriptor */
772 macdata->descriptor = caam_calloc_desc(MAX_DESC_ENTRIES);
773 if (!macdata->descriptor) {
774 CIPHER_TRACE("Allocation descriptor error");
775 ret = TEE_ERROR_OUT_OF_MEMORY;
776 goto err;
777 }
778
779 /* Setup the algorithm pointer */
780 macdata->alg = alg;
781
782 /* Initialize the block buffer */
783 macdata->blockbuf.max = alg->size_block;
784
785 /* Keep the MAC mode */
786 macdata->mode = TEE_ALG_GET_CHAIN_MODE(algo);
787
788 mac->mac_ctx.ops = &cmac_ops;
789 mac->ctx = macdata;
790
791 *ctx = &mac->mac_ctx;
792
793 return TEE_SUCCESS;
794
795 err:
796 if (macdata)
797 caam_free_desc(&macdata->descriptor);
798
799 caam_free(macdata);
800 free(mac);
801
802 return ret;
803 }
804
805 /*
806 * Initialize the CMAC module
807 *
808 * @ctrl_addr Controller base address
809 */
caam_cmac_init(vaddr_t ctrl_addr __unused)810 enum caam_status caam_cmac_init(vaddr_t ctrl_addr __unused)
811 {
812 if (drvcrypt_register(CRYPTO_CMAC, &caam_cmac_allocate))
813 return CAAM_FAILURE;
814
815 return CAAM_NO_ERROR;
816 }
817