1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2020-2021 NXP
4 *
5 * CAAM DSA Prime Numbering.
6 * Implementation of Prime Number functions
7 */
8 #include <caam_common.h>
9 #include <caam_desc_ccb_defines.h>
10 #include <caam_jr.h>
11 #include <caam_utils_mem.h>
12 #include <crypto/crypto.h>
13 #include <kernel/panic.h>
14 #include <mm/core_memprot.h>
15 #include <string.h>
16 #include <tee_api_types.h>
17 #include <tee/cache.h>
18
19 #include "local.h"
20
21 #define PRIME_DESC_ENTRIES 62
22
23 /* Define the number max of try to generate valid primes */
24 #define DSA_MAX_TRIES_PRIME_Q 50000
25 #define DSA_MAX_TRIES_PRIME_P 500
26
27 #define DSA_TRY_FAIL 0x42
28 #define DSA_NOT_PRIME 0x43
29 #define DSA_PRIME_TOO_SMALL 0x44
30
31 struct dsa_hash {
32 unsigned int op; /* CAAM Hash operation code */
33 size_t size; /* Hash digest size */
34 };
35
36 /*
37 * Build the descriptor generating a DSA prime Q
38 * Referring to FIPS.186-4, Section A.1.1.2 Generation of the
39 * Probable Primes p and q Using an Approved Hash Function
40 *
41 * @desc [out] Descriptor built
42 * @seed [out] Resulting seed used to generate prime
43 * @prime [in/out] Prime generation data
44 * @hash_func Selected Hash function
45 */
do_desc_prime_q(uint32_t * desc,struct caambuf * seed,struct prime_data_dsa * prime,struct dsa_hash * hash_func)46 static void do_desc_prime_q(uint32_t *desc, struct caambuf *seed,
47 struct prime_data_dsa *prime,
48 struct dsa_hash *hash_func)
49 {
50 unsigned int desclen = 0;
51 unsigned int retry_new_mr_failed = 0;
52 unsigned int retry_mr_test = 0;
53
54 caam_desc_init(desc);
55 caam_desc_add_word(desc, DESC_HEADER(0));
56
57 /* Set the PKHA N and A register size */
58 caam_desc_add_word(desc, LD_IMM(CLASS_1, REG_PKHA_N_SIZE, 4));
59 caam_desc_add_word(desc, prime->q->length);
60 caam_desc_add_word(desc, LD_IMM(CLASS_1, REG_PKHA_A_SIZE, 4));
61 caam_desc_add_word(desc, prime->q->length);
62
63 caam_desc_add_word(desc, MATH(ADD, ZERO, IMM_DATA, VSOL, 4));
64 caam_desc_add_word(desc, DSA_MAX_TRIES_PRIME_Q);
65
66 caam_desc_add_word(desc, MATHI_OP1(SHIFT_L, ONE, 63, REG2, 8));
67
68 retry_new_mr_failed = caam_desc_get_len(desc);
69
70 /* Decrement the number of try */
71 caam_desc_add_word(desc, MATH(SUB, VSOL, ONE, VSOL, 4));
72 /* Exceed retry count - exit with DSA_TRY_FAIL error */
73 caam_desc_add_word(desc,
74 HALT_USER(ALL_COND_TRUE, MATH_N, DSA_TRY_FAIL));
75
76 /* Clear Class 2 SHA */
77 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_CLEAR_WRITTEN, 4));
78 caam_desc_add_word(desc, CLR_WR_RST_C2_CHA | CLR_WR_RST_C2_DSZ);
79
80 /*
81 * Step 5. Generate Random Seed
82 *
83 * Seed Length shall be equal or greater than N (Q prime length)
84 * Seed result push in Message Data
85 */
86 if (seed->length > 16) {
87 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO_n_SIZE, 4));
88 caam_desc_add_word(desc, NFIFO_PAD(BOTH, 0, MSG, RND, 16));
89
90 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO_n_SIZE, 4));
91 caam_desc_add_word(desc,
92 NFIFO_PAD(BOTH, NFIFO_LC1 | NFIFO_LC2, MSG,
93 RND, seed->length - 16));
94 } else {
95 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO_n_SIZE, 4));
96 caam_desc_add_word(desc, NFIFO_PAD(BOTH, NFIFO_LC1 | NFIFO_LC2,
97 MSG, RND, seed->length));
98 }
99
100 caam_desc_add_word(desc, MOVE(C1_ALIGN, OFIFO, 0, seed->length));
101 caam_desc_add_word(desc, FIFO_ST(MSG_DATA, seed->length));
102 caam_desc_add_ptr(desc, seed->paddr);
103
104 /*
105 * Hash the Seed, this is a pseudo U, bits upper N - 1 still present
106 */
107 caam_desc_add_word(desc, HASH_INITFINAL(hash_func->op));
108
109 /*
110 * Step 6. U = hash(seed) mod 2^(N-1)
111 * Step 7. q = 2^(N-1) + U + 1 - (U mod 2)
112 */
113 /* Trash the bits > N - 1, the hash size is >= N */
114 caam_desc_add_word(desc,
115 MOVE_WAIT(C2_CTX_REG, MATH_REG0,
116 hash_func->size - prime->q->length, 8));
117
118 /* Get the MSB of U and set the bit N-1 */
119 caam_desc_add_word(desc, MATH(OR, REG2, REG0, REG0, 8));
120
121 /* Move the candidate prime q's MSB into IFIFO */
122 caam_desc_add_word(desc, MOVE_WAIT(MATH_REG0, IFIFO, 0, 8));
123
124 /*
125 * Move the candidate prime q's intermediate value into IFIFO
126 */
127 caam_desc_add_word(desc,
128 MOVE_WAIT(C2_CTX_REG, IFIFO,
129 hash_func->size - prime->q->length + 8,
130 prime->q->length - 16));
131
132 /* Get the LSB of U and set the bit 0 */
133 caam_desc_add_word(desc, MOVE_WAIT(C2_CTX_REG, MATH_REG0,
134 hash_func->size - 8, 8));
135 caam_desc_add_word(desc, MATH(OR, ONE, REG0, REG0, 8));
136
137 /* Move the candidate prime q's LSB into IFIFO */
138 caam_desc_add_word(desc, MOVE_WAIT(MATH_REG0, IFIFO, 0, 8));
139
140 /* Move the IFIFO in to PKHA N */
141 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8));
142 caam_desc_add_word(desc, NFIFO_NOPAD(C1, NFIFO_FC1, IFIFO, PKHA_N, 0));
143 caam_desc_add_word(desc, prime->q->length);
144
145 /* Store the Prime q here because Miller-Rabin test affect PKHA N */
146 caam_desc_add_word(desc, FIFO_ST(PKHA_N, prime->q->length));
147 caam_desc_add_ptr(desc, prime->q->paddr);
148
149 /*
150 * Step 8. Test q prime with 'miller-rabin' test
151 *
152 * Load the number of Miller-Rabin test iteration
153 */
154 caam_desc_add_word(desc, MATH(ADD, IMM_DATA, ZERO, SIL, 4));
155 if (prime->p->length <= 1024 / 8)
156 caam_desc_add_word(desc, 40);
157 else if (prime->p->length >= 3072 / 8)
158 caam_desc_add_word(desc, 64);
159 else
160 caam_desc_add_word(desc, 56);
161
162 retry_mr_test = caam_desc_get_len(desc);
163
164 /* Generate 8 random bytes 'miller-rabin seed' */
165 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8));
166 caam_desc_add_word(desc, NFIFO_PAD(C1, NFIFO_FC1, PKHA_A, RND, 0));
167 caam_desc_add_word(desc, prime->q->length);
168 caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1));
169 caam_desc_add_word(desc, 0x01);
170 caam_desc_add_word(desc, PKHA_OP(MR_PRIMER_TEST, B));
171
172 desclen = caam_desc_get_len(desc);
173
174 /*
175 * Step 9. If q is not q prime back to step 5
176 */
177 caam_desc_add_word(desc, JUMP_CNO_LOCAL(ANY_COND_FALSE,
178 JMP_COND(PKHA_IS_PRIME),
179 retry_new_mr_failed - desclen));
180 caam_desc_add_word(desc, MATH(SUB, SIL, ONE, SIL, 4));
181
182 desclen = caam_desc_get_len(desc);
183 /* Test while number of MR test iteration not complete */
184 caam_desc_add_word(desc,
185 JUMP_CNO_LOCAL(ALL_COND_FALSE,
186 JMP_COND(MATH_N) | JMP_COND(MATH_Z),
187 retry_mr_test - desclen));
188 DSA_TRACE("Prime Q descriptor");
189 DSA_DUMPDESC(desc);
190 }
191
192 /*
193 * Build the descriptor generating the intermediate value X (step 11.3)
194 * Referring to FIPS.186-4, Section A.1.1.2 Generation of the
195 * Probable Primes p and q Using an Approved Hash Function
196 *
197 * @desc [out] Descriptor built
198 * @x [out] Value X
199 * @seed [in/out] Seed to hash and next seed for next loop
200 * @prime [in/out] Prime generation data
201 * @hash_func Selected Hash function
202 * @mod_n Modular value (0xFF filled buffer)
203 * @desc_p Physical address of the descriptor doing Prime P
204 */
do_desc_gen_x(uint32_t * desc,struct caambuf * x,struct caambuf * seed,struct prime_data_dsa * prime,struct dsa_hash * hash_func,struct caambuf * mod_n,paddr_t desc_p)205 static void do_desc_gen_x(uint32_t *desc, struct caambuf *x,
206 struct caambuf *seed, struct prime_data_dsa *prime,
207 struct dsa_hash *hash_func, struct caambuf *mod_n,
208 paddr_t desc_p)
209 {
210 unsigned int desclen = 0;
211 unsigned int loop_n = 0;
212 size_t n = 0;
213 size_t b = 0;
214 size_t b_offset = 0;
215
216 /*
217 * Step 3. n = ceil(L / outlen) - 1
218 * where outlen is the hash size in bits
219 *
220 * Note build descriptor with n = ceil(L / outlen) to
221 * pre-calculate seed for next run.
222 */
223 n = (prime->p->length + hash_func->size) * 8 - 1;
224 n /= hash_func->size * 8;
225
226 /*
227 * Step 4. b = L - 1 - (n * outlen)
228 *
229 * Note b determine the number of bits to keep in the last
230 * Vn computed.
231 * Calculate b_offset which is the offset in bytes to remove from
232 * the calculated hash
233 */
234 b = prime->p->length * 8 - 1 - (n - 1) * hash_func->size * 8;
235
236 DSA_TRACE("Prime p => n = %zu | b = %zu", n - 1, b);
237 b_offset = hash_func->size - (b + 1) / 8;
238 DSA_TRACE("Vn offset is %zu", b_offset);
239
240 caam_desc_init(desc);
241 caam_desc_add_word(desc, DESC_HEADER(0));
242
243 caam_desc_add_word(desc, SEQ_OUT_PTR(x->length));
244 caam_desc_add_ptr(desc, x->paddr);
245
246 caam_desc_add_word(desc, MATHI_OP1(SHIFT_L, ONE, 63, REG2, 8));
247
248 caam_desc_add_word(desc, MATH(ADD, ZERO, IMM_DATA, REG0, 4));
249 caam_desc_add_word(desc, n);
250
251 caam_desc_add_word(desc,
252 FIFO_LD(CLASS_1, PKHA_N, NOACTION, seed->length));
253 caam_desc_add_ptr(desc, mod_n->paddr);
254
255 /*
256 * Because the Sequence Out Pointer is incremental store, we need
257 * to build w number in reverse.
258 *
259 * Hence, calculate the last seed number of the loop and save it.
260 * Step 11.9 is automatically done here by incrementing seed number.
261 */
262 caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1));
263 caam_desc_add_word(desc, n);
264 caam_desc_add_word(desc,
265 FIFO_LD(CLASS_1, PKHA_A, NOACTION, seed->length));
266 caam_desc_add_ptr(desc, seed->paddr);
267 caam_desc_add_word(desc, PKHA_OP(MOD_ADD_A_B, A));
268 caam_desc_add_word(desc, FIFO_ST(PKHA_A, seed->length));
269 caam_desc_add_ptr(desc, seed->paddr);
270
271 caam_desc_add_word(desc, PKHA_CPY_NSIZE(A0, B1));
272 caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1));
273 caam_desc_add_word(desc, 1);
274
275 caam_desc_add_word(desc, WAIT_COND(ALL_COND_TRUE, NIFP));
276
277 /*
278 * Step 11.1
279 * For j = 0 to n do
280 * Vj = hash((seed + offset + j) mod 2^seedlen
281 * Step 11.2
282 * W = V0 + (V1 * 2^outlen) + ... +
283 * (Vn-1 * 2^((n-1)*outlen)) +
284 * ((Vn mod 2^b) * 2^(n*outlen))
285 */
286 loop_n = caam_desc_get_len(desc);
287
288 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_CLEAR_WRITTEN, 4));
289 caam_desc_add_word(desc, CLR_WR_IFIFO_NFIFO | CLR_WR_RST_C2_CHA |
290 CLR_WR_RST_C2_DSZ);
291
292 caam_desc_add_word(desc, HASH_INITFINAL(hash_func->op));
293 caam_desc_add_word(desc, LD_NOCLASS_IMM(REG_CHA_CTRL, 4));
294 caam_desc_add_word(desc, CCTRL_ULOAD_PKHA_A);
295
296 caam_desc_add_word(desc,
297 MOVE_WAIT(OFIFO, IFIFO_C2_LC2, 0, seed->length));
298
299 /* If Math Register 2 is zero bypass the high bit set to one */
300 caam_desc_add_word(desc, MATH(SUB, REG2, ONE, NODEST, 8));
301 caam_desc_add_word(desc,
302 JUMP_CNO_LOCAL(ANY_COND_TRUE,
303 JMP_COND(MATH_N) | JMP_COND(MATH_Z),
304 8));
305 /*
306 * Step 11.3
307 * X = W + 2^(L-1)
308 *
309 * Set the high bit to one
310 * Remark: the DSA key is a modulus 8 bytes, hence no need
311 * to check if the b_offset is less than 8.
312 */
313 caam_desc_add_word(desc, MOVE_WAIT(C2_CTX_REG, MATH_REG1, b_offset, 8));
314 caam_desc_add_word(desc, MATH(OR, REG2, REG1, REG1, 8));
315 caam_desc_add_word(desc, MOVE(MATH_REG1, OFIFO, 0, 8));
316
317 if (hash_func->size - b_offset > 8)
318 caam_desc_add_word(desc,
319 MOVE_WAIT(C2_CTX_REG, OFIFO, b_offset + 8,
320 hash_func->size - b_offset - 8));
321 caam_desc_add_word(desc,
322 FIFO_ST_SEQ(MSG_DATA, hash_func->size - b_offset));
323
324 /*
325 * Reset MATH Register 2 to bypass the High Bit set
326 * operation next loop
327 */
328 caam_desc_add_word(desc, MATH(AND, REG2, ZERO, REG2, 8));
329
330 caam_desc_add_word(desc,
331 JUMP_CNO_LOCAL(ALL_COND_TRUE, JMP_COND(NONE), 2));
332
333 /* Bypass High Bit set */
334 caam_desc_add_word(desc,
335 ST_NOIMM_SEQ(CLASS_2, REG_CTX, hash_func->size));
336
337 caam_desc_add_word(desc, PKHA_CPY_NSIZE(B1, A0));
338 caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, A));
339 caam_desc_add_word(desc, PKHA_CPY_NSIZE(A0, B1));
340
341 desclen = caam_desc_get_len(desc);
342 caam_desc_add_word(desc, JUMP_CNO_LOCAL_DEC(ALL_COND_FALSE, MATH_0,
343 JMP_COND_MATH(N) |
344 JMP_COND_MATH(Z),
345 loop_n - desclen));
346 /* Jump to the next descriptor desc */
347 caam_desc_add_word(desc, JUMP_NOTLOCAL(CLASS_NO, ALL_COND_TRUE,
348 JMP_COND(NONE)));
349 caam_desc_add_ptr(desc, desc_p);
350
351 DSA_TRACE("X descriptor");
352 DSA_DUMPDESC(desc);
353 }
354
355 /*
356 * Build the descriptor generating the Prime P from value X
357 * Referring to FIPS.186-4, Section A.1.1.2 Generation of the
358 * Probable Primes p and q Using an Approved Hash Function
359 *
360 * @desc [out] Descriptor built
361 * @prime [in/out] Prime generation data
362 * @x Value X
363 * @mod_n Modular value (0xFF filled buffer)
364 */
do_desc_prime_p(uint32_t * desc,struct prime_data_dsa * prime,struct caambuf * x,struct caambuf * mod_n)365 static void do_desc_prime_p(uint32_t *desc, struct prime_data_dsa *prime,
366 struct caambuf *x, struct caambuf *mod_n)
367 {
368 unsigned int desclen = 0;
369 unsigned int retry_mr_test = 0;
370 size_t index = 0;
371
372 caam_desc_init(desc);
373 caam_desc_add_word(desc, DESC_HEADER(0));
374
375 caam_desc_add_word(desc,
376 FIFO_LD(CLASS_1, PKHA_N, NOACTION, mod_n->length));
377 caam_desc_add_ptr(desc, mod_n->paddr);
378
379 /*
380 * Step 11.4
381 * c = X mod 2q
382 */
383
384 /* Calculate 2q and store it in PKHA N */
385 caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION,
386 prime->q->length));
387 caam_desc_add_ptr(desc, prime->q->paddr);
388 caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, B0));
389 caam_desc_add_word(desc, PKHA_OP(MOD_ADD_A_B, A));
390
391 caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, N0));
392
393 /* c = X mod 2q */
394 caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, x->length));
395 caam_desc_add_ptr(desc, x->paddr);
396 caam_desc_add_word(desc,
397 JUMP_CNO_LOCAL(ALL_COND_TRUE, JMP_COND(NIFP), 1) |
398 BIT(24));
399 caam_desc_add_word(desc, PKHA_OP(MOD_AMODN, A));
400
401 /*
402 * Step 11.5
403 * p = X - (c - 1)
404 */
405 caam_desc_add_word(desc,
406 FIFO_LD(CLASS_1, PKHA_N, NOACTION, mod_n->length));
407 caam_desc_add_ptr(desc, mod_n->paddr);
408
409 caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1));
410 caam_desc_add_ptr(desc, 1);
411 caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, B));
412
413 caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, x->length));
414 caam_desc_add_ptr(desc, x->paddr);
415 caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, A));
416
417 /*
418 * Save the candidate Prime q now because N is going to be
419 * affected by the Miller-Rabin test
420 */
421 caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, N0));
422 caam_desc_add_word(desc, FIFO_ST(PKHA_N, prime->p->length));
423 caam_desc_add_ptr(desc, prime->p->paddr);
424 caam_desc_add_word(desc, FIFO_ST_SEQ(MSG_DATA, 0));
425
426 /*
427 * Step 11.6
428 * if (p < 2^(L-1)) then go to step 11.9
429 *
430 */
431 caam_desc_add_word(desc, LD_NOCLASS_IMM(REG_CHA_CTRL, 4));
432 caam_desc_add_word(desc, CCTRL_ULOAD_PKHA_A);
433
434 /* Keep the MSB from p candidate and check if bit 2^(L-1) is set */
435 caam_desc_add_word(desc, MOVE_WAIT(OFIFO, MATH_REG0, 0, 8));
436 for (index = 1; index < prime->p->length / 128; index++)
437 caam_desc_add_word(desc, MOVE(OFIFO, C1_CTX_REG, 0, 128));
438
439 caam_desc_add_word(desc, MOVE(OFIFO, C1_CTX_REG, 0, 124));
440
441 caam_desc_add_word(desc, MATHI_OP1(SHIFT_L, ONE, 63, REG2, 8));
442 caam_desc_add_word(desc, MATH(AND, REG0, REG2, REG0, 8));
443
444 caam_desc_add_word(desc, HALT_USER(ALL_COND_TRUE, MATH_Z,
445 DSA_PRIME_TOO_SMALL));
446
447 /*
448 * Step 11.7
449 * Test whether or not p is prime
450 *
451 * Referring to FIPS.186-4, Table C.1
452 * Get the number Miller-Rabin test interation function
453 * of the prime number size
454 */
455 caam_desc_add_word(desc, MATH(ADD, IMM_DATA, ZERO, REG0, 4));
456 if (prime->p->length <= 1024 / 8)
457 caam_desc_add_word(desc, 40);
458 else if (prime->p->length >= 3072 / 8)
459 caam_desc_add_word(desc, 64);
460 else
461 caam_desc_add_word(desc, 56);
462
463 retry_mr_test = caam_desc_get_len(desc);
464 /* Generate 8 random bytes 'miller-rabin seed' */
465 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8));
466 caam_desc_add_word(desc, NFIFO_PAD(C1, NFIFO_FC1, PKHA_A, RND, 0));
467 caam_desc_add_word(desc, prime->p->length);
468 caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1));
469 caam_desc_add_word(desc, 0x01);
470 caam_desc_add_word(desc, PKHA_OP(MR_PRIMER_TEST, B));
471
472 desclen = caam_desc_get_len(desc);
473
474 /*
475 * Step 11.8
476 * if p is not a prime continue to step 11.9
477 */
478 caam_desc_add_word(desc, HALT_USER(ALL_COND_FALSE, PKHA_IS_PRIME,
479 DSA_NOT_PRIME));
480
481 desclen = caam_desc_get_len(desc);
482 /* Test while number of MR test iteration not complete */
483 caam_desc_add_word(desc, JUMP_CNO_LOCAL_DEC(ALL_COND_FALSE, MATH_0,
484 JMP_COND_MATH(N) |
485 JMP_COND_MATH(Z),
486 retry_mr_test - desclen));
487
488 DSA_TRACE("Prime P descriptor");
489 DSA_DUMPDESC(desc);
490
491 /*
492 * Ensure descriptor is pushed in physical memory because it's
493 * called from another descriptor.
494 */
495 cache_operation(TEE_CACHECLEAN, desc, DESC_SZBYTES(PRIME_DESC_ENTRIES));
496 }
497
498 /*
499 * Run the Prime Q descriptor.
500 *
501 * @desc Descriptor built
502 */
run_prime_q(uint32_t * desc,struct prime_data_dsa * prime)503 static enum caam_status run_prime_q(uint32_t *desc,
504 struct prime_data_dsa *prime)
505 {
506 enum caam_status retstatus = CAAM_FAILURE;
507 struct caam_jobctx jobctx = { };
508
509 cache_operation(TEE_CACHEFLUSH, prime->q->data, prime->q->length);
510
511 jobctx.desc = desc;
512 retstatus = caam_jr_enqueue(&jobctx, NULL);
513
514 if (retstatus != CAAM_NO_ERROR) {
515 DSA_TRACE("Prime Q Status 0x%08" PRIx32 " ret 0x%08" PRIx32,
516 jobctx.status, retstatus);
517 retstatus = CAAM_FAILURE;
518 } else {
519 cache_operation(TEE_CACHEINVALIDATE, prime->q->data,
520 prime->q->length);
521 DSA_DUMPBUF("Prime Q", prime->q->data, prime->q->length);
522 }
523
524 return retstatus;
525 }
526
527 /*
528 * Run the Prime P descriptors.
529 *
530 * @desc Descriptor built
531 * @prime Prime generation data
532 */
run_prime_p(uint32_t * desc,struct prime_data_dsa * prime)533 static enum caam_status run_prime_p(uint32_t *desc,
534 struct prime_data_dsa *prime)
535 {
536 enum caam_status retstatus = CAAM_FAILURE;
537 struct caam_jobctx jobctx = { };
538 size_t counter = 0;
539
540 cache_operation(TEE_CACHEFLUSH, prime->p->data, prime->p->length);
541
542 jobctx.desc = desc;
543 for (counter = 0; counter < 4 * prime->p->length * 8; counter++) {
544 retstatus = caam_jr_enqueue(&jobctx, NULL);
545
546 if (retstatus == CAAM_NO_ERROR) {
547 DSA_TRACE("Prime P try: counter=%zu", counter);
548 cache_operation(TEE_CACHEINVALIDATE, prime->p->data,
549 prime->p->length);
550 DSA_DUMPBUF("Prime P", prime->p->data,
551 prime->p->length);
552
553 return retstatus;
554 }
555
556 if (retstatus == CAAM_JOB_STATUS) {
557 if (JRSTA_GET_HALT_USER(jobctx.status) !=
558 DSA_NOT_PRIME &&
559 JRSTA_GET_HALT_USER(jobctx.status) !=
560 DSA_PRIME_TOO_SMALL) {
561 DSA_TRACE("Prime P status 0x%08" PRIx32,
562 jobctx.status);
563 return CAAM_FAILURE;
564 }
565 }
566 }
567
568 /* This is not a prime, will try with another prime q */
569 return CAAM_BAD_PARAM;
570 }
571
572 /*
573 * Generate the DSA parameter G (generator)
574 * Referring to FIPS.186-4, Section A.2.1 Unverifiable Generation of the
575 * Generator g
576 *
577 * @desc Descriptor buffer to use
578 * @prime [in/out] Prime generation data
579 * @mod_n Modular value (0xFF filled buffer)
580 */
do_generator(uint32_t * desc,struct prime_data_dsa * prime,struct caambuf * mod_n)581 static enum caam_status do_generator(uint32_t *desc,
582 struct prime_data_dsa *prime,
583 struct caambuf *mod_n)
584 {
585 enum caam_status retstatus = CAAM_FAILURE;
586 struct caam_jobctx jobctx = { };
587 unsigned int desclen = 0;
588 unsigned int retry_new_h = 0;
589
590 caam_desc_init(desc);
591 caam_desc_add_word(desc, DESC_HEADER(0));
592
593 caam_desc_add_word(desc,
594 FIFO_LD(CLASS_1, PKHA_N, NOACTION, mod_n->length));
595 caam_desc_add_ptr(desc, mod_n->paddr);
596
597 /*
598 * Step 1.
599 * e = (p - 1)/q
600 */
601 caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION,
602 prime->p->length));
603 caam_desc_add_ptr(desc, prime->p->paddr);
604 caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1));
605 caam_desc_add_ptr(desc, 1);
606 /* PKHA B = (p - 1) */
607 caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, B));
608
609 caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION,
610 prime->q->length));
611 caam_desc_add_ptr(desc, prime->q->paddr);
612 /* PKHA A = 1/q */
613 caam_desc_add_word(desc, PKHA_OP(MOD_INV_A, A));
614
615 /* PKHA E = (p - 1)/q */
616 caam_desc_add_word(desc, PKHA_OP(MOD_MUL_A_B, A));
617 caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, E));
618
619 /* Load N with prime p */
620 caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_N, NOACTION,
621 prime->p->length));
622 caam_desc_add_ptr(desc, prime->p->paddr);
623
624 /*
625 * Step 2. Generate a Random h
626 * where 1 < h < (p - 1)
627 *
628 * To ensure h < (p - 1), generate a random of p length - 2
629 */
630 retry_new_h = caam_desc_get_len(desc);
631 caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8));
632 caam_desc_add_word(desc, NFIFO_PAD(C1, NFIFO_FC1, PKHA_A, RND, 0));
633 caam_desc_add_word(desc, prime->p->length - 2);
634
635 /*
636 * Step 3.
637 * g = h^e mod p
638 */
639 caam_desc_add_word(desc, PKHA_OP(MOD_EXP_A_E, A));
640
641 /*
642 * Step 4.
643 * if (g = 1) then go to step 2
644 */
645 desclen = caam_desc_get_len(desc);
646 caam_desc_add_word(desc,
647 JUMP_CNO_LOCAL(ALL_COND_TRUE, JMP_COND(PKHA_GCD_1),
648 retry_new_h - desclen));
649
650 /* g is good save it */
651 caam_desc_add_word(desc, FIFO_ST(PKHA_A, prime->g->length));
652 caam_desc_add_ptr(desc, prime->g->paddr);
653
654 DSA_DUMPDESC(desc);
655
656 cache_operation(TEE_CACHEFLUSH, prime->g->data, prime->g->length);
657
658 jobctx.desc = desc;
659 retstatus = caam_jr_enqueue(&jobctx, NULL);
660
661 if (retstatus != CAAM_NO_ERROR) {
662 DSA_TRACE("Generator G Status 0x%08" PRIx32 " ret 0x%08" PRIx32,
663 jobctx.status, retstatus);
664 return CAAM_FAILURE;
665 }
666
667 cache_operation(TEE_CACHEINVALIDATE, prime->g->data, prime->g->length);
668 DSA_DUMPBUF("Generator G", prime->g->data, prime->g->length);
669
670 return CAAM_NO_ERROR;
671 }
672
caam_prime_dsa_gen(struct prime_data_dsa * data)673 enum caam_status caam_prime_dsa_gen(struct prime_data_dsa *data)
674 {
675 enum caam_status retstatus = CAAM_FAILURE;
676 uint32_t *desc_all = NULL;
677 uint32_t *desc_q = NULL;
678 uint32_t *desc_x = NULL;
679 uint32_t *desc_p = NULL;
680 struct caambuf seed = { };
681 struct caambuf mod_n = { };
682 struct dsa_hash hash_func = { OP_ALGO(SHA256), TEE_SHA256_HASH_SIZE };
683 size_t nb_tries = 0;
684 struct caambuf x = { };
685
686 /*
687 * For the now as the DSA Prime p size is limited to 3072, Prime q
688 * is also limited to 256. Hence the hash function to use is
689 * SHA-256.
690 * Ensure here that limit is not crossed because on some i.MX device
691 * hash is limited to 256.
692 */
693 if (data->q->length > 256)
694 return CAAM_BAD_PARAM;
695
696 retstatus = caam_calloc_buf(&mod_n, data->p->length);
697 if (retstatus != CAAM_NO_ERROR)
698 goto out;
699
700 memset(mod_n.data, 0xFF, mod_n.length);
701 cache_operation(TEE_CACHECLEAN, mod_n.data, mod_n.length);
702
703 retstatus = caam_calloc_align_buf(&seed, data->q->length);
704 if (retstatus != CAAM_NO_ERROR)
705 return retstatus;
706
707 retstatus = caam_calloc_buf(&x, data->p->length);
708 if (retstatus != CAAM_NO_ERROR)
709 return retstatus;
710
711 desc_all = caam_calloc_desc(PRIME_DESC_ENTRIES * 3);
712 if (!desc_all) {
713 retstatus = CAAM_OUT_MEMORY;
714 goto out;
715 }
716
717 DSA_TRACE("Do primes P %zu bytes, Q %zu bytes", data->p->length,
718 data->q->length);
719
720 desc_q = desc_all;
721 desc_x = desc_q + PRIME_DESC_ENTRIES;
722 desc_p = desc_x + PRIME_DESC_ENTRIES;
723
724 do_desc_prime_q(desc_q, &seed, data, &hash_func);
725 do_desc_gen_x(desc_x, &x, &seed, data, &hash_func, &mod_n,
726 virt_to_phys(desc_p));
727 do_desc_prime_p(desc_p, data, &x, &mod_n);
728
729 cache_operation(TEE_CACHEFLUSH, data->p->data, data->p->length);
730 cache_operation(TEE_CACHEFLUSH, seed.data, seed.length);
731 cache_operation(TEE_CACHEFLUSH, x.data, x.length);
732
733 for (nb_tries = DSA_MAX_TRIES_PRIME_P; nb_tries > 0; nb_tries--) {
734 retstatus = run_prime_q(desc_q, data);
735
736 if (retstatus == CAAM_NO_ERROR) {
737 retstatus = run_prime_p(desc_x, data);
738 if (retstatus == CAAM_NO_ERROR)
739 break;
740 }
741
742 if (retstatus == CAAM_FAILURE) {
743 DSA_TRACE("DSA Prime P/Q Generation failed");
744 break;
745 }
746 }
747
748 if (retstatus == CAAM_NO_ERROR)
749 retstatus = do_generator(desc_all, data, &mod_n);
750
751 out:
752 caam_free_desc(&desc_all);
753 caam_free_buf(&seed);
754 caam_free_buf(&x);
755 caam_free_buf(&mod_n);
756
757 return retstatus;
758 }
759