1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2018-2021, 2023 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_key.h>
12 #include <caam_utils_mem.h>
13 #include <caam_utils_status.h>
14 #include <drvcrypt.h>
15 #include <drvcrypt_acipher.h>
16 #include <mm/core_memprot.h>
17 #include <tee/cache.h>
18 #include <string.h>
19
20 #ifdef CFG_CAAM_64BIT
21 #define MAX_DESC_KEY_GEN 14
22 #define MAX_DESC_SHARED 14
23 #else
24 #define MAX_DESC_KEY_GEN 9
25 #define MAX_DESC_SHARED 9
26 #endif
27
28 /*
29 * Definition of the local DH Keypair
30 */
31 struct caam_dh_keypair {
32 struct caambuf g; /* Generator */
33 struct caambuf p; /* Prime Number Modulus */
34 struct caamkey x; /* Private key */
35 struct caambuf y; /* Public key */
36 };
37
38 /*
39 * Free local DH keypair
40 *
41 * @key DH keypair
42 */
do_keypair_free(struct caam_dh_keypair * key)43 static void do_keypair_free(struct caam_dh_keypair *key)
44 {
45 caam_free_buf(&key->g);
46 caam_free_buf(&key->p);
47 caam_key_free(&key->x);
48 caam_free_buf(&key->y);
49 }
50
51 /*
52 * Convert Crypto DH Key p and g bignumbers to local buffers
53 * (via keypair object).
54 *
55 * @outkey [out] Output keypair in local format
56 * @inkey Input key in TEE Crypto format
57 */
do_keypair_conv_p_g(struct caam_dh_keypair * outkey,const struct dh_keypair * inkey)58 static enum caam_status do_keypair_conv_p_g(struct caam_dh_keypair *outkey,
59 const struct dh_keypair *inkey)
60 {
61 enum caam_status retstatus = CAAM_OUT_MEMORY;
62 size_t p_size = 0;
63 size_t field_size = 0;
64
65 p_size = crypto_bignum_num_bytes(inkey->p);
66
67 DH_TRACE("DH Convert Key Parameters (p,g) size %zu bytes", p_size);
68
69 /* Prime Number Modulus */
70 retstatus = caam_calloc_buf(&outkey->p, p_size);
71 if (retstatus != CAAM_NO_ERROR)
72 return retstatus;
73
74 crypto_bignum_bn2bin(inkey->p, outkey->p.data);
75 cache_operation(TEE_CACHECLEAN, outkey->p.data, outkey->p.length);
76
77 /* Generator */
78 retstatus = caam_calloc_buf(&outkey->g, p_size);
79 if (retstatus != CAAM_NO_ERROR)
80 return retstatus;
81
82 /* Get the number of bytes of g to pad with 0's */
83 field_size = crypto_bignum_num_bytes(inkey->g);
84 crypto_bignum_bn2bin(inkey->g, outkey->g.data + p_size - field_size);
85 cache_operation(TEE_CACHECLEAN, outkey->g.data, outkey->g.length);
86
87 return CAAM_NO_ERROR;
88 }
89
90 /*
91 * Convert Crypto DH Private Key to a local Private Key (via keypair object)
92 *
93 * @outkey [out] Output local keypair
94 * @inkey Input Private key in TEE Crypto format
95 */
do_keypriv_conv(struct caam_dh_keypair * outkey,const struct dh_keypair * inkey)96 static enum caam_status do_keypriv_conv(struct caam_dh_keypair *outkey,
97 const struct dh_keypair *inkey)
98 {
99 enum caam_status retstatus = CAAM_OUT_MEMORY;
100 size_t key_size = inkey->xbits / 8;
101 size_t p_size = 0;
102
103 if (!key_size)
104 key_size = crypto_bignum_num_bytes(inkey->x);
105
106 DH_TRACE("DH Convert Private Key size %zu bytes", key_size);
107
108 /* Prime */
109 p_size = crypto_bignum_num_bytes(inkey->p);
110 retstatus = caam_calloc_buf(&outkey->p, p_size);
111 if (retstatus != CAAM_NO_ERROR)
112 return retstatus;
113
114 crypto_bignum_bn2bin(inkey->p, outkey->p.data);
115 cache_operation(TEE_CACHECLEAN, outkey->p.data, outkey->p.length);
116
117 /* Private Key X */
118 retstatus = caam_key_deserialize_from_bn(inkey->x, &outkey->x, 0);
119 if (retstatus != CAAM_NO_ERROR)
120 return retstatus;
121
122 caam_key_cache_op(TEE_CACHECLEAN, &outkey->x);
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(CFG_CORE_BIGNUM_MAX_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 enum caam_key_type key_type = caam_key_default_key_gen_type();
230
231 l_bytes = crypto_bignum_num_bytes(key->p);
232 if (!l_bytes)
233 return TEE_ERROR_BAD_PARAMETERS;
234
235 /*
236 * If @key_size not specified, private key size is
237 * same as the public key size (same as prime size)
238 */
239 if (!n_bytes)
240 n_bytes = l_bytes;
241
242 /*
243 * CAAM private key support is limited to the descriptor PDB
244 * N maximum value (PDB_DL_KEY_N_MASK)
245 */
246 if (n_bytes > PDB_DL_KEY_N_MASK)
247 n_bytes = PDB_DL_KEY_N_MASK;
248
249 DH_TRACE("Request %zu bits key -> so do %zu bytes key", key_size,
250 n_bytes);
251
252 /* Allocate the job used to prepare the operation */
253 desc = caam_calloc_desc(MAX_DESC_KEY_GEN);
254 if (!desc) {
255 ret = TEE_ERROR_OUT_OF_MEMORY;
256 goto out;
257 }
258
259 /* Allocate Private Key to be generated */
260 caam_dh_key.x.key_type = key_type;
261 caam_dh_key.x.sec_size = n_bytes;
262 caam_dh_key.x.is_blob = false;
263
264 retstatus = caam_key_alloc(&caam_dh_key.x);
265 if (retstatus != CAAM_NO_ERROR) {
266 ret = caam_status_to_tee_result(retstatus);
267 goto out;
268 }
269
270 caam_key_cache_op(TEE_CACHEFLUSH, &caam_dh_key.x);
271
272 /* Allocate Public Key to be generated */
273 retstatus = caam_calloc_align_buf(&caam_dh_key.y, l_bytes);
274 if (retstatus != CAAM_NO_ERROR) {
275 ret = caam_status_to_tee_result(retstatus);
276 goto out;
277 }
278 cache_operation(TEE_CACHEFLUSH, caam_dh_key.y.data,
279 caam_dh_key.y.length);
280
281 /* Allocate Private Key modulus (r) and fill it with one's */
282 retstatus = caam_calloc_buf(&dh_r, n_bytes);
283 if (retstatus != CAAM_NO_ERROR) {
284 ret = caam_status_to_tee_result(retstatus);
285 goto out;
286 }
287
288 memset(dh_r.data, UINT8_MAX, dh_r.length);
289 cache_operation(TEE_CACHECLEAN, dh_r.data, dh_r.length);
290
291 /* Generator and Prime */
292 retstatus = do_keypair_conv_p_g(&caam_dh_key, key);
293 if (retstatus != CAAM_NO_ERROR) {
294 ret = caam_status_to_tee_result(retstatus);
295 goto out;
296 }
297
298 /*
299 * Build the descriptor using the PDB Public Key generation
300 * block (PD=0)
301 */
302 caam_desc_init(desc);
303 caam_desc_add_word(desc, DESC_HEADER(0));
304 caam_desc_add_word(desc, PDB_DL_KEY_L_SIZE(l_bytes) |
305 PDB_DL_KEY_N_SIZE(n_bytes));
306 caam_desc_add_ptr(desc, caam_dh_key.p.paddr);
307 caam_desc_add_ptr(desc, dh_r.paddr);
308 caam_desc_add_ptr(desc, caam_dh_key.g.paddr);
309 caam_desc_add_ptr(desc, caam_dh_key.x.buf.paddr);
310 caam_desc_add_ptr(desc, caam_dh_key.y.paddr);
311
312 switch (key_type) {
313 case CAAM_KEY_PLAIN_TEXT:
314 caam_desc_add_word(desc, PK_KEYPAIR_GEN(DL, NONE));
315 break;
316 case CAAM_KEY_BLACK_ECB:
317 caam_desc_add_word(desc, PK_KEYPAIR_GEN(DL, ECB));
318 break;
319 case CAAM_KEY_BLACK_CCM:
320 caam_desc_add_word(desc, PK_KEYPAIR_GEN(DL, CCM));
321 break;
322 default:
323 ret = TEE_ERROR_GENERIC;
324 goto out;
325 }
326
327 desclen = caam_desc_get_len(desc);
328 caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
329
330 DH_DUMPDESC(desc);
331
332 /*
333 * If the Secure Key X doesn't have the correct size
334 * retry a new generation.
335 * Retry 10 times before returing an error to not lock the system.
336 */
337 for (counter = 0; counter < 10; counter++) {
338 memset(&jobctx, 0, sizeof(jobctx));
339 jobctx.desc = desc;
340 retstatus = caam_jr_enqueue(&jobctx, NULL);
341
342 if (retstatus == CAAM_NO_ERROR) {
343 caam_key_cache_op(TEE_CACHEINVALIDATE, &caam_dh_key.x);
344 cache_operation(TEE_CACHEINVALIDATE, caam_dh_key.y.data,
345 caam_dh_key.y.length);
346
347 /* Copy Private and Public keypair */
348 ret = caam_key_serialize_to_bn(key->x, &caam_dh_key.x);
349 if (ret != TEE_SUCCESS)
350 goto out;
351
352 if (crypto_bignum_num_bytes(key->x) != n_bytes) {
353 DH_TRACE("Error X size=%zu expected %zu",
354 crypto_bignum_num_bytes(key->x),
355 n_bytes);
356 DH_DUMPBUF("X", caam_dh_key.x.data,
357 caam_dh_key.x.length);
358 DH_DUMPBUF("Y", caam_dh_key.y.data,
359 caam_dh_key.y.length);
360 continue;
361 }
362
363 ret = crypto_bignum_bin2bn(caam_dh_key.y.data,
364 caam_dh_key.y.length,
365 key->y);
366 if (ret != TEE_SUCCESS)
367 goto out;
368
369 /* Set the Private Key size in bits */
370 key->xbits = n_bytes * 8;
371
372 ret = TEE_SUCCESS;
373 goto out;
374 } else {
375 DH_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
376 ret = job_status_to_tee_result(jobctx.status);
377 goto out;
378 }
379 }
380
381 out:
382 caam_free_desc(&desc);
383 caam_free_buf(&dh_r);
384 do_keypair_free(&caam_dh_key);
385
386 return ret;
387 }
388
389 /*
390 * Compute the shared secret data from DH Private key and Public Key
391 *
392 * @sdata [in/out] DH Shared Secret data
393 */
do_shared_secret(struct drvcrypt_secret_data * sdata)394 static TEE_Result do_shared_secret(struct drvcrypt_secret_data *sdata)
395 {
396 TEE_Result ret = TEE_ERROR_GENERIC;
397 enum caam_status retstatus = CAAM_FAILURE;
398 struct dh_keypair *inkeypair = sdata->key_priv;
399 struct caam_dh_keypair caam_dh_key = { };
400 struct caamdmaobj secret = { };
401 struct caam_jobctx jobctx = { };
402 uint32_t *desc = NULL;
403 uint32_t desclen = 0;
404 uint32_t pdb_sgt_flags = 0;
405
406 DH_TRACE("DH Shared Secret");
407
408 /* Allocate the job descriptor */
409 desc = caam_calloc_desc(MAX_DESC_SHARED);
410 if (!desc) {
411 ret = TEE_ERROR_OUT_OF_MEMORY;
412 goto out;
413 }
414
415 /*
416 * ReAllocate the secret result buffer with a maximum size
417 * of the secret size if not cache aligned
418 */
419 ret = caam_dmaobj_output_sgtbuf(&secret, sdata->secret.data,
420 sdata->secret.length,
421 sdata->secret.length);
422 if (ret)
423 goto out;
424
425 if (secret.sgtbuf.sgt_type)
426 pdb_sgt_flags |= PDB_SGT_PKDH_SECRET;
427
428 caam_dmaobj_cache_push(&secret);
429
430 /* Convert the Private key to local key */
431 retstatus = do_keypriv_conv(&caam_dh_key, inkeypair);
432 if (retstatus != CAAM_NO_ERROR) {
433 ret = TEE_ERROR_OUT_OF_MEMORY;
434 goto out;
435 }
436
437 /* Convert the Public key to local key */
438 retstatus = do_keypub_conv(&caam_dh_key, sdata->key_pub);
439 if (retstatus != CAAM_NO_ERROR) {
440 ret = caam_status_to_tee_result(retstatus);
441 goto out;
442 }
443
444 /*
445 * Build the descriptor using PDB Shared Secret
446 */
447 caam_desc_init(desc);
448 caam_desc_add_word(desc, DESC_HEADER(0));
449 caam_desc_add_word(desc, pdb_sgt_flags |
450 PDB_DL_KEY_L_SIZE(caam_dh_key.y.length) |
451 PDB_DL_KEY_N_SIZE(caam_dh_key.x.sec_size));
452 /* Prime */
453 caam_desc_add_ptr(desc, caam_dh_key.p.paddr);
454 /* Modulus - Not used */
455 caam_desc_add_ptr(desc, 0);
456 /* Public key */
457 caam_desc_add_ptr(desc, caam_dh_key.y.paddr);
458 /* Private key */
459 caam_desc_add_ptr(desc, caam_dh_key.x.buf.paddr);
460 /* Output secret */
461 caam_desc_add_ptr(desc, secret.sgtbuf.paddr);
462
463 switch (caam_dh_key.x.key_type) {
464 case CAAM_KEY_PLAIN_TEXT:
465 caam_desc_add_word(desc, SHARED_SECRET(DL, NONE));
466 break;
467 case CAAM_KEY_BLACK_ECB:
468 caam_desc_add_word(desc, SHARED_SECRET(DL, ECB));
469 break;
470 case CAAM_KEY_BLACK_CCM:
471 caam_desc_add_word(desc, SHARED_SECRET(DL, CCM));
472 break;
473 default:
474 ret = TEE_ERROR_GENERIC;
475 goto out;
476 }
477
478 desclen = caam_desc_get_len(desc);
479 caam_desc_update_hdr(desc, DESC_HEADER_IDX(desclen, desclen - 1));
480
481 DH_DUMPDESC(desc);
482 jobctx.desc = desc;
483
484 retstatus = caam_jr_enqueue(&jobctx, NULL);
485
486 if (retstatus == CAAM_NO_ERROR) {
487 sdata->secret.length = caam_dmaobj_copy_to_orig(&secret);
488
489 DH_DUMPBUF("Secret", sdata->secret.data, sdata->secret.length);
490 ret = caam_status_to_tee_result(retstatus);
491 } else {
492 DH_TRACE("CAAM Status 0x%08" PRIx32, jobctx.status);
493 ret = job_status_to_tee_result(jobctx.status);
494 }
495
496 out:
497 caam_free_desc(&desc);
498 do_keypair_free(&caam_dh_key);
499 caam_dmaobj_free(&secret);
500
501 return ret;
502 }
503
504 /*
505 * Registration of the ECC Driver
506 */
507 static struct drvcrypt_dh driver_dh = {
508 .alloc_keypair = do_allocate_keypair,
509 .gen_keypair = do_gen_keypair,
510 .shared_secret = do_shared_secret,
511 };
512
caam_dh_init(struct caam_jrcfg * caam_jrcfg)513 enum caam_status caam_dh_init(struct caam_jrcfg *caam_jrcfg)
514 {
515 enum caam_status retstatus = CAAM_FAILURE;
516 vaddr_t jr_base = caam_jrcfg->base + caam_jrcfg->offset;
517
518 if (caam_hal_ctrl_pknum(jr_base) &&
519 drvcrypt_register_dh(&driver_dh) == TEE_SUCCESS)
520 retstatus = CAAM_NO_ERROR;
521
522 return retstatus;
523 }
524