libmbedtls: support mbedtls ECC function

Support mbedtls ECC: ecdh and ecdsa.

Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Edison Ai <edison.ai@arm.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/lib/libmbedtls/core/ecc.c b/lib/libmbedtls/core/ecc.c
new file mode 100644
index 0000000..3c04258
--- /dev/null
+++ b/lib/libmbedtls/core/ecc.c
@@ -0,0 +1,378 @@
+// 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;
+}
diff --git a/lib/libmbedtls/core/stubbed.c b/lib/libmbedtls/core/stubbed.c
index b8f6b89..359d655 100644
--- a/lib/libmbedtls/core/stubbed.c
+++ b/lib/libmbedtls/core/stubbed.c
@@ -57,59 +57,6 @@
 }
 #endif /* CFG_CRYPTO_DSA */
 
-#if defined(CFG_CRYPTO_ECC)
-TEE_Result
-crypto_acipher_alloc_ecc_public_key(struct ecc_public_key *s __unused,
-				    size_t key_size_bits __unused)
-{
-	return TEE_ERROR_NOT_IMPLEMENTED;
-}
-
-TEE_Result crypto_acipher_alloc_ecc_keypair(struct ecc_keypair *s __unused,
-					    size_t key_size_bits __unused)
-{
-	return TEE_ERROR_NOT_IMPLEMENTED;
-}
-
-void crypto_acipher_free_ecc_public_key(struct ecc_public_key *s __unused)
-{
-}
-
-TEE_Result crypto_acipher_gen_ecc_key(struct ecc_keypair *key __unused)
-{
-	return TEE_ERROR_NOT_IMPLEMENTED;
-}
-
-TEE_Result crypto_acipher_ecc_sign(uint32_t algo __unused,
-				   struct ecc_keypair *key __unused,
-				   const uint8_t *msg __unused,
-				   size_t msg_len __unused,
-				   uint8_t *sig __unused,
-				   size_t *sig_len __unused)
-{
-	return TEE_ERROR_NOT_IMPLEMENTED;
-}
-
-TEE_Result crypto_acipher_ecc_verify(uint32_t algo __unused,
-				     struct ecc_public_key *key __unused,
-				     const uint8_t *msg __unused,
-				     size_t msg_len __unused,
-				     const uint8_t *sig __unused,
-				     size_t sig_len __unused)
-{
-	return TEE_ERROR_NOT_IMPLEMENTED;
-}
-
-TEE_Result
-crypto_acipher_ecc_shared_secret(struct ecc_keypair *private_key __unused,
-				 struct ecc_public_key *public_key __unused,
-				 void *secret __unused,
-				 unsigned long *secret_len __unused)
-{
-	return TEE_ERROR_NOT_IMPLEMENTED;
-}
-#endif /* CFG_CRYPTO_ECC */
-
 
 /* Stubs for the crypto alloc ctx functions matching crypto_impl.h */
 #undef CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED
diff --git a/lib/libmbedtls/core/sub.mk b/lib/libmbedtls/core/sub.mk
index ff67e18..dc26286 100644
--- a/lib/libmbedtls/core/sub.mk
+++ b/lib/libmbedtls/core/sub.mk
@@ -26,3 +26,4 @@
 			     CFG_CRYPTO_DH CFG_CRYPTO_ECC) += bignum.c
 srcs-$(CFG_CRYPTO_RSA) += rsa.c
 srcs-$(CFG_CRYPTO_DH) += dh.c
+srcs-$(CFG_CRYPTO_ECC) += ecc.c
diff --git a/lib/libmbedtls/include/mbedtls_config_kernel.h b/lib/libmbedtls/include/mbedtls_config_kernel.h
index b3d71cd..d8ade1d 100644
--- a/lib/libmbedtls/include/mbedtls_config_kernel.h
+++ b/lib/libmbedtls/include/mbedtls_config_kernel.h
@@ -79,7 +79,7 @@
 #define MBEDTLS_RSA_NO_CRT
 #endif
 
-#if defined(CFG_CRYPTO_RSA)
+#if defined(CFG_CRYPTO_RSA) || defined(CFG_CRYPTO_ECC)
 #define MBEDTLS_ASN1_PARSE_C
 #define MBEDTLS_ASN1_WRITE_C
 #endif
@@ -88,6 +88,24 @@
 #define MBEDTLS_DHM_C
 #endif
 
+#if defined(CFG_CRYPTO_ECC)
+#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
+#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
+#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
+#define MBEDTLS_ECP_DP_BP256R1_ENABLED
+#define MBEDTLS_ECP_DP_BP384R1_ENABLED
+#define MBEDTLS_ECP_DP_BP512R1_ENABLED
+#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
+#define MBEDTLS_ECP_C
+#define MBEDTLS_ECDSA_C
+#define MBEDTLS_ECDH_C
+#endif
+
 #endif /*CFG_CRYPTOLIB_NAME_mbedtls*/
 
 #include <mbedtls/check_config.h>