diff options
Diffstat (limited to 'core/lib/libtomcrypt/dsa.c')
-rw-r--r-- | core/lib/libtomcrypt/dsa.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/core/lib/libtomcrypt/dsa.c b/core/lib/libtomcrypt/dsa.c new file mode 100644 index 00000000..3fa6301c --- /dev/null +++ b/core/lib/libtomcrypt/dsa.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2014-2019, Linaro Limited + */ + +#include <crypto/crypto.h> +#include <stdlib.h> +#include <string.h> +#include <tee_api_types.h> +#include <tee/tee_cryp_utl.h> +#include <tomcrypt.h> +#include <trace.h> +#include <utee_defines.h> + +#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) +{ + TEE_Result res; + dsa_key ltc_tmp_key; + size_t group_size, modulus_size = key_size/8; + int ltc_res; + + if (modulus_size <= 128) + group_size = 20; + else if (modulus_size <= 256) + group_size = 30; + else if (modulus_size <= 384) + group_size = 35; + else + group_size = 40; + + /* Generate the DSA key */ + ltc_res = dsa_make_key(NULL, find_prng("prng_mpa"), group_size, + modulus_size, <c_tmp_key); + if (ltc_res != CRYPT_OK) { + res = TEE_ERROR_BAD_PARAMETERS; + } else if ((size_t)mp_count_bits(ltc_tmp_key.p) != key_size) { + dsa_free(<c_tmp_key); + res = TEE_ERROR_BAD_PARAMETERS; + } else { + /* Copy the key */ + ltc_mp.copy(ltc_tmp_key.g, key->g); + ltc_mp.copy(ltc_tmp_key.p, key->p); + ltc_mp.copy(ltc_tmp_key.q, key->q); + ltc_mp.copy(ltc_tmp_key.y, key->y); + ltc_mp.copy(ltc_tmp_key.x, key->x); + + /* Free the tempory key */ + dsa_free(<c_tmp_key); + res = TEE_SUCCESS; + } + return res; +} + +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->g), + .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_hash_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_mpa"), <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->g), + .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; +} |