1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2018-2021 NXP
4  *
5  * Implementation of DH
6  */
7 #include <caam_acipher.h>
8 #include <caam_common.h>
9 #include <caam_hal_ctrl.h>
10 #include <caam_jr.h>
11 #include <caam_utils_mem.h>
12 #include <caam_utils_status.h>
13 #include <drvcrypt.h>
14 #include <drvcrypt_acipher.h>
15 #include <mm/core_memprot.h>
16 #include <tee/cache.h>
17 #include <string.h>
18 
19 #ifdef CFG_CAAM_64BIT
20 #define MAX_DESC_KEY_GEN 14
21 #define MAX_DESC_SHARED  14
22 #else
23 #define MAX_DESC_KEY_GEN 9
24 #define MAX_DESC_SHARED  9
25 #endif
26 
27 /*
28  * Definition of the local DH Keypair
29  */
30 struct caam_dh_keypair {
31 	struct caambuf g; /* Generator */
32 	struct caambuf p; /* Prime Number Modulus */
33 	struct caambuf x; /* Private key */
34 	struct caambuf y; /* Public key */
35 };
36 
37 /*
38  * Free local DH keypair
39  *
40  * @key DH keypair
41  */
do_keypair_free(struct caam_dh_keypair * key)42 static void do_keypair_free(struct caam_dh_keypair *key)
43 {
44 	caam_free_buf(&key->g);
45 	caam_free_buf(&key->p);
46 	caam_free_buf(&key->x);
47 	caam_free_buf(&key->y);
48 }
49 
50 /*
51  * Convert Crypto DH Key p and g bignumbers to local buffers
52  * (via keypair object).
53  *
54  * @outkey [out] Output keypair in local format
55  * @inkey  Input key in TEE Crypto format
56  */
do_keypair_conv_p_g(struct caam_dh_keypair * outkey,const struct dh_keypair * inkey)57 static enum caam_status do_keypair_conv_p_g(struct caam_dh_keypair *outkey,
58 					    const struct dh_keypair *inkey)
59 {
60 	enum caam_status retstatus = CAAM_OUT_MEMORY;
61 	size_t p_size = 0;
62 	size_t field_size = 0;
63 
64 	p_size = crypto_bignum_num_bytes(inkey->p);
65 
66 	DH_TRACE("DH Convert Key Parameters (p,g) size %zu bytes", p_size);
67 
68 	/* Prime Number Modulus */
69 	retstatus = caam_calloc_buf(&outkey->p, p_size);
70 	if (retstatus != CAAM_NO_ERROR)
71 		return retstatus;
72 
73 	crypto_bignum_bn2bin(inkey->p, outkey->p.data);
74 	cache_operation(TEE_CACHECLEAN, outkey->p.data, outkey->p.length);
75 
76 	/* Generator */
77 	retstatus = caam_calloc_buf(&outkey->g, p_size);
78 	if (retstatus != CAAM_NO_ERROR)
79 		return retstatus;
80 
81 	/* Get the number of bytes of g to pad with 0's */
82 	field_size = crypto_bignum_num_bytes(inkey->g);
83 	crypto_bignum_bn2bin(inkey->g, outkey->g.data + p_size - field_size);
84 	cache_operation(TEE_CACHECLEAN, outkey->g.data, outkey->g.length);
85 
86 	return CAAM_NO_ERROR;
87 }
88 
89 /*
90  * Convert Crypto DH Private Key to a local Private Key (via keypair object)
91  *
92  * @outkey [out] Output local keypair
93  * @inkey  Input Private key in TEE Crypto format
94  */
do_keypriv_conv(struct caam_dh_keypair * outkey,const struct dh_keypair * inkey)95 static enum caam_status do_keypriv_conv(struct caam_dh_keypair *outkey,
96 					const struct dh_keypair *inkey)
97 {
98 	enum caam_status retstatus = CAAM_OUT_MEMORY;
99 	size_t key_size = inkey->xbits / 8;
100 	size_t p_size = 0;
101 
102 	if (!key_size)
103 		key_size = crypto_bignum_num_bytes(inkey->x);
104 
105 	DH_TRACE("DH Convert Private Key size %zu bytes", key_size);
106 
107 	/* Prime */
108 	p_size = crypto_bignum_num_bytes(inkey->p);
109 	retstatus = caam_calloc_buf(&outkey->p, p_size);
110 	if (retstatus != CAAM_NO_ERROR)
111 		return retstatus;
112 
113 	crypto_bignum_bn2bin(inkey->p, outkey->p.data);
114 	cache_operation(TEE_CACHECLEAN, outkey->p.data, outkey->p.length);
115 
116 	/* Private Key X */
117 	retstatus = caam_calloc_buf(&outkey->x, key_size);
118 	if (retstatus != CAAM_NO_ERROR)
119 		return retstatus;
120 
121 	crypto_bignum_bn2bin(inkey->x, outkey->x.data);
122 	cache_operation(TEE_CACHECLEAN, outkey->x.data, outkey->x.length);
123 
124 	return CAAM_NO_ERROR;
125 }
126 
127 /*
128  * Convert Crypto DH Public Key to local Public Key (via a keypair object)
129  *
130  * @outkey [out] Output local keypair
131  * @inkey  Input Public key in TEE Crypto format
132  */
do_keypub_conv(struct caam_dh_keypair * outkey,const struct bignum * inkey)133 static enum caam_status do_keypub_conv(struct caam_dh_keypair *outkey,
134 				       const struct bignum *inkey)
135 {
136 	enum caam_status retstatus = CAAM_OUT_MEMORY;
137 	size_t key_size = 0;
138 
139 	key_size = crypto_bignum_num_bytes((struct bignum *)inkey);
140 	DH_TRACE("DH Convert Keypair size %zu bytes", key_size);
141 
142 	/* Public Key Y */
143 	retstatus = caam_calloc_buf(&outkey->y, key_size);
144 	if (retstatus != CAAM_NO_ERROR)
145 		return retstatus;
146 
147 	crypto_bignum_bn2bin(inkey, outkey->y.data);
148 	cache_operation(TEE_CACHECLEAN, outkey->y.data, outkey->y.length);
149 
150 	return CAAM_NO_ERROR;
151 }
152 
153 /*
154  * Allocate a TEE DH keypair.
155  * Note: The subprime q is not used but it must be allocated to prevent
156  * system referencing issues when object is destroyed.
157  *
158  * @key       Keypair
159  * @size_bits Key size in bits
160  */
do_allocate_keypair(struct dh_keypair * key,size_t size_bits)161 static TEE_Result do_allocate_keypair(struct dh_keypair *key, size_t size_bits)
162 {
163 	DH_TRACE("Allocate Keypair of %zu bits", size_bits);
164 
165 	/* Initialize the key fields to NULL */
166 	memset(key, 0, sizeof(*key));
167 
168 	/* Allocate Generator Scalar */
169 	key->g = crypto_bignum_allocate(size_bits);
170 	if (!key->g)
171 		goto err;
172 
173 	/* Allocate Prime Number Modulus */
174 	key->p = crypto_bignum_allocate(size_bits);
175 	if (!key->p)
176 		goto err;
177 
178 	/* Allocate Private key X */
179 	key->x = crypto_bignum_allocate(size_bits);
180 	if (!key->x)
181 		goto err;
182 
183 	/* Allocate Public Key Y */
184 	key->y = crypto_bignum_allocate(size_bits);
185 	if (!key->y)
186 		goto err;
187 
188 	/* Allocate Subprime even if not used */
189 	key->q = crypto_bignum_allocate(size_bits);
190 	if (!key->q)
191 		goto err;
192 
193 	return TEE_SUCCESS;
194 
195 err:
196 	DH_TRACE("Allocation error");
197 
198 	crypto_bignum_free(key->g);
199 	crypto_bignum_free(key->p);
200 	crypto_bignum_free(key->x);
201 	crypto_bignum_free(key->y);
202 
203 	return TEE_ERROR_OUT_OF_MEMORY;
204 }
205 
206 /*
207  * Generates an DH keypair
208  * Keypair @key contains the input prime p and generator g values
209  * The function calculates private x and public y, knowing that the
210  * number of bits of x is either key_size if specified or p size.
211  *
212  * @key      [in/out] Keypair
213  * @q        Sub Prime (not used)
214  * @key_size Key size in bits multiple of 8 bits
215  */
do_gen_keypair(struct dh_keypair * key,struct bignum * q __unused,size_t key_size)216 static TEE_Result do_gen_keypair(struct dh_keypair *key,
217 				 struct bignum *q __unused, size_t key_size)
218 {
219 	TEE_Result ret = TEE_ERROR_GENERIC;
220 	enum caam_status retstatus = CAAM_FAILURE;
221 	struct caam_dh_keypair caam_dh_key = { };
222 	struct caambuf dh_r = { };
223 	size_t n_bytes = key_size / 8;
224 	size_t l_bytes = 0;
225 	struct caam_jobctx jobctx = { };
226 	uint32_t *desc = NULL;
227 	uint32_t desclen = 0;
228 	int counter = 0;
229 
230 	l_bytes = crypto_bignum_num_bytes(key->p);
231 	if (!l_bytes)
232 		return TEE_ERROR_BAD_PARAMETERS;
233 
234 	/*
235 	 * If @key_size not specified, private key size is
236 	 * same as the public key size (same as prime size)
237 	 */
238 	if (!n_bytes)
239 		n_bytes = l_bytes;
240 
241 	/*
242 	 * CAAM private key support is limited to the descriptor PDB
243 	 * N maximum value (PDB_DL_KEY_N_MASK)
244 	 */
245 	if (n_bytes > PDB_DL_KEY_N_MASK)
246 		n_bytes = PDB_DL_KEY_N_MASK;
247 
248 	DH_TRACE("Request %zu bits key -> so do %zu bytes key", key_size,
249 		 n_bytes);
250 
251 	/* Allocate the job used to prepare the operation */
252 	desc = caam_calloc_desc(MAX_DESC_KEY_GEN);
253 	if (!desc) {
254 		ret = TEE_ERROR_OUT_OF_MEMORY;
255 		goto out;
256 	}
257 
258 	/* Allocate Private Key to be generated */
259 	retstatus = caam_calloc_align_buf(&caam_dh_key.x, n_bytes);
260 	if (retstatus != CAAM_NO_ERROR) {
261 		ret = caam_status_to_tee_result(retstatus);
262 		goto out;
263 	}
264 	cache_operation(TEE_CACHEFLUSH, caam_dh_key.x.data,
265 			caam_dh_key.x.length);
266 
267 	/* Allocate Public Key to be generated */
268 	retstatus = caam_calloc_align_buf(&caam_dh_key.y, l_bytes);
269 	if (retstatus != CAAM_NO_ERROR) {
270 		ret = caam_status_to_tee_result(retstatus);
271 		goto out;
272 	}
273 	cache_operation(TEE_CACHEFLUSH, caam_dh_key.y.data,
274 			caam_dh_key.y.length);
275 
276 	/* Allocate Private Key modulus (r) and fill it with one's */
277 	retstatus = caam_calloc_buf(&dh_r, n_bytes);
278 	if (retstatus != CAAM_NO_ERROR) {
279 		ret = caam_status_to_tee_result(retstatus);
280 		goto out;
281 	}
282 
283 	memset(dh_r.data, UINT8_MAX, dh_r.length);
284 	cache_operation(TEE_CACHECLEAN, dh_r.data, dh_r.length);
285 
286 	/* Generator and Prime */
287 	retstatus = do_keypair_conv_p_g(&caam_dh_key, key);
288 	if (retstatus != CAAM_NO_ERROR) {
289 		ret = caam_status_to_tee_result(retstatus);
290 		goto out;
291 	}
292 
293 	/*
294 	 * Build the descriptor using the PDB Public Key generation
295 	 * block (PD=0)
296 	 */
297 	caam_desc_init(desc);
298 	caam_desc_add_word(desc, DESC_HEADER(0));
299 	caam_desc_add_word(desc, PDB_DL_KEY_L_SIZE(l_bytes) |
300 				 PDB_DL_KEY_N_SIZE(n_bytes));
301 	caam_desc_add_ptr(desc, caam_dh_key.p.paddr);
302 	caam_desc_add_ptr(desc, dh_r.paddr);
303 	caam_desc_add_ptr(desc, caam_dh_key.g.paddr);
304 	caam_desc_add_ptr(desc, caam_dh_key.x.paddr);
305 	caam_desc_add_ptr(desc, caam_dh_key.y.paddr);
306 	caam_desc_add_word(desc, PK_KEYPAIR_GEN(DL));
307 
308 	desclen = caam_desc_get_len(desc);
309 	caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
310 
311 	DH_DUMPDESC(desc);
312 
313 	/*
314 	 * If the Secure Key X doesn't have the correct size
315 	 * retry a new generation.
316 	 * Retry 10 times before returing an error to not lock the system.
317 	 */
318 	for (counter = 0; counter < 10; counter++) {
319 		memset(&jobctx, 0, sizeof(jobctx));
320 		jobctx.desc = desc;
321 		retstatus = caam_jr_enqueue(&jobctx, NULL);
322 
323 		if (retstatus == CAAM_NO_ERROR) {
324 			cache_operation(TEE_CACHEINVALIDATE, caam_dh_key.x.data,
325 					caam_dh_key.x.length);
326 			cache_operation(TEE_CACHEINVALIDATE, caam_dh_key.y.data,
327 					caam_dh_key.y.length);
328 
329 			/* Copy Private and Public keypair */
330 			ret = crypto_bignum_bin2bn(caam_dh_key.x.data,
331 						   caam_dh_key.x.length,
332 						   key->x);
333 			if (ret != TEE_SUCCESS)
334 				goto out;
335 
336 			if (crypto_bignum_num_bytes(key->x) != n_bytes) {
337 				DH_TRACE("Error X size=%zu expected %zu",
338 					 crypto_bignum_num_bytes(key->x),
339 					 n_bytes);
340 				DH_DUMPBUF("X", caam_dh_key.x.data,
341 					   caam_dh_key.x.length);
342 				DH_DUMPBUF("Y", caam_dh_key.y.data,
343 					   caam_dh_key.y.length);
344 				continue;
345 			}
346 
347 			ret = crypto_bignum_bin2bn(caam_dh_key.y.data,
348 						   caam_dh_key.y.length,
349 						   key->y);
350 			if (ret != TEE_SUCCESS)
351 				goto out;
352 
353 			/* Set the Private Key size in bits */
354 			key->xbits = n_bytes * 8;
355 
356 			ret = TEE_SUCCESS;
357 			goto out;
358 		} else {
359 			DH_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
360 			ret = job_status_to_tee_result(jobctx.status);
361 			goto out;
362 		}
363 	}
364 
365 out:
366 	caam_free_desc(&desc);
367 	caam_free_buf(&dh_r);
368 	do_keypair_free(&caam_dh_key);
369 
370 	return ret;
371 }
372 
373 /*
374  * Compute the shared secret data from DH Private key and Public Key
375  *
376  * @sdata   [in/out] DH Shared Secret data
377  */
do_shared_secret(struct drvcrypt_secret_data * sdata)378 static TEE_Result do_shared_secret(struct drvcrypt_secret_data *sdata)
379 {
380 	TEE_Result ret = TEE_ERROR_GENERIC;
381 	enum caam_status retstatus = CAAM_FAILURE;
382 	struct dh_keypair *inkeypair = sdata->key_priv;
383 	struct caam_dh_keypair caam_dh_key = { };
384 	struct caamdmaobj secret = { };
385 	struct caam_jobctx jobctx = { };
386 	uint32_t *desc = NULL;
387 	uint32_t desclen = 0;
388 	uint32_t pdb_sgt_flags = 0;
389 
390 	DH_TRACE("DH Shared Secret");
391 
392 	/* Allocate the job descriptor */
393 	desc = caam_calloc_desc(MAX_DESC_SHARED);
394 	if (!desc) {
395 		ret = TEE_ERROR_OUT_OF_MEMORY;
396 		goto out;
397 	}
398 
399 	/*
400 	 * ReAllocate the secret result buffer with a maximum size
401 	 * of the secret size if not cache aligned
402 	 */
403 	ret = caam_dmaobj_output_sgtbuf(&secret, sdata->secret.data,
404 					sdata->secret.length,
405 					sdata->secret.length);
406 	if (ret)
407 		goto out;
408 
409 	if (secret.sgtbuf.sgt_type)
410 		pdb_sgt_flags |= PDB_SGT_PKDH_SECRET;
411 
412 	caam_dmaobj_cache_push(&secret);
413 
414 	/* Convert the Private key to local key */
415 	retstatus = do_keypriv_conv(&caam_dh_key, inkeypair);
416 	if (retstatus != CAAM_NO_ERROR) {
417 		ret = TEE_ERROR_OUT_OF_MEMORY;
418 		goto out;
419 	}
420 
421 	/* Convert the Public key to local key */
422 	retstatus = do_keypub_conv(&caam_dh_key, sdata->key_pub);
423 	if (retstatus != CAAM_NO_ERROR) {
424 		ret = caam_status_to_tee_result(retstatus);
425 		goto out;
426 	}
427 
428 	/*
429 	 * Build the descriptor using PDB Shared Secret
430 	 */
431 	caam_desc_init(desc);
432 	caam_desc_add_word(desc, DESC_HEADER(0));
433 	caam_desc_add_word(desc, pdb_sgt_flags |
434 				 PDB_DL_KEY_L_SIZE(caam_dh_key.y.length) |
435 				 PDB_DL_KEY_N_SIZE(caam_dh_key.x.length));
436 	/* Prime */
437 	caam_desc_add_ptr(desc, caam_dh_key.p.paddr);
438 	/* Modulus - Not used */
439 	caam_desc_add_ptr(desc, 0);
440 	/* Public key */
441 	caam_desc_add_ptr(desc, caam_dh_key.y.paddr);
442 	/* Private key */
443 	caam_desc_add_ptr(desc, caam_dh_key.x.paddr);
444 	/* Output secret */
445 	caam_desc_add_ptr(desc, secret.sgtbuf.paddr);
446 
447 	caam_desc_add_word(desc, SHARED_SECRET(DL));
448 	desclen = caam_desc_get_len(desc);
449 	caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
450 
451 	DH_DUMPDESC(desc);
452 	jobctx.desc = desc;
453 
454 	retstatus = caam_jr_enqueue(&jobctx, NULL);
455 
456 	if (retstatus == CAAM_NO_ERROR) {
457 		sdata->secret.length = caam_dmaobj_copy_to_orig(&secret);
458 
459 		DH_DUMPBUF("Secret", sdata->secret.data, sdata->secret.length);
460 		ret = caam_status_to_tee_result(retstatus);
461 	} else {
462 		DH_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
463 		ret = job_status_to_tee_result(jobctx.status);
464 	}
465 
466 out:
467 	caam_free_desc(&desc);
468 	do_keypair_free(&caam_dh_key);
469 	caam_dmaobj_free(&secret);
470 
471 	return ret;
472 }
473 
474 /*
475  * Registration of the ECC Driver
476  */
477 static struct drvcrypt_dh driver_dh = {
478 	.alloc_keypair = do_allocate_keypair,
479 	.gen_keypair = do_gen_keypair,
480 	.shared_secret = do_shared_secret,
481 };
482 
caam_dh_init(struct caam_jrcfg * caam_jrcfg)483 enum caam_status caam_dh_init(struct caam_jrcfg *caam_jrcfg)
484 {
485 	enum caam_status retstatus = CAAM_FAILURE;
486 	vaddr_t jr_base = caam_jrcfg->base + caam_jrcfg->offset;
487 
488 	if (caam_hal_ctrl_pknum(jr_base) &&
489 	    drvcrypt_register_dh(&driver_dh) == TEE_SUCCESS)
490 		retstatus = CAAM_NO_ERROR;
491 
492 	return retstatus;
493 }
494