// SPDX-License-Identifier: BSD-2-Clause /* * Copyright 2020-2021 NXP * * CAAM DSA Prime Numbering. * Implementation of Prime Number functions */ #include #include #include #include #include #include #include #include #include #include #include "local.h" #define PRIME_DESC_ENTRIES 62 /* Define the number max of try to generate valid primes */ #define DSA_MAX_TRIES_PRIME_Q 50000 #define DSA_MAX_TRIES_PRIME_P 500 #define DSA_TRY_FAIL 0x42 #define DSA_NOT_PRIME 0x43 #define DSA_PRIME_TOO_SMALL 0x44 struct dsa_hash { unsigned int op; /* CAAM Hash operation code */ size_t size; /* Hash digest size */ }; /* * Build the descriptor generating a DSA prime Q * Referring to FIPS.186-4, Section A.1.1.2 Generation of the * Probable Primes p and q Using an Approved Hash Function * * @desc [out] Descriptor built * @seed [out] Resulting seed used to generate prime * @prime [in/out] Prime generation data * @hash_func Selected Hash function */ static void do_desc_prime_q(uint32_t *desc, struct caambuf *seed, struct prime_data_dsa *prime, struct dsa_hash *hash_func) { unsigned int desclen = 0; unsigned int retry_new_mr_failed = 0; unsigned int retry_mr_test = 0; caam_desc_init(desc); caam_desc_add_word(desc, DESC_HEADER(0)); /* Set the PKHA N and A register size */ caam_desc_add_word(desc, LD_IMM(CLASS_1, REG_PKHA_N_SIZE, 4)); caam_desc_add_word(desc, prime->q->length); caam_desc_add_word(desc, LD_IMM(CLASS_1, REG_PKHA_A_SIZE, 4)); caam_desc_add_word(desc, prime->q->length); caam_desc_add_word(desc, MATH(ADD, ZERO, IMM_DATA, VSOL, 4)); caam_desc_add_word(desc, DSA_MAX_TRIES_PRIME_Q); caam_desc_add_word(desc, MATHI_OP1(SHIFT_L, ONE, 63, REG2, 8)); retry_new_mr_failed = caam_desc_get_len(desc); /* Decrement the number of try */ caam_desc_add_word(desc, MATH(SUB, VSOL, ONE, VSOL, 4)); /* Exceed retry count - exit with DSA_TRY_FAIL error */ caam_desc_add_word(desc, HALT_USER(ALL_COND_TRUE, MATH_N, DSA_TRY_FAIL)); /* Clear Class 2 SHA */ caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_CLEAR_WRITTEN, 4)); caam_desc_add_word(desc, CLR_WR_RST_C2_CHA | CLR_WR_RST_C2_DSZ); /* * Step 5. Generate Random Seed * * Seed Length shall be equal or greater than N (Q prime length) * Seed result push in Message Data */ if (seed->length > 16) { caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO_n_SIZE, 4)); caam_desc_add_word(desc, NFIFO_PAD(BOTH, 0, MSG, RND, 16)); caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO_n_SIZE, 4)); caam_desc_add_word(desc, NFIFO_PAD(BOTH, NFIFO_LC1 | NFIFO_LC2, MSG, RND, seed->length - 16)); } else { caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO_n_SIZE, 4)); caam_desc_add_word(desc, NFIFO_PAD(BOTH, NFIFO_LC1 | NFIFO_LC2, MSG, RND, seed->length)); } caam_desc_add_word(desc, MOVE(C1_ALIGN, OFIFO, 0, seed->length)); caam_desc_add_word(desc, FIFO_ST(MSG_DATA, seed->length)); caam_desc_add_ptr(desc, seed->paddr); /* * Hash the Seed, this is a pseudo U, bits upper N - 1 still present */ caam_desc_add_word(desc, HASH_INITFINAL(hash_func->op)); /* * Step 6. U = hash(seed) mod 2^(N-1) * Step 7. q = 2^(N-1) + U + 1 - (U mod 2) */ /* Trash the bits > N - 1, the hash size is >= N */ caam_desc_add_word(desc, MOVE_WAIT(C2_CTX_REG, MATH_REG0, hash_func->size - prime->q->length, 8)); /* Get the MSB of U and set the bit N-1 */ caam_desc_add_word(desc, MATH(OR, REG2, REG0, REG0, 8)); /* Move the candidate prime q's MSB into IFIFO */ caam_desc_add_word(desc, MOVE_WAIT(MATH_REG0, IFIFO, 0, 8)); /* * Move the candidate prime q's intermediate value into IFIFO */ caam_desc_add_word(desc, MOVE_WAIT(C2_CTX_REG, IFIFO, hash_func->size - prime->q->length + 8, prime->q->length - 16)); /* Get the LSB of U and set the bit 0 */ caam_desc_add_word(desc, MOVE_WAIT(C2_CTX_REG, MATH_REG0, hash_func->size - 8, 8)); caam_desc_add_word(desc, MATH(OR, ONE, REG0, REG0, 8)); /* Move the candidate prime q's LSB into IFIFO */ caam_desc_add_word(desc, MOVE_WAIT(MATH_REG0, IFIFO, 0, 8)); /* Move the IFIFO in to PKHA N */ caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8)); caam_desc_add_word(desc, NFIFO_NOPAD(C1, NFIFO_FC1, IFIFO, PKHA_N, 0)); caam_desc_add_word(desc, prime->q->length); /* Store the Prime q here because Miller-Rabin test affect PKHA N */ caam_desc_add_word(desc, FIFO_ST(PKHA_N, prime->q->length)); caam_desc_add_ptr(desc, prime->q->paddr); /* * Step 8. Test q prime with 'miller-rabin' test * * Load the number of Miller-Rabin test iteration */ caam_desc_add_word(desc, MATH(ADD, IMM_DATA, ZERO, SIL, 4)); if (prime->p->length <= 1024 / 8) caam_desc_add_word(desc, 40); else if (prime->p->length >= 3072 / 8) caam_desc_add_word(desc, 64); else caam_desc_add_word(desc, 56); retry_mr_test = caam_desc_get_len(desc); /* Generate 8 random bytes 'miller-rabin seed' */ caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8)); caam_desc_add_word(desc, NFIFO_PAD(C1, NFIFO_FC1, PKHA_A, RND, 0)); caam_desc_add_word(desc, prime->q->length); caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1)); caam_desc_add_word(desc, 0x01); caam_desc_add_word(desc, PKHA_OP(MR_PRIMER_TEST, B)); desclen = caam_desc_get_len(desc); /* * Step 9. If q is not q prime back to step 5 */ caam_desc_add_word(desc, JUMP_CNO_LOCAL(ANY_COND_FALSE, JMP_COND(PKHA_IS_PRIME), retry_new_mr_failed - desclen)); caam_desc_add_word(desc, MATH(SUB, SIL, ONE, SIL, 4)); desclen = caam_desc_get_len(desc); /* Test while number of MR test iteration not complete */ caam_desc_add_word(desc, JUMP_CNO_LOCAL(ALL_COND_FALSE, JMP_COND(MATH_N) | JMP_COND(MATH_Z), retry_mr_test - desclen)); DSA_TRACE("Prime Q descriptor"); DSA_DUMPDESC(desc); } /* * Build the descriptor generating the intermediate value X (step 11.3) * Referring to FIPS.186-4, Section A.1.1.2 Generation of the * Probable Primes p and q Using an Approved Hash Function * * @desc [out] Descriptor built * @x [out] Value X * @seed [in/out] Seed to hash and next seed for next loop * @prime [in/out] Prime generation data * @hash_func Selected Hash function * @mod_n Modular value (0xFF filled buffer) * @desc_p Physical address of the descriptor doing Prime P */ static void 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) { unsigned int desclen = 0; unsigned int loop_n = 0; size_t n = 0; size_t b = 0; size_t b_offset = 0; /* * Step 3. n = ceil(L / outlen) - 1 * where outlen is the hash size in bits * * Note build descriptor with n = ceil(L / outlen) to * pre-calculate seed for next run. */ n = (prime->p->length + hash_func->size) * 8 - 1; n /= hash_func->size * 8; /* * Step 4. b = L - 1 - (n * outlen) * * Note b determine the number of bits to keep in the last * Vn computed. * Calculate b_offset which is the offset in bytes to remove from * the calculated hash */ b = prime->p->length * 8 - 1 - (n - 1) * hash_func->size * 8; DSA_TRACE("Prime p => n = %zu | b = %zu", n - 1, b); b_offset = hash_func->size - (b + 1) / 8; DSA_TRACE("Vn offset is %zu", b_offset); caam_desc_init(desc); caam_desc_add_word(desc, DESC_HEADER(0)); caam_desc_add_word(desc, SEQ_OUT_PTR(x->length)); caam_desc_add_ptr(desc, x->paddr); caam_desc_add_word(desc, MATHI_OP1(SHIFT_L, ONE, 63, REG2, 8)); caam_desc_add_word(desc, MATH(ADD, ZERO, IMM_DATA, REG0, 4)); caam_desc_add_word(desc, n); caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_N, NOACTION, seed->length)); caam_desc_add_ptr(desc, mod_n->paddr); /* * Because the Sequence Out Pointer is incremental store, we need * to build w number in reverse. * * Hence, calculate the last seed number of the loop and save it. * Step 11.9 is automatically done here by incrementing seed number. */ caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1)); caam_desc_add_word(desc, n); caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, seed->length)); caam_desc_add_ptr(desc, seed->paddr); caam_desc_add_word(desc, PKHA_OP(MOD_ADD_A_B, A)); caam_desc_add_word(desc, FIFO_ST(PKHA_A, seed->length)); caam_desc_add_ptr(desc, seed->paddr); caam_desc_add_word(desc, PKHA_CPY_NSIZE(A0, B1)); caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1)); caam_desc_add_word(desc, 1); caam_desc_add_word(desc, WAIT_COND(ALL_COND_TRUE, NIFP)); /* * Step 11.1 * For j = 0 to n do * Vj = hash((seed + offset + j) mod 2^seedlen * Step 11.2 * W = V0 + (V1 * 2^outlen) + ... + * (Vn-1 * 2^((n-1)*outlen)) + * ((Vn mod 2^b) * 2^(n*outlen)) */ loop_n = caam_desc_get_len(desc); caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_CLEAR_WRITTEN, 4)); caam_desc_add_word(desc, CLR_WR_IFIFO_NFIFO | CLR_WR_RST_C2_CHA | CLR_WR_RST_C2_DSZ); caam_desc_add_word(desc, HASH_INITFINAL(hash_func->op)); caam_desc_add_word(desc, LD_NOCLASS_IMM(REG_CHA_CTRL, 4)); caam_desc_add_word(desc, CCTRL_ULOAD_PKHA_A); caam_desc_add_word(desc, MOVE_WAIT(OFIFO, IFIFO_C2_LC2, 0, seed->length)); /* If Math Register 2 is zero bypass the high bit set to one */ caam_desc_add_word(desc, MATH(SUB, REG2, ONE, NODEST, 8)); caam_desc_add_word(desc, JUMP_CNO_LOCAL(ANY_COND_TRUE, JMP_COND(MATH_N) | JMP_COND(MATH_Z), 8)); /* * Step 11.3 * X = W + 2^(L-1) * * Set the high bit to one * Remark: the DSA key is a modulus 8 bytes, hence no need * to check if the b_offset is less than 8. */ caam_desc_add_word(desc, MOVE_WAIT(C2_CTX_REG, MATH_REG1, b_offset, 8)); caam_desc_add_word(desc, MATH(OR, REG2, REG1, REG1, 8)); caam_desc_add_word(desc, MOVE(MATH_REG1, OFIFO, 0, 8)); if (hash_func->size - b_offset > 8) caam_desc_add_word(desc, MOVE_WAIT(C2_CTX_REG, OFIFO, b_offset + 8, hash_func->size - b_offset - 8)); caam_desc_add_word(desc, FIFO_ST_SEQ(MSG_DATA, hash_func->size - b_offset)); /* * Reset MATH Register 2 to bypass the High Bit set * operation next loop */ caam_desc_add_word(desc, MATH(AND, REG2, ZERO, REG2, 8)); caam_desc_add_word(desc, JUMP_CNO_LOCAL(ALL_COND_TRUE, JMP_COND(NONE), 2)); /* Bypass High Bit set */ caam_desc_add_word(desc, ST_NOIMM_SEQ(CLASS_2, REG_CTX, hash_func->size)); caam_desc_add_word(desc, PKHA_CPY_NSIZE(B1, A0)); caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, A)); caam_desc_add_word(desc, PKHA_CPY_NSIZE(A0, B1)); desclen = caam_desc_get_len(desc); caam_desc_add_word(desc, JUMP_CNO_LOCAL_DEC(ALL_COND_FALSE, MATH_0, JMP_COND_MATH(N) | JMP_COND_MATH(Z), loop_n - desclen)); /* Jump to the next descriptor desc */ caam_desc_add_word(desc, JUMP_NOTLOCAL(CLASS_NO, ALL_COND_TRUE, JMP_COND(NONE))); caam_desc_add_ptr(desc, desc_p); DSA_TRACE("X descriptor"); DSA_DUMPDESC(desc); } /* * Build the descriptor generating the Prime P from value X * Referring to FIPS.186-4, Section A.1.1.2 Generation of the * Probable Primes p and q Using an Approved Hash Function * * @desc [out] Descriptor built * @prime [in/out] Prime generation data * @x Value X * @mod_n Modular value (0xFF filled buffer) */ static void do_desc_prime_p(uint32_t *desc, struct prime_data_dsa *prime, struct caambuf *x, struct caambuf *mod_n) { unsigned int desclen = 0; unsigned int retry_mr_test = 0; size_t index = 0; caam_desc_init(desc); caam_desc_add_word(desc, DESC_HEADER(0)); caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_N, NOACTION, mod_n->length)); caam_desc_add_ptr(desc, mod_n->paddr); /* * Step 11.4 * c = X mod 2q */ /* Calculate 2q and store it in PKHA N */ caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, prime->q->length)); caam_desc_add_ptr(desc, prime->q->paddr); caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, B0)); caam_desc_add_word(desc, PKHA_OP(MOD_ADD_A_B, A)); caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, N0)); /* c = X mod 2q */ caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, x->length)); caam_desc_add_ptr(desc, x->paddr); caam_desc_add_word(desc, JUMP_CNO_LOCAL(ALL_COND_TRUE, JMP_COND(NIFP), 1) | BIT(24)); caam_desc_add_word(desc, PKHA_OP(MOD_AMODN, A)); /* * Step 11.5 * p = X - (c - 1) */ caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_N, NOACTION, mod_n->length)); caam_desc_add_ptr(desc, mod_n->paddr); caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1)); caam_desc_add_ptr(desc, 1); caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, B)); caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, x->length)); caam_desc_add_ptr(desc, x->paddr); caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, A)); /* * Save the candidate Prime q now because N is going to be * affected by the Miller-Rabin test */ caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, N0)); caam_desc_add_word(desc, FIFO_ST(PKHA_N, prime->p->length)); caam_desc_add_ptr(desc, prime->p->paddr); caam_desc_add_word(desc, FIFO_ST_SEQ(MSG_DATA, 0)); /* * Step 11.6 * if (p < 2^(L-1)) then go to step 11.9 * */ caam_desc_add_word(desc, LD_NOCLASS_IMM(REG_CHA_CTRL, 4)); caam_desc_add_word(desc, CCTRL_ULOAD_PKHA_A); /* Keep the MSB from p candidate and check if bit 2^(L-1) is set */ caam_desc_add_word(desc, MOVE_WAIT(OFIFO, MATH_REG0, 0, 8)); for (index = 1; index < prime->p->length / 128; index++) caam_desc_add_word(desc, MOVE(OFIFO, C1_CTX_REG, 0, 128)); caam_desc_add_word(desc, MOVE(OFIFO, C1_CTX_REG, 0, 124)); caam_desc_add_word(desc, MATHI_OP1(SHIFT_L, ONE, 63, REG2, 8)); caam_desc_add_word(desc, MATH(AND, REG0, REG2, REG0, 8)); caam_desc_add_word(desc, HALT_USER(ALL_COND_TRUE, MATH_Z, DSA_PRIME_TOO_SMALL)); /* * Step 11.7 * Test whether or not p is prime * * Referring to FIPS.186-4, Table C.1 * Get the number Miller-Rabin test interation function * of the prime number size */ caam_desc_add_word(desc, MATH(ADD, IMM_DATA, ZERO, REG0, 4)); if (prime->p->length <= 1024 / 8) caam_desc_add_word(desc, 40); else if (prime->p->length >= 3072 / 8) caam_desc_add_word(desc, 64); else caam_desc_add_word(desc, 56); retry_mr_test = caam_desc_get_len(desc); /* Generate 8 random bytes 'miller-rabin seed' */ caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8)); caam_desc_add_word(desc, NFIFO_PAD(C1, NFIFO_FC1, PKHA_A, RND, 0)); caam_desc_add_word(desc, prime->p->length); caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1)); caam_desc_add_word(desc, 0x01); caam_desc_add_word(desc, PKHA_OP(MR_PRIMER_TEST, B)); desclen = caam_desc_get_len(desc); /* * Step 11.8 * if p is not a prime continue to step 11.9 */ caam_desc_add_word(desc, HALT_USER(ALL_COND_FALSE, PKHA_IS_PRIME, DSA_NOT_PRIME)); desclen = caam_desc_get_len(desc); /* Test while number of MR test iteration not complete */ caam_desc_add_word(desc, JUMP_CNO_LOCAL_DEC(ALL_COND_FALSE, MATH_0, JMP_COND_MATH(N) | JMP_COND_MATH(Z), retry_mr_test - desclen)); DSA_TRACE("Prime P descriptor"); DSA_DUMPDESC(desc); /* * Ensure descriptor is pushed in physical memory because it's * called from another descriptor. */ cache_operation(TEE_CACHECLEAN, desc, DESC_SZBYTES(PRIME_DESC_ENTRIES)); } /* * Run the Prime Q descriptor. * * @desc Descriptor built */ static enum caam_status run_prime_q(uint32_t *desc, struct prime_data_dsa *prime) { enum caam_status retstatus = CAAM_FAILURE; struct caam_jobctx jobctx = { }; cache_operation(TEE_CACHEFLUSH, prime->q->data, prime->q->length); jobctx.desc = desc; retstatus = caam_jr_enqueue(&jobctx, NULL); if (retstatus != CAAM_NO_ERROR) { DSA_TRACE("Prime Q Status 0x%08" PRIx32 " ret 0x%08" PRIx32, jobctx.status, retstatus); retstatus = CAAM_FAILURE; } else { cache_operation(TEE_CACHEINVALIDATE, prime->q->data, prime->q->length); DSA_DUMPBUF("Prime Q", prime->q->data, prime->q->length); } return retstatus; } /* * Run the Prime P descriptors. * * @desc Descriptor built * @prime Prime generation data */ static enum caam_status run_prime_p(uint32_t *desc, struct prime_data_dsa *prime) { enum caam_status retstatus = CAAM_FAILURE; struct caam_jobctx jobctx = { }; size_t counter = 0; cache_operation(TEE_CACHEFLUSH, prime->p->data, prime->p->length); jobctx.desc = desc; for (counter = 0; counter < 4 * prime->p->length * 8; counter++) { retstatus = caam_jr_enqueue(&jobctx, NULL); if (retstatus == CAAM_NO_ERROR) { DSA_TRACE("Prime P try: counter=%zu", counter); cache_operation(TEE_CACHEINVALIDATE, prime->p->data, prime->p->length); DSA_DUMPBUF("Prime P", prime->p->data, prime->p->length); return retstatus; } if (retstatus == CAAM_JOB_STATUS) { if (JRSTA_GET_HALT_USER(jobctx.status) != DSA_NOT_PRIME && JRSTA_GET_HALT_USER(jobctx.status) != DSA_PRIME_TOO_SMALL) { DSA_TRACE("Prime P status 0x%08" PRIx32, jobctx.status); return CAAM_FAILURE; } } } /* This is not a prime, will try with another prime q */ return CAAM_BAD_PARAM; } /* * Generate the DSA parameter G (generator) * Referring to FIPS.186-4, Section A.2.1 Unverifiable Generation of the * Generator g * * @desc Descriptor buffer to use * @prime [in/out] Prime generation data * @mod_n Modular value (0xFF filled buffer) */ static enum caam_status do_generator(uint32_t *desc, struct prime_data_dsa *prime, struct caambuf *mod_n) { enum caam_status retstatus = CAAM_FAILURE; struct caam_jobctx jobctx = { }; unsigned int desclen = 0; unsigned int retry_new_h = 0; caam_desc_init(desc); caam_desc_add_word(desc, DESC_HEADER(0)); caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_N, NOACTION, mod_n->length)); caam_desc_add_ptr(desc, mod_n->paddr); /* * Step 1. * e = (p - 1)/q */ caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, prime->p->length)); caam_desc_add_ptr(desc, prime->p->paddr); caam_desc_add_word(desc, FIFO_LD_IMM(CLASS_1, PKHA_B, NOACTION, 1)); caam_desc_add_ptr(desc, 1); /* PKHA B = (p - 1) */ caam_desc_add_word(desc, PKHA_OP(MOD_SUB_A_B, B)); caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_A, NOACTION, prime->q->length)); caam_desc_add_ptr(desc, prime->q->paddr); /* PKHA A = 1/q */ caam_desc_add_word(desc, PKHA_OP(MOD_INV_A, A)); /* PKHA E = (p - 1)/q */ caam_desc_add_word(desc, PKHA_OP(MOD_MUL_A_B, A)); caam_desc_add_word(desc, PKHA_CPY_SSIZE(A0, E)); /* Load N with prime p */ caam_desc_add_word(desc, FIFO_LD(CLASS_1, PKHA_N, NOACTION, prime->p->length)); caam_desc_add_ptr(desc, prime->p->paddr); /* * Step 2. Generate a Random h * where 1 < h < (p - 1) * * To ensure h < (p - 1), generate a random of p length - 2 */ retry_new_h = caam_desc_get_len(desc); caam_desc_add_word(desc, LD_IMM(CLASS_NO, REG_NFIFO, 8)); caam_desc_add_word(desc, NFIFO_PAD(C1, NFIFO_FC1, PKHA_A, RND, 0)); caam_desc_add_word(desc, prime->p->length - 2); /* * Step 3. * g = h^e mod p */ caam_desc_add_word(desc, PKHA_OP(MOD_EXP_A_E, A)); /* * Step 4. * if (g = 1) then go to step 2 */ desclen = caam_desc_get_len(desc); caam_desc_add_word(desc, JUMP_CNO_LOCAL(ALL_COND_TRUE, JMP_COND(PKHA_GCD_1), retry_new_h - desclen)); /* g is good save it */ caam_desc_add_word(desc, FIFO_ST(PKHA_A, prime->g->length)); caam_desc_add_ptr(desc, prime->g->paddr); DSA_DUMPDESC(desc); cache_operation(TEE_CACHEFLUSH, prime->g->data, prime->g->length); jobctx.desc = desc; retstatus = caam_jr_enqueue(&jobctx, NULL); if (retstatus != CAAM_NO_ERROR) { DSA_TRACE("Generator G Status 0x%08" PRIx32 " ret 0x%08" PRIx32, jobctx.status, retstatus); return CAAM_FAILURE; } cache_operation(TEE_CACHEINVALIDATE, prime->g->data, prime->g->length); DSA_DUMPBUF("Generator G", prime->g->data, prime->g->length); return CAAM_NO_ERROR; } enum caam_status caam_prime_dsa_gen(struct prime_data_dsa *data) { enum caam_status retstatus = CAAM_FAILURE; uint32_t *desc_all = NULL; uint32_t *desc_q = NULL; uint32_t *desc_x = NULL; uint32_t *desc_p = NULL; struct caambuf seed = { }; struct caambuf mod_n = { }; struct dsa_hash hash_func = { OP_ALGO(SHA256), TEE_SHA256_HASH_SIZE }; size_t nb_tries = 0; struct caambuf x = { }; /* * For the now as the DSA Prime p size is limited to 3072, Prime q * is also limited to 256. Hence the hash function to use is * SHA-256. * Ensure here that limit is not crossed because on some i.MX device * hash is limited to 256. */ if (data->q->length > 256) return CAAM_BAD_PARAM; retstatus = caam_calloc_buf(&mod_n, data->p->length); if (retstatus != CAAM_NO_ERROR) goto out; memset(mod_n.data, 0xFF, mod_n.length); cache_operation(TEE_CACHECLEAN, mod_n.data, mod_n.length); retstatus = caam_calloc_align_buf(&seed, data->q->length); if (retstatus != CAAM_NO_ERROR) return retstatus; retstatus = caam_calloc_buf(&x, data->p->length); if (retstatus != CAAM_NO_ERROR) return retstatus; desc_all = caam_calloc_desc(PRIME_DESC_ENTRIES * 3); if (!desc_all) { retstatus = CAAM_OUT_MEMORY; goto out; } DSA_TRACE("Do primes P %zu bytes, Q %zu bytes", data->p->length, data->q->length); desc_q = desc_all; desc_x = desc_q + PRIME_DESC_ENTRIES; desc_p = desc_x + PRIME_DESC_ENTRIES; do_desc_prime_q(desc_q, &seed, data, &hash_func); do_desc_gen_x(desc_x, &x, &seed, data, &hash_func, &mod_n, virt_to_phys(desc_p)); do_desc_prime_p(desc_p, data, &x, &mod_n); cache_operation(TEE_CACHEFLUSH, data->p->data, data->p->length); cache_operation(TEE_CACHEFLUSH, seed.data, seed.length); cache_operation(TEE_CACHEFLUSH, x.data, x.length); for (nb_tries = DSA_MAX_TRIES_PRIME_P; nb_tries > 0; nb_tries--) { retstatus = run_prime_q(desc_q, data); if (retstatus == CAAM_NO_ERROR) { retstatus = run_prime_p(desc_x, data); if (retstatus == CAAM_NO_ERROR) break; } if (retstatus == CAAM_FAILURE) { DSA_TRACE("DSA Prime P/Q Generation failed"); break; } } if (retstatus == CAAM_NO_ERROR) retstatus = do_generator(desc_all, data, &mod_n); out: caam_free_desc(&desc_all); caam_free_buf(&seed); caam_free_buf(&x); caam_free_buf(&mod_n); return retstatus; }