blob: 3c0425860b9fdab6a98f90bf71644fa83941d881 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (C) 2018, ARM Limited
* Copyright (C) 2019, Linaro Limited
*/
#include <assert.h>
#include <compiler.h>
#include <crypto/crypto.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdh.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/ecp.h>
#include <mbedtls/entropy.h>
#include <mbedtls/pk.h>
#include <stdlib.h>
#include <string.h>
#include "mbd_rand.h"
/* Translate mbedtls result to TEE result */
static TEE_Result get_tee_result(int lmd_res)
{
switch (lmd_res) {
case 0:
return TEE_SUCCESS;
case MBEDTLS_ERR_ECP_VERIFY_FAILED:
return TEE_ERROR_SIGNATURE_INVALID;
case MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL:
return TEE_ERROR_SHORT_BUFFER;
default:
return TEE_ERROR_BAD_STATE;
}
}
TEE_Result crypto_acipher_alloc_ecc_keypair(struct ecc_keypair *s,
size_t key_size_bits)
{
memset(s, 0, sizeof(*s));
s->d = crypto_bignum_allocate(key_size_bits);
if (!s->d)
goto err;
s->x = crypto_bignum_allocate(key_size_bits);
if (!s->x)
goto err;
s->y = crypto_bignum_allocate(key_size_bits);
if (!s->y)
goto err;
return TEE_SUCCESS;
err:
crypto_bignum_free(s->d);
crypto_bignum_free(s->x);
return TEE_ERROR_OUT_OF_MEMORY;
}
TEE_Result crypto_acipher_alloc_ecc_public_key(struct ecc_public_key *s,
size_t key_size_bits)
{
memset(s, 0, sizeof(*s));
s->x = crypto_bignum_allocate(key_size_bits);
if (!s->x)
goto err;
s->y = crypto_bignum_allocate(key_size_bits);
if (!s->y)
goto err;
return TEE_SUCCESS;
err:
crypto_bignum_free(s->x);
return TEE_ERROR_OUT_OF_MEMORY;
}
void crypto_acipher_free_ecc_public_key(struct ecc_public_key *s)
{
if (!s)
return;
crypto_bignum_free(s->x);
crypto_bignum_free(s->y);
}
/*
* curve is part of TEE_ECC_CURVE_NIST_P192,...
* algo is part of TEE_ALG_ECDSA_P192,..., and 0 if we do not have it
*/
static TEE_Result ecc_get_keysize(uint32_t curve, uint32_t algo,
size_t *key_size_bytes, size_t *key_size_bits)
{
/*
* Note GPv1.1 indicates TEE_ALG_ECDH_NIST_P192_DERIVE_SHARED_SECRET
* but defines TEE_ALG_ECDH_P192
*/
switch (curve) {
case TEE_ECC_CURVE_NIST_P192:
*key_size_bits = 192;
*key_size_bytes = 24;
if ((algo != 0) && (algo != TEE_ALG_ECDSA_P192) &&
(algo != TEE_ALG_ECDH_P192))
return TEE_ERROR_BAD_PARAMETERS;
break;
case TEE_ECC_CURVE_NIST_P224:
*key_size_bits = 224;
*key_size_bytes = 28;
if ((algo != 0) && (algo != TEE_ALG_ECDSA_P224) &&
(algo != TEE_ALG_ECDH_P224))
return TEE_ERROR_BAD_PARAMETERS;
break;
case TEE_ECC_CURVE_NIST_P256:
*key_size_bits = 256;
*key_size_bytes = 32;
if ((algo != 0) && (algo != TEE_ALG_ECDSA_P256) &&
(algo != TEE_ALG_ECDH_P256))
return TEE_ERROR_BAD_PARAMETERS;
break;
case TEE_ECC_CURVE_NIST_P384:
*key_size_bits = 384;
*key_size_bytes = 48;
if ((algo != 0) && (algo != TEE_ALG_ECDSA_P384) &&
(algo != TEE_ALG_ECDH_P384))
return TEE_ERROR_BAD_PARAMETERS;
break;
case TEE_ECC_CURVE_NIST_P521:
*key_size_bits = 521;
*key_size_bytes = 66;
if ((algo != 0) && (algo != TEE_ALG_ECDSA_P521) &&
(algo != TEE_ALG_ECDH_P521))
return TEE_ERROR_BAD_PARAMETERS;
break;
default:
*key_size_bits = 0;
*key_size_bytes = 0;
return TEE_ERROR_NOT_SUPPORTED;
}
return TEE_SUCCESS;
}
/*
* Clear some memory that was used to prepare the context
*/
static void ecc_clear_precomputed(mbedtls_ecp_group *grp)
{
size_t i = 0;
if (grp->T) {
for (i = 0; i < grp->T_size; i++)
mbedtls_ecp_point_free(&grp->T[i]);
free(grp->T);
}
grp->T = NULL;
grp->T_size = 0;
}
TEE_Result crypto_acipher_gen_ecc_key(struct ecc_keypair *key)
{
TEE_Result res = TEE_SUCCESS;
int lmd_res = 0;
mbedtls_ecdsa_context ecdsa;
size_t key_size_bytes = 0;
size_t key_size_bits = 0;
memset(&ecdsa, 0, sizeof(ecdsa));
res = ecc_get_keysize(key->curve, 0, &key_size_bytes, &key_size_bits);
if (res != TEE_SUCCESS)
return res;
mbedtls_ecdsa_init(&ecdsa);
/* Generate the ECC key */
lmd_res = mbedtls_ecdsa_genkey(&ecdsa, key->curve, mbd_rand, NULL);
if (lmd_res != 0) {
res = TEE_ERROR_BAD_PARAMETERS;
FMSG("mbedtls_ecdsa_genkey failed.");
goto exit;
}
ecc_clear_precomputed(&ecdsa.grp);
/* check the size of the keys */
if ((mbedtls_mpi_bitlen(&ecdsa.Q.X) > key_size_bits) ||
(mbedtls_mpi_bitlen(&ecdsa.Q.Y) > key_size_bits) ||
(mbedtls_mpi_bitlen(&ecdsa.d) > key_size_bits)) {
res = TEE_ERROR_BAD_PARAMETERS;
FMSG("Check the size of the keys failed.");
goto exit;
}
/* check LMD is returning z==1 */
if (mbedtls_mpi_bitlen(&ecdsa.Q.Z) != 1) {
res = TEE_ERROR_BAD_PARAMETERS;
FMSG("Check LMD failed.");
goto exit;
}
/* Copy the key */
crypto_bignum_copy(key->d, (void *)&ecdsa.d);
crypto_bignum_copy(key->x, (void *)&ecdsa.Q.X);
crypto_bignum_copy(key->y, (void *)&ecdsa.Q.Y);
res = TEE_SUCCESS;
exit:
mbedtls_ecdsa_free(&ecdsa); /* Free the temporary key */
return res;
}
TEE_Result crypto_acipher_ecc_sign(uint32_t algo, struct ecc_keypair *key,
const uint8_t *msg, size_t msg_len,
uint8_t *sig, size_t *sig_len)
{
TEE_Result res = TEE_SUCCESS;
int lmd_res = 0;
const mbedtls_pk_info_t *pk_info = NULL;
mbedtls_ecdsa_context ecdsa;
size_t key_size_bytes = 0;
size_t key_size_bits = 0;
mbedtls_mpi r;
mbedtls_mpi s;
memset(&ecdsa, 0, sizeof(ecdsa));
memset(&r, 0, sizeof(r));
memset(&s, 0, sizeof(s));
if (algo == 0)
return TEE_ERROR_BAD_PARAMETERS;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
mbedtls_ecdsa_init(&ecdsa);
lmd_res = mbedtls_ecp_group_load(&ecdsa.grp, key->curve);
if (lmd_res != 0) {
res = TEE_ERROR_NOT_SUPPORTED;
goto out;
}
ecdsa.d = *(mbedtls_mpi *)key->d;
res = ecc_get_keysize(key->curve, algo, &key_size_bytes,
&key_size_bits);
if (res != TEE_SUCCESS)
goto out;
pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECDSA);
if (pk_info == NULL) {
res = TEE_ERROR_NOT_SUPPORTED;
goto out;
}
lmd_res = mbedtls_ecdsa_sign(&ecdsa.grp, &r, &s, &ecdsa.d, msg,
msg_len, mbd_rand, NULL);
if (lmd_res == 0) {
*sig_len = 2 * key_size_bytes;
memset(sig, 0, *sig_len);
mbedtls_mpi_write_binary(&r, sig + *sig_len / 2 -
mbedtls_mpi_size(&r),
mbedtls_mpi_size(&r));
mbedtls_mpi_write_binary(&s, sig + *sig_len -
mbedtls_mpi_size(&s),
mbedtls_mpi_size(&s));
res = TEE_SUCCESS;
} else {
FMSG("mbedtls_ecdsa_sign failed, returned 0x%x\n", -lmd_res);
res = TEE_ERROR_GENERIC;
}
out:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
/* Reset mpi to skip freeing here, those mpis will be freed with key */
mbedtls_mpi_init(&ecdsa.d);
mbedtls_ecdsa_free(&ecdsa);
return res;
}
TEE_Result crypto_acipher_ecc_verify(uint32_t algo, struct ecc_public_key *key,
const uint8_t *msg, size_t msg_len,
const uint8_t *sig, size_t sig_len)
{
TEE_Result res = TEE_SUCCESS;
int lmd_res = 0;
mbedtls_ecdsa_context ecdsa;
size_t key_size_bytes, key_size_bits = 0;
uint8_t one[1] = { 1 };
mbedtls_mpi r;
mbedtls_mpi s;
memset(&ecdsa, 0, sizeof(ecdsa));
memset(&r, 0, sizeof(r));
memset(&s, 0, sizeof(s));
if (algo == 0)
return TEE_ERROR_BAD_PARAMETERS;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
mbedtls_ecdsa_init(&ecdsa);
lmd_res = mbedtls_ecp_group_load(&ecdsa.grp, key->curve);
if (lmd_res != 0) {
res = TEE_ERROR_NOT_SUPPORTED;
goto out;
}
ecdsa.Q.X = *(mbedtls_mpi *)key->x;
ecdsa.Q.Y = *(mbedtls_mpi *)key->y;
mbedtls_mpi_read_binary(&ecdsa.Q.Z, one, sizeof(one));
res = ecc_get_keysize(key->curve, algo,
&key_size_bytes, &key_size_bits);
if (res != TEE_SUCCESS) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
/* check keysize vs sig_len */
if ((key_size_bytes * 2) != sig_len) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
mbedtls_mpi_read_binary(&r, sig, sig_len / 2);
mbedtls_mpi_read_binary(&s, sig + sig_len / 2, sig_len / 2);
lmd_res = mbedtls_ecdsa_verify(&ecdsa.grp, msg, msg_len, &ecdsa.Q,
&r, &s);
if (lmd_res != 0) {
FMSG("mbedtls_ecdsa_verify failed, returned 0x%x", -lmd_res);
res = get_tee_result(lmd_res);
}
out:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
/* Reset mpi to skip freeing here, those mpis will be freed with key */
mbedtls_mpi_init(&ecdsa.Q.X);
mbedtls_mpi_init(&ecdsa.Q.Y);
mbedtls_ecdsa_free(&ecdsa);
return res;
}
TEE_Result crypto_acipher_ecc_shared_secret(struct ecc_keypair *private_key,
struct ecc_public_key *public_key,
void *secret,
unsigned long *secret_len)
{
TEE_Result res = TEE_SUCCESS;
int lmd_res = 0;
uint8_t one[1] = { 1 };
mbedtls_ecdh_context ecdh;
size_t out_len = 0;
memset(&ecdh, 0, sizeof(ecdh));
mbedtls_ecdh_init(&ecdh);
lmd_res = mbedtls_ecp_group_load(&ecdh.grp, private_key->curve);
if (lmd_res != 0) {
res = TEE_ERROR_NOT_SUPPORTED;
goto out;
}
ecdh.d = *(mbedtls_mpi *)private_key->d;
ecdh.Qp.X = *(mbedtls_mpi *)public_key->x;
ecdh.Qp.Y = *(mbedtls_mpi *)public_key->y;
mbedtls_mpi_read_binary(&ecdh.Qp.Z, one, sizeof(one));
lmd_res = mbedtls_ecdh_calc_secret(&ecdh, &out_len, secret,
*secret_len, mbd_rand, NULL);
if (lmd_res != 0) {
res = get_tee_result(lmd_res);
goto out;
}
*secret_len = out_len;
out:
/* Reset mpi to skip freeing here, those mpis will be freed with key */
mbedtls_mpi_init(&ecdh.d);
mbedtls_mpi_init(&ecdh.Qp.X);
mbedtls_mpi_init(&ecdh.Qp.Y);
mbedtls_ecdh_free(&ecdh);
return res;
}