// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (c) 2014-2019, Linaro Limited */ #include #include #include #include #include #include #include #include "acipher_helpers.h" TEE_Result crypto_acipher_alloc_dsa_keypair(struct dsa_keypair *s, size_t key_size_bits __unused) { memset(s, 0, sizeof(*s)); if (!bn_alloc_max(&s->g)) return TEE_ERROR_OUT_OF_MEMORY; if (!bn_alloc_max(&s->p)) goto err; if (!bn_alloc_max(&s->q)) goto err; if (!bn_alloc_max(&s->y)) goto err; if (!bn_alloc_max(&s->x)) goto err; return TEE_SUCCESS; err: crypto_bignum_free(s->g); crypto_bignum_free(s->p); crypto_bignum_free(s->q); crypto_bignum_free(s->y); return TEE_ERROR_OUT_OF_MEMORY; } TEE_Result crypto_acipher_alloc_dsa_public_key(struct dsa_public_key *s, size_t key_size_bits __unused) { memset(s, 0, sizeof(*s)); if (!bn_alloc_max(&s->g)) return TEE_ERROR_OUT_OF_MEMORY; if (!bn_alloc_max(&s->p)) goto err; if (!bn_alloc_max(&s->q)) goto err; if (!bn_alloc_max(&s->y)) goto err; return TEE_SUCCESS; err: crypto_bignum_free(s->g); crypto_bignum_free(s->p); crypto_bignum_free(s->q); return TEE_ERROR_OUT_OF_MEMORY; } TEE_Result crypto_acipher_gen_dsa_key(struct dsa_keypair *key, size_t key_size) { dsa_key ltc_tmp_key = { }; int ltc_res = 0; if (key_size != 8 * mp_unsigned_bin_size(key->p)) return TEE_ERROR_BAD_PARAMETERS; ltc_res = mp_init_multi(<c_tmp_key.g, <c_tmp_key.p, <c_tmp_key.q, <c_tmp_key.x, <c_tmp_key.y, NULL); if (ltc_res) return TEE_ERROR_OUT_OF_MEMORY; /* Copy the key parameters */ mp_copy(key->g, ltc_tmp_key.g); mp_copy(key->p, ltc_tmp_key.p); mp_copy(key->q, ltc_tmp_key.q); /* Generate the DSA key */ ltc_res = dsa_generate_key(NULL, find_prng("prng_crypto"), <c_tmp_key); if (ltc_res) return TEE_ERROR_BAD_PARAMETERS; /* Copy the key */ mp_copy(ltc_tmp_key.y, key->y); mp_copy(ltc_tmp_key.x, key->x); /* Free the temporary key */ dsa_free(<c_tmp_key); return TEE_SUCCESS; } TEE_Result crypto_acipher_dsa_sign(uint32_t algo, struct dsa_keypair *key, const uint8_t *msg, size_t msg_len, uint8_t *sig, size_t *sig_len) { TEE_Result res; size_t hash_size; int ltc_res; void *r, *s; dsa_key ltc_key = { .type = PK_PRIVATE, .qord = mp_unsigned_bin_size(key->q), .g = key->g, .p = key->p, .q = key->q, .y = key->y, .x = key->x, }; if (algo != TEE_ALG_DSA_SHA1 && algo != TEE_ALG_DSA_SHA224 && algo != TEE_ALG_DSA_SHA256) { res = TEE_ERROR_NOT_IMPLEMENTED; goto err; } res = tee_alg_get_digest_size(TEE_DIGEST_HASH_TO_ALGO(algo), &hash_size); if (res != TEE_SUCCESS) goto err; if (mp_unsigned_bin_size(ltc_key.q) < hash_size) hash_size = mp_unsigned_bin_size(ltc_key.q); if (msg_len != hash_size) { res = TEE_ERROR_SECURITY; goto err; } if (*sig_len < 2 * mp_unsigned_bin_size(ltc_key.q)) { *sig_len = 2 * mp_unsigned_bin_size(ltc_key.q); res = TEE_ERROR_SHORT_BUFFER; goto err; } ltc_res = mp_init_multi(&r, &s, NULL); if (ltc_res != CRYPT_OK) { res = TEE_ERROR_OUT_OF_MEMORY; goto err; } ltc_res = dsa_sign_hash_raw(msg, msg_len, r, s, NULL, find_prng("prng_crypto"), <c_key); if (ltc_res == CRYPT_OK) { *sig_len = 2 * mp_unsigned_bin_size(ltc_key.q); memset(sig, 0, *sig_len); mp_to_unsigned_bin(r, (uint8_t *)sig + *sig_len/2 - mp_unsigned_bin_size(r)); mp_to_unsigned_bin(s, (uint8_t *)sig + *sig_len - mp_unsigned_bin_size(s)); res = TEE_SUCCESS; } else { res = TEE_ERROR_GENERIC; } mp_clear_multi(r, s, NULL); err: return res; } TEE_Result crypto_acipher_dsa_verify(uint32_t algo, struct dsa_public_key *key, const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len) { TEE_Result res; int ltc_stat, ltc_res; void *r, *s; dsa_key ltc_key = { .type = PK_PUBLIC, .qord = mp_unsigned_bin_size(key->q), .g = key->g, .p = key->p, .q = key->q, .y = key->y }; if (algo != TEE_ALG_DSA_SHA1 && algo != TEE_ALG_DSA_SHA224 && algo != TEE_ALG_DSA_SHA256) { res = TEE_ERROR_NOT_IMPLEMENTED; goto err; } ltc_res = mp_init_multi(&r, &s, NULL); if (ltc_res != CRYPT_OK) { res = TEE_ERROR_OUT_OF_MEMORY; goto err; } mp_read_unsigned_bin(r, (uint8_t *)sig, sig_len/2); mp_read_unsigned_bin(s, (uint8_t *)sig + sig_len/2, sig_len/2); ltc_res = dsa_verify_hash_raw(r, s, msg, msg_len, <c_stat, <c_key); mp_clear_multi(r, s, NULL); res = convert_ltc_verify_status(ltc_res, ltc_stat); err: return res; }