1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2018-2021 NXP
4 *
5 * Implementation of Hashing functions.
6 */
7 #include <caam_hal_ctrl.h>
8 #include <caam_hash.h>
9 #include <caam_jr.h>
10 #include <caam_utils_dmaobj.h>
11 #include <caam_utils_mem.h>
12 #include <caam_utils_status.h>
13 #include <drvcrypt.h>
14 #include <drvcrypt_mac.h>
15 #include <kernel/panic.h>
16 #include <mm/core_memprot.h>
17 #include <tee/cache.h>
18 #include <utee_defines.h>
19
20 #include "local.h"
21
22 #ifdef CFG_PHYS_64BIT
23 #define KEY_REDUCE_DESC_ENTRIES 10
24 #define KEY_COMPUTE_DESC_ENTRIES 10
25 #else
26 #define KEY_REDUCE_DESC_ENTRIES 8
27 #define KEY_COMPUTE_DESC_ENTRIES 8
28 #endif
29
30 static const struct crypto_mac_ops hmac_ops;
31
32 /*
33 * Format the MAC context to keep the reference to the operation driver.
34 */
35 struct crypto_mac {
36 struct crypto_mac_ctx mac_ctx; /* Crypto MAC API context */
37 struct hashctx *ctx; /* HMAC context */
38 };
39
40 /*
41 * Keep the HW hash limit because after the initialization
42 * of the module, we don't have the CAAM Controller base address
43 * to call the function returning the HW capacity.
44 */
45 static uint8_t caam_hash_limit;
46
47 /*
48 * Returns the reference to the driver context
49 *
50 * @ctx API Context
51 */
to_mac_ctx(struct crypto_mac_ctx * ctx)52 static struct crypto_mac *to_mac_ctx(struct crypto_mac_ctx *ctx)
53 {
54 assert(ctx && ctx->ops == &hmac_ops);
55
56 return container_of(ctx, struct crypto_mac, mac_ctx);
57 }
58
59 /*
60 * Reduce key to be a hash algorithm block size maximum
61 *
62 * @alg Reference to the algorithm definition
63 * @inkey Key to be reduced
64 * @outkey [out] key resulting
65 */
do_reduce_key(struct caamdmaobj * reduce_key,const struct hashalg * alg,const uint8_t * inkey,size_t len)66 static enum caam_status do_reduce_key(struct caamdmaobj *reduce_key,
67 const struct hashalg *alg,
68 const uint8_t *inkey, size_t len)
69 {
70 enum caam_status retstatus = CAAM_FAILURE;
71 struct caamdmaobj key = { };
72 struct caam_jobctx jobctx = { };
73 uint32_t *desc = NULL;
74
75 if (caam_dmaobj_input_sgtbuf(&key, inkey, len))
76 return CAAM_OUT_MEMORY;
77
78 /* Allocate the job descriptor */
79 desc = caam_calloc_desc(KEY_REDUCE_DESC_ENTRIES);
80 if (!desc) {
81 retstatus = CAAM_OUT_MEMORY;
82 goto out;
83 }
84
85 caam_desc_init(desc);
86 caam_desc_add_word(desc, DESC_HEADER(0));
87 caam_desc_add_word(desc, HASH_INITFINAL(alg->type));
88
89 /* Load the input key */
90 caam_desc_fifo_load(desc, &key, CLASS_2, MSG, LAST_C2);
91 /* Store key reduced */
92 caam_desc_store(desc, reduce_key, CLASS_2, REG_CTX);
93
94 caam_dmaobj_cache_push(&key);
95 caam_dmaobj_cache_push(reduce_key);
96
97 HASH_DUMPDESC(desc);
98
99 jobctx.desc = desc;
100 retstatus = caam_jr_enqueue(&jobctx, NULL);
101
102 if (retstatus != CAAM_NO_ERROR) {
103 HASH_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
104 retstatus = CAAM_FAILURE;
105 }
106
107 out:
108 caam_dmaobj_free(&key);
109 caam_free_desc(&desc);
110
111 return retstatus;
112 }
113
114 /*
115 * Initialization of the HMAC operation.
116 * Split the input key using the CAAM HW HMAC operation
117 * Call common initialization operation between hash and HMAC
118 *
119 * @ctx Operation software context
120 * @key Input key to compute
121 * @len Key length
122 */
do_hmac_init(struct crypto_mac_ctx * ctx,const uint8_t * inkey,size_t len)123 static TEE_Result do_hmac_init(struct crypto_mac_ctx *ctx, const uint8_t *inkey,
124 size_t len)
125 {
126 TEE_Result ret = TEE_ERROR_GENERIC;
127 enum caam_status retstatus = CAAM_FAILURE;
128 struct crypto_mac *mac = to_mac_ctx(ctx);
129 struct hashctx *hmac_ctx = mac->ctx;
130 const struct hashalg *alg = hmac_ctx->alg;
131 struct caamdmaobj reduce_key = { };
132 struct caam_jobctx jobctx = { };
133 uint32_t *desc = NULL;
134
135 /* First initialize the context */
136 ret = caam_hash_hmac_init(hmac_ctx);
137 if (ret != TEE_SUCCESS)
138 return ret;
139
140 HASH_TRACE("split key length %zu", len);
141
142 /* Allocate the job descriptor */
143 desc = caam_calloc_desc(KEY_COMPUTE_DESC_ENTRIES);
144 if (!desc) {
145 ret = TEE_ERROR_OUT_OF_MEMORY;
146 goto out;
147 }
148
149 hmac_ctx->key.length = alg->size_key;
150
151 if (len > alg->size_block) {
152 HASH_TRACE("Input key must be reduced");
153
154 ret = caam_dmaobj_output_sgtbuf(&reduce_key, NULL, 0,
155 alg->size_digest);
156 if (ret) {
157 HASH_TRACE("Reduced Key allocation error");
158 goto out;
159 }
160
161 retstatus = do_reduce_key(&reduce_key, alg, inkey, len);
162 if (retstatus != CAAM_NO_ERROR)
163 goto out;
164 } else {
165 /* Key size is correct use directly the input key */
166 ret = caam_dmaobj_input_sgtbuf(&reduce_key, inkey, len);
167 if (ret)
168 goto out;
169 }
170
171 caam_desc_init(desc);
172 caam_desc_add_word(desc, DESC_HEADER(0));
173 /* Load either input key or the reduced input key into key register */
174 caam_desc_load_key(desc, &reduce_key, CLASS_2, REG);
175 /* Split the key */
176 caam_desc_add_word(desc, HMAC_INIT_DECRYPT(alg->type));
177 caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_2, MSG, LAST_C2, 0));
178 /* Store the split key */
179 caam_desc_add_word(desc, FIFO_ST(C2_MDHA_SPLIT_KEY_AES_ECB_JKEK,
180 hmac_ctx->key.length));
181 caam_desc_add_ptr(desc, hmac_ctx->key.paddr);
182 HASH_DUMPDESC(desc);
183
184 caam_dmaobj_cache_push(&reduce_key);
185 cache_operation(TEE_CACHEFLUSH, hmac_ctx->key.data,
186 hmac_ctx->key.length);
187
188 jobctx.desc = desc;
189 retstatus = caam_jr_enqueue(&jobctx, NULL);
190
191 if (retstatus == CAAM_NO_ERROR) {
192 HASH_DUMPBUF("Split Key", hmac_ctx->key.data,
193 hmac_ctx->key.length);
194
195 ret = TEE_SUCCESS;
196 } else {
197 HASH_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
198 ret = job_status_to_tee_result(jobctx.status);
199 }
200
201 out:
202 caam_dmaobj_free(&reduce_key);
203 caam_free_desc(&desc);
204
205 return ret;
206 }
207
208 /*
209 * Update the HMAC operation
210 * Call common update operation between hash and HMAC
211 *
212 * @ctx Operation Software context
213 * @data Data to hash
214 * @len Data length
215 */
do_hmac_update(struct crypto_mac_ctx * ctx,const uint8_t * data,size_t len)216 static TEE_Result do_hmac_update(struct crypto_mac_ctx *ctx,
217 const uint8_t *data, size_t len)
218 {
219 struct crypto_mac *mac = to_mac_ctx(ctx);
220
221 return caam_hash_hmac_update(mac->ctx, data, len);
222 }
223
224 /*
225 * Finalize the HMAC operation
226 * Call common final operation between hash and HMAC
227 *
228 * @ctx Operation Software context
229 * @digest [out] Hash digest buffer
230 * @len Digest buffer length
231 */
do_hmac_final(struct crypto_mac_ctx * ctx,uint8_t * digest,size_t len)232 static TEE_Result do_hmac_final(struct crypto_mac_ctx *ctx, uint8_t *digest,
233 size_t len)
234 {
235 struct crypto_mac *mac = to_mac_ctx(ctx);
236
237 return caam_hash_hmac_final(mac->ctx, digest, len);
238 }
239
240 /*
241 * Free the software context
242 * Call common free operation between hash and HMAC
243 *
244 * @ctx Caller context variable
245 */
do_hmac_free(struct crypto_mac_ctx * ctx)246 static void do_hmac_free(struct crypto_mac_ctx *ctx)
247 {
248 struct crypto_mac *mac = to_mac_ctx(ctx);
249
250 caam_hash_hmac_free(mac->ctx);
251
252 free(mac);
253 }
254
255 /*
256 * Copy sofware HMAC context
257 * Call common copy operation between hash and HMAC
258 *
259 * @dst_ctx [out] Reference the context destination
260 * @src_ctx Reference the context source
261 */
do_hmac_copy_state(struct crypto_mac_ctx * dst_ctx,struct crypto_mac_ctx * src_ctx)262 static void do_hmac_copy_state(struct crypto_mac_ctx *dst_ctx,
263 struct crypto_mac_ctx *src_ctx)
264 {
265 struct crypto_mac *mac_src = to_mac_ctx(src_ctx);
266 struct crypto_mac *mac_dst = to_mac_ctx(dst_ctx);
267
268 return caam_hash_hmac_copy_state(mac_dst->ctx, mac_src->ctx);
269 }
270
271 /*
272 * Registration of the HMAC driver
273 */
274 static const struct crypto_mac_ops hmac_ops = {
275 .init = do_hmac_init,
276 .update = do_hmac_update,
277 .final = do_hmac_final,
278 .free_ctx = do_hmac_free,
279 .copy_state = do_hmac_copy_state,
280 };
281
282 /*
283 * Allocate the internal hashing data context
284 *
285 * @ctx [out] Caller context reference
286 * @algo Algorithm ID
287 */
caam_hmac_allocate(struct crypto_mac_ctx ** ctx,uint32_t algo)288 static TEE_Result caam_hmac_allocate(struct crypto_mac_ctx **ctx, uint32_t algo)
289 {
290 struct crypto_mac *mac = NULL;
291 struct hashctx *hmac_ctx = NULL;
292 const struct hashalg *alg = NULL;
293 TEE_Result ret = TEE_ERROR_GENERIC;
294
295 HASH_TRACE("Allocate Context (%p) algo %" PRId32, ctx, algo);
296
297 *ctx = NULL;
298
299 alg = caam_hash_get_alg(algo);
300 if (!alg)
301 return TEE_ERROR_NOT_IMPLEMENTED;
302
303 mac = calloc(1, sizeof(*mac));
304 if (!mac)
305 return TEE_ERROR_OUT_OF_MEMORY;
306
307 hmac_ctx = caam_calloc(sizeof(*hmac_ctx));
308 if (!hmac_ctx) {
309 ret = TEE_ERROR_OUT_OF_MEMORY;
310 goto err;
311 }
312
313 hmac_ctx->alg = alg;
314 mac->mac_ctx.ops = &hmac_ops;
315 mac->ctx = hmac_ctx;
316
317 *ctx = &mac->mac_ctx;
318
319 ret = caam_hash_hmac_allocate(hmac_ctx);
320 if (ret != TEE_SUCCESS)
321 goto err;
322
323 HASH_TRACE("Allocated Context (%p)", hmac_ctx);
324
325 return TEE_SUCCESS;
326
327 err:
328 free(mac);
329
330 if (hmac_ctx)
331 caam_free(hmac_ctx);
332
333 return ret;
334 }
335
caam_hmac_init(struct caam_jrcfg * caam_jrcfg)336 enum caam_status caam_hmac_init(struct caam_jrcfg *caam_jrcfg)
337 {
338 vaddr_t jr_base = caam_jrcfg->base + caam_jrcfg->offset;
339
340 caam_hash_limit = caam_hal_ctrl_hash_limit(jr_base);
341
342 if (caam_hash_limit != UINT8_MAX &&
343 caam_hal_ctrl_splitkey_support(jr_base)) {
344 if (drvcrypt_register_hmac(&caam_hmac_allocate))
345 return CAAM_FAILURE;
346 }
347
348 return CAAM_NO_ERROR;
349 }
350