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