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