xref: /optee_os/core/drivers/crypto/caam/ae/caam_ae_ccm.c (revision a75d305d48d89d70c813266fac3b0b337e42b9e7)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2024 NXP
4  *
5  * Implementation of Cipher CCM functions
6  */
7 #include <caam_common.h>
8 #include <caam_utils_mem.h>
9 #include <caam_utils_status.h>
10 #include <drvcrypt_math.h>
11 #include <string.h>
12 #include <string_ext.h>
13 #include <utee_defines.h>
14 
15 #include "local.h"
16 
17 /* Length of AAD buffer size, as in SP800-38C */
18 #define AAD_SIZE_LEN 2
19 
20 /* Nonce length */
21 #define AES_CCM_MAX_NONCE_LEN 15
22 
23 /* Tag length */
24 #define AES_CCM_MIN_TAG_LEN 4
25 #define AES_CCM_MAX_TAG_LEN 16
26 
27 /* Adata Flag */
28 #define BM_B0_ADATA_PRESENCE BIT32(6)
29 
30 /* B0 Tag length */
31 #define BS_B0_TAG_LENGTH 3
32 #define BM_B0_TAG_LENGTH SHIFT_U32(0x7, BS_B0_TAG_LENGTH)
33 #define B0_TAG_LENGTH(x) \
34 	(SHIFT_U32(((x) - 2) / 2, BS_B0_TAG_LENGTH) & BM_B0_TAG_LENGTH)
35 
36 /* B0 Payload size length */
37 #define BS_B0_Q_LENGTH 0
38 #define BM_B0_Q_LENGTH SHIFT_U32(0x7, BS_B0_Q_LENGTH)
39 #define B0_Q_LENGTH(x) (SHIFT_U32((x) - 1, BS_B0_Q_LENGTH) & BM_B0_Q_LENGTH)
40 
41 /*
42  * Initialize AES CCM operation context
43  *
44  * @caam_ctx AE Cipher context
45  * @dinit    Data initialization object
46  */
caam_ae_ccm_init_ctx(struct caam_ae_ctx * caam_ctx,struct drvcrypt_authenc_init * dinit)47 static TEE_Result caam_ae_ccm_init_ctx(struct caam_ae_ctx *caam_ctx,
48 				       struct drvcrypt_authenc_init *dinit)
49 {
50 	TEE_Result ret = TEE_ERROR_GENERIC;
51 	enum caam_status retstatus = CAAM_FAILURE;
52 	struct caambuf aad = { };
53 	uint8_t *b0 = NULL;
54 	uint8_t *ctr0 = NULL;
55 	size_t q = 0;
56 	size_t payload_len = 0;
57 	size_t i = 0;
58 
59 	assert(caam_ctx && dinit);
60 
61 	if (dinit->nonce.length > AES_CCM_MAX_NONCE_LEN)
62 		return TEE_ERROR_BAD_PARAMETERS;
63 
64 	/* The tag_len should be 4, 6, 8, 10, 12, 14 or 16 */
65 	if (caam_ctx->tag_length < 4 || caam_ctx->tag_length > 16 ||
66 	    caam_ctx->tag_length % 2 != 0)
67 		return TEE_ERROR_BAD_PARAMETERS;
68 
69 	payload_len = caam_ctx->payload_length;
70 
71 	/*
72 	 * Before AE operations CAAM ctx register
73 	 * must be filled with B0 and Ctr0.
74 	 */
75 	b0 = caam_ctx->initial_ctx.data;
76 	ctr0 = caam_ctx->initial_ctx.data + TEE_AES_BLOCK_SIZE;
77 
78 	/*
79 	 * Set B0 initial value
80 	 * B0 initial value (specification SP 800-38C) contains flags,
81 	 * data length (Whole operation length in case of init update final)
82 	 * and nonce
83 	 */
84 	memset(b0, 0, TEE_AES_BLOCK_SIZE);
85 
86 	/* Available length for the data size length field */
87 	q = AES_CCM_MAX_NONCE_LEN - dinit->nonce.length;
88 
89 	/* Flags value in b0[0] */
90 	b0[0] = B0_TAG_LENGTH(caam_ctx->tag_length) | B0_Q_LENGTH(q);
91 	if (caam_ctx->aad_length)
92 		b0[0] |= BM_B0_ADATA_PRESENCE;
93 
94 	/* Nonce value in b0[1..AES_CCM_MAX_NONCE_LEN] */
95 	memcpy(&b0[1], dinit->nonce.data, dinit->nonce.length);
96 
97 	/*
98 	 * Payload length as defined in SP800-38C,
99 	 * A.2.1 Formatting of the Control Information and the Nonce
100 	 * Payload length (i.e. Q) is store in big-endian fashion.
101 	 */
102 	for (i = AES_CCM_MAX_NONCE_LEN; i >= dinit->nonce.length + 1; i--) {
103 		b0[i] = payload_len & 0xFF;
104 		payload_len >>= 8;
105 	}
106 
107 	/* Add AAD size to Adata */
108 	if (caam_ctx->aad_length > 0) {
109 		if (caam_ctx->aad_length >= AAD_LENGTH_OVERFLOW)
110 			return TEE_ERROR_NOT_SUPPORTED;
111 
112 		retstatus = caam_calloc_align_buf(&aad, AAD_SIZE_LEN);
113 		if (retstatus)
114 			return caam_status_to_tee_result(retstatus);
115 
116 		aad.data[0] = (caam_ctx->aad_length & GENMASK_32(15, 8)) >> 8;
117 		aad.data[1] = caam_ctx->aad_length & GENMASK_32(7, 0);
118 		retstatus = caam_cpy_block_src(&caam_ctx->buf_aad, &aad, 0);
119 		if (retstatus) {
120 			ret = caam_status_to_tee_result(retstatus);
121 			goto out;
122 		}
123 	}
124 
125 	/*
126 	 * Set CTR0 initial value
127 	 * Ctr0 initial value (specification SP 800-38C) contains flags
128 	 * and nonce
129 	 */
130 	memset(ctr0, 0, TEE_AES_BLOCK_SIZE);
131 
132 	/* Flags value in ctr0[0] */
133 	ctr0[0] = B0_Q_LENGTH(q);
134 
135 	/* Nonce value in ctr0[1..AES_CCM_MAX_NONCE_LEN] */
136 	memcpy(&ctr0[1], &b0[1], dinit->nonce.length);
137 
138 	ret = TEE_SUCCESS;
139 out:
140 	caam_free_buf(&aad);
141 	return ret;
142 }
143 
caam_ae_initialize_ccm(struct drvcrypt_authenc_init * dinit)144 TEE_Result caam_ae_initialize_ccm(struct drvcrypt_authenc_init *dinit)
145 {
146 	TEE_Result ret = TEE_ERROR_GENERIC;
147 	enum caam_status retstatus = CAAM_FAILURE;
148 	struct caam_ae_ctx *caam_ctx = NULL;
149 
150 	if (!dinit || !dinit->ctx)
151 		return TEE_ERROR_BAD_PARAMETERS;
152 
153 	caam_ctx = dinit->ctx;
154 
155 	if (caam_ctx->tag_length < AES_CCM_MIN_TAG_LEN ||
156 	    caam_ctx->tag_length > AES_CCM_MAX_TAG_LEN)
157 		return TEE_ERROR_NOT_SUPPORTED;
158 
159 	/* Allocate initial B0 and CTR0 input */
160 	retstatus = caam_alloc_align_buf(&caam_ctx->initial_ctx,
161 					 caam_ctx->alg->size_ctx);
162 	if (retstatus)
163 		return caam_status_to_tee_result(retstatus);
164 
165 	/* Initialize the AAD buffer */
166 	caam_ctx->buf_aad.max = dinit->aad_len + AAD_SIZE_LEN;
167 
168 	ret = caam_ae_ccm_init_ctx(caam_ctx, dinit);
169 	if (ret)
170 		goto err;
171 
172 	return TEE_SUCCESS;
173 err:
174 	caam_free_buf(&caam_ctx->initial_ctx);
175 
176 	return ret;
177 }
178 
caam_ae_final_ccm(struct drvcrypt_authenc_final * dfinal)179 TEE_Result caam_ae_final_ccm(struct drvcrypt_authenc_final *dfinal)
180 {
181 	TEE_Result ret = TEE_ERROR_GENERIC;
182 	struct caam_ae_ctx *caam_ctx = NULL;
183 	uint8_t *encrypted_tag = NULL;
184 	struct drvcrypt_mod_op mod_op = { };
185 
186 	if (!dfinal || !dfinal->ctx)
187 		return TEE_ERROR_BAD_PARAMETERS;
188 
189 	caam_ctx = dfinal->ctx;
190 
191 	ret = caam_ae_do_update(caam_ctx, &dfinal->src, &dfinal->dst, true);
192 	if (ret)
193 		return ret;
194 
195 	if (caam_ctx->tag_length) {
196 		if (dfinal->tag.length < caam_ctx->tag_length)
197 			return TEE_ERROR_BAD_PARAMETERS;
198 
199 		if (caam_ctx->encrypt) {
200 			encrypted_tag = caam_ctx->ctx.data +
201 					(2 * AES_CCM_MAX_TAG_LEN);
202 
203 			memcpy(dfinal->tag.data, encrypted_tag,
204 			       caam_ctx->tag_length);
205 			dfinal->tag.length = caam_ctx->tag_length;
206 		} else {
207 			encrypted_tag = caam_ctx->ctx.data;
208 
209 			mod_op.n.length = caam_ctx->tag_length;
210 			mod_op.a.data = encrypted_tag;
211 			mod_op.a.length = caam_ctx->tag_length;
212 			mod_op.b.data = encrypted_tag +
213 					2 * AES_CCM_MAX_TAG_LEN;
214 			mod_op.b.length = caam_ctx->tag_length;
215 			mod_op.result.data = encrypted_tag;
216 			mod_op.result.length = caam_ctx->tag_length;
217 
218 			ret = drvcrypt_xor_mod_n(&mod_op);
219 			if (ret)
220 				return ret;
221 
222 			if (consttime_memcmp(dfinal->tag.data, encrypted_tag,
223 					     caam_ctx->tag_length))
224 				return TEE_ERROR_MAC_INVALID;
225 		}
226 	}
227 
228 	return TEE_SUCCESS;
229 }
230