core: add support for SM2 using MBed TLS
The SM2 algorithms (PKE, KEP and DSA) are currently implemented using
LibTomCrypt. They are automatically disabled when MBed TLS is selected
as the core crypto library (that is, when CFG_CRYPTOLIB_NAME=mbedtls
CFG_CRYPTOLIB_DIR=lib/libmbedtls).
This commit removes this restriction by porting the relevant files
(core/lib/libtomcrypt/sm2-{dsa,kep,pke}.c) over to the MBed TLS API in
lib/libmbedtls/core.
Signed-off-by: Jerome Forissier <jerome@forissier.org>
Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
diff --git a/lib/libmbedtls/core/ecc.c b/lib/libmbedtls/core/ecc.c
index d04eda7..7c2cd03 100644
--- a/lib/libmbedtls/core/ecc.c
+++ b/lib/libmbedtls/core/ecc.c
@@ -5,7 +5,7 @@
*/
#include <assert.h>
-#include <compiler.h>
+#include <config.h>
#include <crypto/crypto_impl.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdh.h>
@@ -17,6 +17,8 @@
#include <string.h>
#include "mbed_helpers.h"
+#include "sm2-dsa.h"
+#include "sm2-pke.h"
/* Translate mbedtls result to TEE result */
static TEE_Result get_tee_result(int lmd_res)
@@ -349,20 +351,53 @@
.shared_secret = ecc_shared_secret,
};
+static const struct crypto_ecc_keypair_ops sm2_pke_keypair_ops = {
+ .generate = ecc_generate_keypair,
+ .decrypt = sm2_mbedtls_pke_decrypt,
+};
+
+static const struct crypto_ecc_keypair_ops sm2_kep_keypair_ops = {
+ .generate = ecc_generate_keypair,
+};
+
+static const struct crypto_ecc_keypair_ops sm2_dsa_keypair_ops = {
+ .generate = ecc_generate_keypair,
+ .sign = sm2_mbedtls_dsa_sign,
+};
+
TEE_Result crypto_asym_alloc_ecc_keypair(struct ecc_keypair *s,
uint32_t key_type,
size_t key_size_bits)
{
+ memset(s, 0, sizeof(*s));
+
switch (key_type) {
- case TEE_TYPE_SM2_DSA_KEYPAIR:
- case TEE_TYPE_SM2_PKE_KEYPAIR:
- case TEE_TYPE_SM2_KEP_KEYPAIR:
- return TEE_ERROR_NOT_IMPLEMENTED;
- default:
+ case TEE_TYPE_ECDSA_KEYPAIR:
+ case TEE_TYPE_ECDH_KEYPAIR:
+ s->ops = &ecc_keypair_ops;
break;
+ case TEE_TYPE_SM2_DSA_KEYPAIR:
+ if (!IS_ENABLED(CFG_CRYPTO_SM2_DSA))
+ return TEE_ERROR_NOT_IMPLEMENTED;
+
+ s->ops = &sm2_dsa_keypair_ops;
+ break;
+ case TEE_TYPE_SM2_PKE_KEYPAIR:
+ if (!IS_ENABLED(CFG_CRYPTO_SM2_PKE))
+ return TEE_ERROR_NOT_IMPLEMENTED;
+
+ s->ops = &sm2_pke_keypair_ops;
+ break;
+ case TEE_TYPE_SM2_KEP_KEYPAIR:
+ if (!IS_ENABLED(CFG_CRYPTO_SM2_KEP))
+ return TEE_ERROR_NOT_IMPLEMENTED;
+
+ s->ops = &sm2_kep_keypair_ops;
+ break;
+ default:
+ return TEE_ERROR_NOT_IMPLEMENTED;
}
- memset(s, 0, sizeof(*s));
s->d = crypto_bignum_allocate(key_size_bits);
if (!s->d)
goto err;
@@ -373,8 +408,6 @@
if (!s->y)
goto err;
- s->ops = &ecc_keypair_ops;
-
return TEE_SUCCESS;
err:
@@ -389,20 +422,53 @@
.verify = ecc_verify,
};
+static const struct crypto_ecc_public_ops sm2_pke_public_key_ops = {
+ .free = ecc_free_public_key,
+ .encrypt = sm2_mbedtls_pke_encrypt,
+};
+
+static const struct crypto_ecc_public_ops sm2_kep_public_key_ops = {
+ .free = ecc_free_public_key,
+};
+
+static const struct crypto_ecc_public_ops sm2_dsa_public_key_ops = {
+ .free = ecc_free_public_key,
+ .verify = sm2_mbedtls_dsa_verify,
+};
+
TEE_Result crypto_asym_alloc_ecc_public_key(struct ecc_public_key *s,
uint32_t key_type,
size_t key_size_bits)
{
+ memset(s, 0, sizeof(*s));
+
switch (key_type) {
- case TEE_TYPE_SM2_DSA_PUBLIC_KEY:
- case TEE_TYPE_SM2_PKE_PUBLIC_KEY:
- case TEE_TYPE_SM2_KEP_PUBLIC_KEY:
- return TEE_ERROR_NOT_IMPLEMENTED;
- default:
+ case TEE_TYPE_ECDSA_PUBLIC_KEY:
+ case TEE_TYPE_ECDH_PUBLIC_KEY:
+ s->ops = &ecc_public_key_ops;
break;
+ case TEE_TYPE_SM2_DSA_PUBLIC_KEY:
+ if (!IS_ENABLED(CFG_CRYPTO_SM2_DSA))
+ return TEE_ERROR_NOT_IMPLEMENTED;
+
+ s->ops = &sm2_dsa_public_key_ops;
+ break;
+ case TEE_TYPE_SM2_PKE_PUBLIC_KEY:
+ if (!IS_ENABLED(CFG_CRYPTO_SM2_PKE))
+ return TEE_ERROR_NOT_IMPLEMENTED;
+
+ s->ops = &sm2_pke_public_key_ops;
+ break;
+ case TEE_TYPE_SM2_KEP_PUBLIC_KEY:
+ if (!IS_ENABLED(CFG_CRYPTO_SM2_KEP))
+ return TEE_ERROR_NOT_IMPLEMENTED;
+
+ s->ops = &sm2_kep_public_key_ops;
+ break;
+ default:
+ return TEE_ERROR_NOT_IMPLEMENTED;
}
- memset(s, 0, sizeof(*s));
s->x = crypto_bignum_allocate(key_size_bits);
if (!s->x)
goto err;
@@ -410,8 +476,6 @@
if (!s->y)
goto err;
- s->ops = &ecc_public_key_ops;
-
return TEE_SUCCESS;
err:
diff --git a/lib/libmbedtls/core/mbed_helpers.c b/lib/libmbedtls/core/mbed_helpers.c
new file mode 100644
index 0000000..49d322e
--- /dev/null
+++ b/lib/libmbedtls/core/mbed_helpers.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2021 Huawei Technologies Co., Ltd
+ */
+
+#include <compiler.h>
+#include <crypto/crypto.h>
+#include <mbedtls/bignum.h>
+#include <stddef.h>
+#include <tee_api_defines.h>
+#include <tee_api_types.h>
+
+#include "mbed_helpers.h"
+
+/* Generate random number 1 <= n < max */
+TEE_Result mbed_gen_random_upto(mbedtls_mpi *n, mbedtls_mpi *max)
+{
+ size_t sz = mbedtls_mpi_size(max);
+ bool found = false;
+ int mres = 0;
+
+ do {
+ mres = mbedtls_mpi_fill_random(n, sz, mbd_rand, NULL);
+ if (mres)
+ return TEE_ERROR_BAD_STATE;
+ if (mbedtls_mpi_bitlen(n) != 0 &&
+ mbedtls_mpi_cmp_mpi(n, max) == -1)
+ found = true;
+ } while (!found);
+
+ return TEE_SUCCESS;
+}
+
diff --git a/lib/libmbedtls/core/mbed_helpers.h b/lib/libmbedtls/core/mbed_helpers.h
index 9ecf626..ffea285 100644
--- a/lib/libmbedtls/core/mbed_helpers.h
+++ b/lib/libmbedtls/core/mbed_helpers.h
@@ -9,7 +9,9 @@
#include <crypto/crypto.h>
#include <mbedtls/aes.h>
+#include <mbedtls/bignum.h>
#include <mbedtls/ctr_drbg.h>
+#include <tee_api_types.h>
static inline int mbd_rand(void *rng_state __unused, unsigned char *output,
size_t len)
@@ -36,4 +38,5 @@
#endif
}
+TEE_Result mbed_gen_random_upto(mbedtls_mpi *n, mbedtls_mpi *max);
#endif /*MBED_HELPERS_H*/
diff --git a/lib/libmbedtls/core/sm2-dsa.c b/lib/libmbedtls/core/sm2-dsa.c
new file mode 100644
index 0000000..4db1de7
--- /dev/null
+++ b/lib/libmbedtls/core/sm2-dsa.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2019-2021 Huawei Technologies Co., Ltd
+ */
+
+#include <compiler.h>
+#include <crypto/crypto.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/ecp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tee_api_types.h>
+#include <util.h>
+#include <utee_defines.h>
+
+#include "mbed_helpers.h"
+#include "sm2-dsa.h"
+
+/* SM2 uses 256 bit unsigned integers in big endian format */
+#define SM2_INT_SIZE_BYTES 32
+
+/*
+ * GM/T 0003.1‒2012 Part1 2 Section 6.1
+ */
+TEE_Result sm2_mbedtls_dsa_sign(uint32_t algo __unused, struct ecc_keypair *key,
+ const uint8_t *msg, size_t msg_len,
+ uint8_t *sig, size_t *sig_len)
+{
+ TEE_Result res = TEE_SUCCESS;
+ mbedtls_ecp_group grp = { };
+ mbedtls_ecp_point x1y1p = { };
+ int mres = 0;
+ mbedtls_mpi k = { };
+ mbedtls_mpi e = { };
+ mbedtls_mpi r = { };
+ mbedtls_mpi s = { };
+ mbedtls_mpi tmp = { };
+
+ if (*sig_len < 2 * SM2_INT_SIZE_BYTES) {
+ *sig_len = 64;
+ return TEE_ERROR_SHORT_BUFFER;
+ }
+
+ mbedtls_mpi_init(&k);
+ mbedtls_mpi_init(&e);
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi_init(&s);
+ mbedtls_mpi_init(&tmp);
+
+ mbedtls_ecp_point_init(&x1y1p);
+
+ mbedtls_ecp_group_init(&grp);
+ mres = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SM2);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+
+ /*
+ * Steps A1 and A2 are the generation of the hash value e from user
+ * information (ZA) and the message to be signed (M). There are not done
+ * here since @msg is expected to be the hash value e already.
+ */
+
+ /* Step A3: generate random number 1 <= k < n */
+ do {
+ res = mbed_gen_random_upto(&k, &grp.N);
+ if (res)
+ goto out;
+
+ res = TEE_ERROR_BAD_STATE;
+
+ /* Step A4: compute (x1, y1) = [k]G */
+
+ mres = mbedtls_ecp_mul(&grp, &x1y1p, &k, &grp.G, mbd_rand,
+ NULL);
+ if (mres)
+ goto out;
+
+ /* Step A5: compute r = (e + x1) mod n */
+
+ mbedtls_mpi_read_binary(&e, (unsigned char *)msg, msg_len);
+ mres = mbedtls_mpi_add_mpi(&r, &e, &x1y1p.X);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mod_mpi(&r, &r, &grp.N);
+ if (mres)
+ goto out;
+
+ /* Step A5 (continued): return to A3 if r = 0 or r + k = n */
+
+ mres = mbedtls_mpi_add_mpi(&tmp, &r, &k);
+ if (mres)
+ goto out;
+ } while (!mbedtls_mpi_cmp_int(&r, 0) ||
+ !mbedtls_mpi_cmp_mpi(&tmp, &grp.N));
+
+ /* Step A6: compute s = ((1 + dA)^-1 * (k - r*dA)) mod n */
+
+ mres = mbedtls_mpi_add_int(&s, (mbedtls_mpi *)key->d, 1);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_inv_mod(&s, &s, &grp.N);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mul_mpi(&tmp, &r, (mbedtls_mpi *)key->d);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mod_mpi(&tmp, &tmp, &grp.N);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_sub_mpi(&tmp, &k, &tmp);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mul_mpi(&s, &s, &tmp);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mod_mpi(&s, &s, &grp.N);
+ if (mres)
+ goto out;
+
+ /* Step A7: convert (r, s) to binary for output */
+
+ *sig_len = 2 * SM2_INT_SIZE_BYTES;
+ memset(sig, 0, *sig_len);
+ mres = mbedtls_mpi_write_binary(&r, sig, SM2_INT_SIZE_BYTES);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_write_binary(&s, sig + SM2_INT_SIZE_BYTES,
+ SM2_INT_SIZE_BYTES);
+ if (mres)
+ goto out;
+
+ res = TEE_SUCCESS;
+out:
+ mbedtls_ecp_point_free(&x1y1p);
+ mbedtls_mpi_free(&k);
+ mbedtls_mpi_free(&e);
+ mbedtls_mpi_free(&r);
+ mbedtls_mpi_free(&s);
+ mbedtls_mpi_free(&tmp);
+ return res;
+}
+
+/*
+ * GM/T 0003.1‒2012 Part1 2 Section 7.1
+ */
+TEE_Result sm2_mbedtls_dsa_verify(uint32_t algo __unused,
+ 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_ERROR_BAD_STATE;
+ mbedtls_ecp_group grp = { };
+ mbedtls_mpi rprime = { };
+ mbedtls_mpi sprime = { };
+ mbedtls_mpi t = { };
+ mbedtls_mpi eprime = { };
+ mbedtls_mpi R = { };
+ mbedtls_ecp_point x1y1p = { };
+ mbedtls_ecp_point PA = { };
+ int mres = 0;
+
+ if (sig_len != 64)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ mbedtls_mpi_init(&rprime);
+ mbedtls_mpi_init(&sprime);
+ mbedtls_mpi_init(&t);
+ mbedtls_mpi_init(&eprime);
+ mbedtls_mpi_init(&R);
+
+ mbedtls_ecp_point_init(&x1y1p);
+ mbedtls_ecp_point_init(&PA);
+
+ mbedtls_ecp_group_init(&grp);
+ mres = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SM2);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+
+ mres = mbedtls_mpi_read_binary(&rprime, sig, 32);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_read_binary(&sprime, sig + 32, 32);
+ if (mres)
+ goto out;
+
+ /* Step B1: verify r' in [1, n - 1] */
+
+ if (mbedtls_mpi_cmp_int(&rprime, 1) < 0 ||
+ mbedtls_mpi_cmp_mpi(&rprime, &grp.N) >= 0) {
+ res = TEE_ERROR_SIGNATURE_INVALID;
+ goto out;
+ }
+
+ /* Step B2: verify s' in [1, n - 1] */
+
+ if (mbedtls_mpi_cmp_int(&sprime, 1) < 0 ||
+ mbedtls_mpi_cmp_mpi(&sprime, &grp.N) >= 0) {
+ res = TEE_ERROR_SIGNATURE_INVALID;
+ goto out;
+ }
+
+ /*
+ * Steps B3: M'bar = (ZA || M') and B4: e' = Hv(M'bar) are not done here
+ * because @msg is supposed to contain the hash value e' already.
+ */
+
+ /* Step B5: t = (r' + s') mod n and check t != 0 */
+
+ mres = mbedtls_mpi_add_mpi(&t, &rprime, &sprime);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mod_mpi(&t, &t, &grp.N);
+ if (mres)
+ goto out;
+ if (!mbedtls_mpi_cmp_int(&t, 0)) {
+ res = TEE_ERROR_SIGNATURE_INVALID;
+ goto out;
+ }
+
+ /* Step B6: (x1', y1') = [s']G + [t]PA */
+
+ mres = mbedtls_mpi_copy(&PA.X, (mbedtls_mpi *)key->x);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_copy(&PA.Y, (mbedtls_mpi *)key->y);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_lset(&PA.Z, 1);
+ if (mres)
+ goto out;
+
+ mres = mbedtls_ecp_muladd(&grp, &x1y1p, &sprime, &grp.G, &t, &PA);
+ if (mres)
+ goto out;
+
+ /* Step B7: compute R = (e' + x1') mod n and verify R == r' */
+
+ mres = mbedtls_mpi_read_binary(&eprime, msg, msg_len);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_add_mpi(&R, &eprime, &x1y1p.X);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mod_mpi(&R, &R, &grp.N);
+ if (mres)
+ goto out;
+ if (mbedtls_mpi_cmp_mpi(&R, &rprime)) {
+ res = TEE_ERROR_SIGNATURE_INVALID;
+ goto out;
+ }
+
+ res = TEE_SUCCESS;
+out:
+ mbedtls_ecp_point_free(&x1y1p);
+ mbedtls_ecp_point_free(&PA);
+ mbedtls_mpi_free(&rprime);
+ mbedtls_mpi_free(&sprime);
+ mbedtls_mpi_free(&t);
+ mbedtls_mpi_free(&eprime);
+ mbedtls_mpi_free(&R);
+ return res;
+}
diff --git a/lib/libmbedtls/core/sm2-dsa.h b/lib/libmbedtls/core/sm2-dsa.h
new file mode 100644
index 0000000..a7b22ea
--- /dev/null
+++ b/lib/libmbedtls/core/sm2-dsa.h
@@ -0,0 +1,20 @@
+
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2021 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _SM2_DSA_H_
+
+#include <crypto/crypto.h>
+#include <stdint.h>
+#include <tee_api_types.h>
+
+TEE_Result sm2_mbedtls_dsa_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 sm2_mbedtls_dsa_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);
+#endif /* _SM2_DSA_H_ */
diff --git a/lib/libmbedtls/core/sm2-kep.c b/lib/libmbedtls/core/sm2-kep.c
new file mode 100644
index 0000000..46f994e
--- /dev/null
+++ b/lib/libmbedtls/core/sm2-kep.c
@@ -0,0 +1,499 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2020-21 Huawei Technologies Co., Ltd
+ */
+
+#include <crypto/crypto.h>
+#include <crypto/sm2-kdf.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/ecp.h>
+#include <string_ext.h>
+#include <tee_api_types.h>
+#include <utee_defines.h>
+
+#include "mbed_helpers.h"
+
+/* SM2 uses 256 bit unsigned integers in big endian format */
+#define SM2_INT_SIZE_BYTES 32
+
+/* The public x and y values extracted from a public or private ECC key */
+struct key_xy {
+ mbedtls_mpi *x;
+ mbedtls_mpi *y;
+};
+
+/*
+ * Compute a hash of a user's identity and public key
+ * For user A: ZA = SM3(ENTLA || IDA || a || b || xG || yG || xA || yA)
+ */
+static TEE_Result sm2_kep_compute_Z(const mbedtls_ecp_group *grp, uint8_t *Z,
+ size_t Zlen, const uint8_t *id,
+ size_t idlen, struct key_xy *key)
+{
+ TEE_Result res = TEE_ERROR_GENERIC;
+ uint8_t ENTLEN[2] = { };
+ uint8_t buf[SM2_INT_SIZE_BYTES] = { };
+ void *ctx = NULL;
+ int mres = 0;
+
+ if (Zlen < TEE_SM3_HASH_SIZE)
+ return TEE_ERROR_SHORT_BUFFER;
+
+ /*
+ * ENTLEN is the length in bits if the user's distinguished identifier
+ * encoded over 16 bits in big endian format.
+ */
+ ENTLEN[0] = (idlen * 8) >> 8;
+ ENTLEN[1] = idlen * 8;
+
+ res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
+ if (res)
+ goto out;
+
+ res = crypto_hash_init(ctx);
+ if (res)
+ goto out;
+
+ res = crypto_hash_update(ctx, ENTLEN, sizeof(ENTLEN));
+ if (res)
+ goto out;
+
+ res = crypto_hash_update(ctx, id, idlen);
+ if (res)
+ goto out;
+
+ mres = mbedtls_mpi_write_binary(&grp->A, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ mres = mbedtls_mpi_write_binary(&grp->B, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ mres = mbedtls_mpi_write_binary(&grp->G.X, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ mres = mbedtls_mpi_write_binary(&grp->G.Y, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ mres = mbedtls_mpi_write_binary(key->x, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ mres = mbedtls_mpi_write_binary(key->y, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ res = crypto_hash_final(ctx, Z, TEE_SM3_HASH_SIZE);
+out:
+ crypto_hash_free_ctx(ctx);
+ return res;
+}
+
+/*
+ * Compute a verification value, to be checked against the value sent by the
+ * peer.
+ * On the initiator's side:
+ * S1 = SM3(0x02 || yU || SM3(xU || ZA || ZB || x1 || y1 || x2 || y2))
+ * On the responder's side:
+ * S2 = SM3(0x03 || yV || SM3(xV || ZA || ZB || x1 || y1 || x2 || y2))
+ */
+static TEE_Result sm2_kep_compute_S(uint8_t *S, size_t S_len, uint8_t flag,
+ mbedtls_ecp_point *UV, const uint8_t *ZAZB,
+ size_t ZAZB_len,
+ struct key_xy *initiator_eph_key,
+ struct key_xy *responder_eph_key)
+{
+ uint8_t hash[TEE_SM3_HASH_SIZE] = { };
+ TEE_Result res = TEE_ERROR_GENERIC;
+ uint8_t buf[SM2_INT_SIZE_BYTES];
+ void *ctx = NULL;
+ int mres = 0;
+
+ if (S_len < TEE_SM3_HASH_SIZE)
+ return TEE_ERROR_SHORT_BUFFER;
+
+ res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
+ if (res)
+ goto out;
+
+ /* Compute the inner hash */
+
+ res = crypto_hash_init(ctx);
+ if (res)
+ goto out;
+
+ /* xU or xV */
+ mres = mbedtls_mpi_write_binary(&UV->X, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ /* ZA || ZB */
+ res = crypto_hash_update(ctx, ZAZB, ZAZB_len);
+ if (res)
+ goto out;
+
+ /* x1 */
+ mres = mbedtls_mpi_write_binary(initiator_eph_key->x, buf,
+ SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ /* y1 */
+ mres = mbedtls_mpi_write_binary(initiator_eph_key->y, buf,
+ SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ /* x2 */
+ mres = mbedtls_mpi_write_binary(responder_eph_key->x, buf,
+ SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ /* y2 */
+ mres = mbedtls_mpi_write_binary(responder_eph_key->y, buf,
+ SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ res = crypto_hash_final(ctx, hash, sizeof(hash));
+ if (res)
+ goto out;
+
+ /* Now compute S */
+
+ res = crypto_hash_init(ctx);
+ if (res)
+ goto out;
+
+ /* 0x02 or 0x03 */
+ res = crypto_hash_update(ctx, &flag, sizeof(flag));
+ if (res)
+ goto out;
+
+ /* yU or yV */
+ mres = mbedtls_mpi_write_binary(&UV->Y, buf, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+ res = crypto_hash_update(ctx, buf, sizeof(buf));
+ if (res)
+ goto out;
+
+ /* Inner SM3(...) */
+ res = crypto_hash_update(ctx, hash, sizeof(hash));
+ if (res)
+ goto out;
+
+ res = crypto_hash_final(ctx, S, TEE_SM3_HASH_SIZE);
+
+out:
+ crypto_hash_free_ctx(ctx);
+ return res;
+
+}
+
+static void extract_xy_from_keypair(struct key_xy *xy,
+ const struct ecc_keypair *pair)
+{
+ xy->x = (mbedtls_mpi *)pair->x;
+ xy->y = (mbedtls_mpi *)pair->y;
+ /* Other fields are not used */
+}
+
+static void extract_xy_from_public_key(struct key_xy *xy,
+ const struct ecc_public_key *from)
+{
+ xy->x = (mbedtls_mpi *)from->x;
+ xy->y = (mbedtls_mpi *)from->y;
+}
+
+/*
+ * GM/T 0003.1‒2012 Part 3 Section 6.1
+ * Key exchange protocol
+ */
+TEE_Result crypto_acipher_sm2_kep_derive(struct ecc_keypair *my_key,
+ struct ecc_keypair *my_eph_key,
+ struct ecc_public_key *peer_key,
+ struct ecc_public_key *peer_eph_key,
+ struct sm2_kep_parms *p)
+{
+ /*
+ * Variable names and documented steps reflect the initator side (user A
+ * in the spec), but the other side is quite similar hence only one
+ * function.
+ */
+ uint8_t xUyUZAZB[2 * SM2_INT_SIZE_BYTES + 2 * TEE_SM3_HASH_SIZE] = { };
+ struct key_xy initiator_eph_key = { };
+ struct key_xy responder_eph_key = { };
+ struct key_xy initiator_key = { };
+ struct key_xy responder_key = { };
+ TEE_Result res = TEE_ERROR_BAD_STATE;
+ uint8_t tmp[SM2_INT_SIZE_BYTES] = { };
+ mbedtls_ecp_group grp = { };
+ mbedtls_ecp_point PB = { };
+ mbedtls_ecp_point RB = { };
+ mbedtls_ecp_point U = { };
+ mbedtls_mpi x1bar = { };
+ mbedtls_mpi x2bar = { };
+ mbedtls_mpi tA = { };
+ mbedtls_mpi h = { };
+ mbedtls_mpi htA = { };
+ mbedtls_mpi one = { };
+ int mres = 0;
+
+ if (p->is_initiator) {
+ extract_xy_from_keypair(&initiator_eph_key, my_eph_key);
+ extract_xy_from_public_key(&responder_eph_key, peer_eph_key);
+ extract_xy_from_keypair(&initiator_key, my_key);
+ extract_xy_from_public_key(&responder_key, peer_key);
+ } else {
+ extract_xy_from_public_key(&initiator_eph_key, peer_eph_key);
+ extract_xy_from_keypair(&responder_eph_key, my_eph_key);
+ extract_xy_from_public_key(&initiator_key, peer_key);
+ extract_xy_from_keypair(&responder_key, my_key);
+ }
+
+ mbedtls_mpi_init(&x1bar);
+ mbedtls_mpi_init(&x2bar);
+ mbedtls_mpi_init(&tA);
+ mbedtls_mpi_init(&h);
+ mbedtls_mpi_init(&htA);
+ mbedtls_mpi_init(&one);
+
+ mbedtls_ecp_point_init(&PB);
+ mbedtls_ecp_point_init(&RB);
+ mbedtls_ecp_point_init(&U);
+
+ mbedtls_ecp_group_init(&grp);
+ mres = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SM2);
+ if (mres)
+ goto out;
+
+ /*
+ * Steps A1-A3 are supposedly done already (generate ephemeral key, send
+ * it to peer).
+ * Step A4: (x1, y1) = RA; x1bar = 2^w + (x1 & (2^w - 1))
+ */
+
+ mres = mbedtls_mpi_write_binary((mbedtls_mpi *)my_eph_key->x, tmp,
+ SM2_INT_SIZE_BYTES);
+ if (mres)
+ goto out;
+ tmp[SM2_INT_SIZE_BYTES / 2] |= 0x80;
+ mres = mbedtls_mpi_read_binary(&x1bar, tmp + SM2_INT_SIZE_BYTES / 2,
+ SM2_INT_SIZE_BYTES / 2);
+ if (mres)
+ goto out;
+
+ /* Step A5: tA = (dA + x1bar * rA) mod n */
+
+ mres = mbedtls_mpi_mul_mpi(&tA, &x1bar, (mbedtls_mpi *)my_eph_key->d);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mod_mpi(&tA, &tA, &grp.N);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_add_mpi(&tA, &tA, (mbedtls_mpi *)my_key->d);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_mod_mpi(&tA, &tA, &grp.N);
+ if (mres)
+ goto out;
+
+ /* Step A6: verify whether RB verifies the curve equation */
+
+ mbedtls_mpi_copy(&RB.X, (mbedtls_mpi *)peer_eph_key->x);
+ mbedtls_mpi_copy(&RB.Y, (mbedtls_mpi *)peer_eph_key->y);
+ mbedtls_mpi_lset(&RB.Z, 1);
+ mres = mbedtls_ecp_check_pubkey(&grp, &RB);
+ if (mres)
+ goto out;
+
+ /* Step A6 (continued): (x2, y2) = RB; x2bar = 2^w + (x2 & (2^w - 1)) */
+
+ mres = mbedtls_mpi_write_binary((mbedtls_mpi *)peer_eph_key->x, tmp,
+ SM2_INT_SIZE_BYTES);
+ if (mres)
+ goto out;
+ tmp[SM2_INT_SIZE_BYTES / 2] |= 0x80;
+ mres = mbedtls_mpi_read_binary(&x2bar, tmp + SM2_INT_SIZE_BYTES / 2,
+ SM2_INT_SIZE_BYTES / 2);
+ if (mres)
+ goto out;
+
+ /* Step A7: compute U = [h.tA](PB + [x2bar]RB) and check for infinity */
+
+ mres = mbedtls_mpi_copy(&PB.X, (mbedtls_mpi *)peer_key->x);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_copy(&PB.Y, (mbedtls_mpi *)peer_key->y);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_lset(&PB.Z, 1);
+ if (mres)
+ goto out;
+ mres = mbedtls_mpi_lset(&one, 1);
+ if (mres)
+ goto out;
+
+ mres = mbedtls_ecp_muladd(&grp, &U, &one, &PB, &x2bar, &RB);
+ if (mres)
+ goto out;
+
+ /* Note: the cofactor for SM2 is 1 so [h.tA] == tA */
+ mres = mbedtls_ecp_mul(&grp, &U, &tA, &U, mbd_rand, NULL);
+ if (mres)
+ goto out;
+
+ /*
+ * "Point is zero" is same as "point is at infinity". Returns 1 if
+ * point is zero, < 0 on error and 0 if point is non-zero.
+ */
+ mres = mbedtls_ecp_is_zero(&U);
+ if (mres)
+ goto out;
+
+ /* Step A8: compute KA = KDF(xU || yU || ZA || ZB, klen) */
+
+ /* xU */
+ mres = mbedtls_mpi_write_binary(&U.X, xUyUZAZB, SM2_INT_SIZE_BYTES);
+ if (mres)
+ goto out;
+
+ /* yU */
+ mres = mbedtls_mpi_write_binary(&U.Y, xUyUZAZB + SM2_INT_SIZE_BYTES,
+ SM2_INT_SIZE_BYTES);
+ if (mres)
+ goto out;
+
+ /* ZA */
+ res = sm2_kep_compute_Z(&grp, xUyUZAZB + 2 * SM2_INT_SIZE_BYTES,
+ TEE_SM3_HASH_SIZE, p->initiator_id,
+ p->initiator_id_len, &initiator_key);
+ if (res)
+ goto out;
+
+ /* ZB */
+ res = sm2_kep_compute_Z(&grp, xUyUZAZB + 2 * SM2_INT_SIZE_BYTES +
+ TEE_SM3_HASH_SIZE,
+ TEE_SM3_HASH_SIZE, p->responder_id,
+ p->responder_id_len, &responder_key);
+ if (res)
+ goto out;
+
+ res = sm2_kdf(xUyUZAZB, sizeof(xUyUZAZB), p->out, p->out_len);
+ if (res)
+ goto out;
+
+ /* Step A9: compute S1 and check S1 == SB */
+
+ if (p->conf_in) {
+ uint8_t S1[TEE_SM3_HASH_SIZE] = { };
+ uint8_t flag = p->is_initiator ? 0x02 : 0x03;
+
+ if (p->conf_in_len < TEE_SM3_HASH_SIZE) {
+ res = TEE_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+ res = sm2_kep_compute_S(S1, sizeof(S1), flag, &U,
+ xUyUZAZB + 2 * SM2_INT_SIZE_BYTES,
+ 2 * SM2_INT_SIZE_BYTES,
+ &initiator_eph_key, &responder_eph_key);
+ if (res)
+ goto out;
+
+ if (consttime_memcmp(S1, p->conf_in, sizeof(S1))) {
+ /* Verification failed */
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+ }
+
+ /* Step A10: compute SA */
+
+ if (p->conf_out) {
+ uint8_t flag = p->is_initiator ? 0x03 : 0x02;
+
+ if (p->conf_out_len < TEE_SM3_HASH_SIZE) {
+ res = TEE_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+
+ res = sm2_kep_compute_S(p->conf_out, TEE_SM3_HASH_SIZE, flag,
+ &U, xUyUZAZB + 2 * SM2_INT_SIZE_BYTES,
+ 2 * SM2_INT_SIZE_BYTES,
+ &initiator_eph_key, &responder_eph_key);
+ }
+out:
+ mbedtls_mpi_free(&x1bar);
+ mbedtls_mpi_free(&x2bar);
+ mbedtls_mpi_free(&tA);
+ mbedtls_mpi_free(&h);
+ mbedtls_mpi_free(&htA);
+ mbedtls_mpi_free(&one);
+ mbedtls_ecp_point_free(&PB);
+ mbedtls_ecp_point_free(&RB);
+ mbedtls_ecp_point_free(&U);
+ mbedtls_ecp_group_free(&grp);
+ return res;
+}
diff --git a/lib/libmbedtls/core/sm2-pke.c b/lib/libmbedtls/core/sm2-pke.c
new file mode 100644
index 0000000..45786e8
--- /dev/null
+++ b/lib/libmbedtls/core/sm2-pke.c
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2019-2021 Huawei Technologies Co., Ltd
+ */
+
+#include <crypto/crypto.h>
+#include <crypto/sm2-kdf.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/ecp.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_ext.h>
+#include <tee_api_types.h>
+#include <util.h>
+#include <utee_defines.h>
+
+#include "mbed_helpers.h"
+#include "sm2-pke.h"
+
+/* SM2 uses 256 bit unsigned integers in big endian format */
+#define SM2_INT_SIZE_BYTES 32
+
+static TEE_Result
+sm2_uncompressed_bytes_to_point(const mbedtls_ecp_group *grp,
+ mbedtls_ecp_point *p, const uint8_t *x1y1,
+ size_t max_size, size_t *consumed)
+{
+ uint8_t *ptr = (uint8_t *)x1y1;
+ int mres = 0;
+
+ if (max_size < (size_t)(2 * SM2_INT_SIZE_BYTES))
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ mres = mbedtls_mpi_read_binary(&p->X, ptr, SM2_INT_SIZE_BYTES);
+ if (mres)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ ptr += SM2_INT_SIZE_BYTES;
+
+ mres = mbedtls_mpi_read_binary(&p->Y, ptr, SM2_INT_SIZE_BYTES);
+ if (mres)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ mres = mbedtls_mpi_lset(&p->Z, 1);
+ if (mres)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ mres = mbedtls_ecp_check_pubkey(grp, p);
+ if (mres)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ *consumed = 2 * SM2_INT_SIZE_BYTES + 1; /* PC */
+
+ return TEE_SUCCESS;
+}
+
+/*
+ * GM/T 0003.1‒2012 Part 1 Section 4.2.9
+ * Conversion of a byte string @buf to a point @p. Makes sure @p is on the curve
+ * defined by domain parameters @dp.
+ * Note: only the uncompressed form is supported. Uncompressed and hybrid forms
+ * are TBD.
+ */
+static TEE_Result sm2_bytes_to_point(const mbedtls_ecp_group *grp,
+ mbedtls_ecp_point *p, const uint8_t *buf,
+ size_t max_size, size_t *consumed)
+{
+ uint8_t PC = 0;
+
+ if (!max_size)
+ return TEE_ERROR_BAD_PARAMETERS;
+
+ PC = buf[0];
+
+ switch (PC) {
+ case 0x02:
+ case 0x03:
+ /* Compressed form */
+ return TEE_ERROR_NOT_SUPPORTED;
+ case 0x04:
+ /* Uncompressed form */
+ return sm2_uncompressed_bytes_to_point(grp, p, buf + 1,
+ max_size - 1, consumed);
+ case 0x06:
+ case 0x07:
+ /* Hybrid form */
+ return TEE_ERROR_NOT_SUPPORTED;
+ default:
+ return TEE_ERROR_BAD_PARAMETERS;
+ }
+
+ return TEE_ERROR_GENERIC;
+}
+
+static bool is_zero(const uint8_t *buf, size_t size)
+{
+ uint8_t v = 0;
+ size_t i = 0;
+
+ for (i = 0; i < size; i++)
+ v |= buf[i];
+
+ return !v;
+}
+
+/*
+ * GM/T 0003.1‒2012 Part 4 Section 7.1
+ * Decryption algorithm
+ */
+TEE_Result sm2_mbedtls_pke_decrypt(struct ecc_keypair *key, const uint8_t *src,
+ size_t src_len, uint8_t *dst,
+ size_t *dst_len)
+{
+ TEE_Result res = TEE_SUCCESS;
+ uint8_t x2y2[64] = { };
+ mbedtls_ecp_point C1 = { };
+ size_t C1_len = 0;
+ mbedtls_ecp_point x2y2p = { };
+ mbedtls_ecp_group grp = { };
+ void *ctx = NULL;
+ int mres = 0;
+ uint8_t *t = NULL;
+ size_t C2_len = 0;
+ size_t i = 0;
+ size_t out_len = 0;
+ uint8_t *eom = NULL;
+ uint8_t u[TEE_SM3_HASH_SIZE] = { };
+
+ /*
+ * Input buffer src is (C1 || C2 || C3)
+ * - C1 represents a point (should be on the curve)
+ * - C2 is the encrypted message
+ * - C3 is a SM3 hash
+ */
+
+ mbedtls_ecp_point_init(&C1);
+ mbedtls_ecp_point_init(&x2y2p);
+
+ mbedtls_ecp_group_init(&grp);
+ mres = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SM2);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+
+ /* Step B1: read and validate point C1 from encrypted message */
+
+ res = sm2_bytes_to_point(&grp, &C1, src, src_len, &C1_len);
+ if (res)
+ goto out;
+
+ /*
+ * Step B2: S = [h]C1, the cofactor h is 1 for SM2 so S == C1.
+ * The fact that S is on the curve has already been checked in
+ * sm2_bytes_to_point().
+ */
+
+ /* Step B3: (x2, y2) = [dB]C1 */
+
+ mres = mbedtls_ecp_mul(&grp, &x2y2p, (mbedtls_mpi *)key->d, &C1,
+ mbd_rand, NULL);
+ if (mres) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+
+ if (mbedtls_mpi_size(&x2y2p.X) > SM2_INT_SIZE_BYTES ||
+ mbedtls_mpi_size(&x2y2p.Y) > SM2_INT_SIZE_BYTES) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+
+ mres = mbedtls_mpi_write_binary(&x2y2p.X, x2y2, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+ mres = mbedtls_mpi_write_binary(&x2y2p.Y, x2y2 + SM2_INT_SIZE_BYTES,
+ SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+
+ /* Step B4: t = KDF(x2 || y2, klen) */
+
+ /* C = C1 || C2 || C3 */
+ if (src_len <= C1_len + TEE_SM3_HASH_SIZE) {
+ res = TEE_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+
+ C2_len = src_len - C1_len - TEE_SM3_HASH_SIZE;
+
+ t = calloc(1, C2_len);
+ if (!t) {
+ res = TEE_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ res = sm2_kdf(x2y2, sizeof(x2y2), t, C2_len);
+ if (res)
+ goto out;
+
+ if (is_zero(t, C2_len)) {
+ res = TEE_ERROR_CIPHERTEXT_INVALID;
+ goto out;
+ }
+
+ /* Step B5: get C2 from C and compute Mprime = C2 (+) t */
+
+ out_len = MIN(*dst_len, C2_len);
+ for (i = 0; i < out_len; i++)
+ dst[i] = src[C1_len + i] ^ t[i];
+ *dst_len = out_len;
+ if (out_len < C2_len) {
+ eom = calloc(1, C2_len - out_len);
+ if (!eom) {
+ res = TEE_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+ for (i = out_len; i < C2_len; i++)
+ eom[i - out_len] = src[C1_len + i] ^ t[i];
+ }
+
+ /* Step B6: compute u = Hash(x2 || M' || y2) and compare with C3 */
+
+ res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
+ if (res)
+ goto out;
+ res = crypto_hash_init(ctx);
+ if (res)
+ goto out;
+ res = crypto_hash_update(ctx, x2y2, SM2_INT_SIZE_BYTES);
+ if (res)
+ goto out;
+ res = crypto_hash_update(ctx, dst, out_len);
+ if (res)
+ goto out;
+ if (out_len < C2_len) {
+ res = crypto_hash_update(ctx, eom, C2_len - out_len);
+ if (res)
+ goto out;
+ }
+ res = crypto_hash_update(ctx, x2y2 + SM2_INT_SIZE_BYTES,
+ SM2_INT_SIZE_BYTES);
+ if (res)
+ goto out;
+ res = crypto_hash_final(ctx, u, sizeof(u));
+ if (res)
+ goto out;
+
+ if (consttime_memcmp(u, src + C1_len + C2_len, TEE_SM3_HASH_SIZE)) {
+ res = TEE_ERROR_CIPHERTEXT_INVALID;
+ goto out;
+ }
+out:
+ free(eom);
+ free(t);
+ crypto_hash_free_ctx(ctx);
+ mbedtls_ecp_point_free(&C1);
+ mbedtls_ecp_point_free(&x2y2p);
+ mbedtls_ecp_group_free(&grp);
+ return res;
+}
+
+/*
+ * GM/T 0003.1‒2012 Part 1 Section 4.2.8
+ * Conversion of point @p to a byte string @buf (uncompressed form).
+ */
+static TEE_Result sm2_point_to_bytes(uint8_t *buf, size_t *size,
+ const mbedtls_ecp_point *p)
+{
+ size_t xsize = mbedtls_mpi_size(&p->X);
+ size_t ysize = mbedtls_mpi_size(&p->Y);
+ size_t sz = 2 * SM2_INT_SIZE_BYTES + 1;
+ int mres = 0;
+
+ if (xsize > SM2_INT_SIZE_BYTES || ysize > SM2_INT_SIZE_BYTES ||
+ *size < sz)
+ return TEE_ERROR_BAD_STATE;
+
+ memset(buf, 0, sz);
+ buf[0] = 0x04; /* Uncompressed form indicator */
+ mres = mbedtls_mpi_write_binary(&p->X, buf + 1, SM2_INT_SIZE_BYTES);
+ if (mres)
+ return TEE_ERROR_BAD_STATE;
+ mres = mbedtls_mpi_write_binary(&p->Y, buf + 1 + SM2_INT_SIZE_BYTES,
+ SM2_INT_SIZE_BYTES);
+ if (mres)
+ return TEE_ERROR_BAD_STATE;
+
+ *size = sz;
+
+ return TEE_SUCCESS;
+}
+
+/*
+ * GM/T 0003.1‒2012 Part 4 Section 6.1
+ * Encryption algorithm
+ */
+TEE_Result sm2_mbedtls_pke_encrypt(struct ecc_public_key *key,
+ const uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t *dst_len)
+{
+ TEE_Result res = TEE_SUCCESS;
+ mbedtls_ecp_group grp = { };
+ mbedtls_ecp_point x2y2p = { };
+ mbedtls_ecp_point PB = { };
+ mbedtls_ecp_point C1 = { };
+ uint8_t x2y2[64] = { };
+ uint8_t *t = NULL;
+ int mres = 0;
+ mbedtls_mpi k = { };
+ size_t C1_len = 0;
+ void *ctx = NULL;
+ size_t i = 0;
+
+ mbedtls_mpi_init(&k);
+
+ mbedtls_ecp_point_init(&x2y2p);
+ mbedtls_ecp_point_init(&PB);
+ mbedtls_ecp_point_init(&C1);
+
+ mbedtls_ecp_group_init(&grp);
+ mres = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SM2);
+ if (mres) {
+ res = TEE_ERROR_GENERIC;
+ goto out;
+ }
+
+ /* Step A1: generate random number 1 <= k < n */
+
+ res = mbed_gen_random_upto(&k, &grp.N);
+ if (res)
+ goto out;
+
+ /* Step A2: compute C1 = [k]G */
+
+ mres = mbedtls_ecp_mul(&grp, &C1, &k, &grp.G, mbd_rand, NULL);
+ if (mres) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+
+ /*
+ * Step A3: compute S = [h]PB and check for infinity.
+ * The cofactor h is 1 for SM2 so S == PB, nothing to do.
+ */
+
+ /* Step A4: compute (x2, y2) = [k]PB */
+
+ mbedtls_mpi_copy(&PB.X, (mbedtls_mpi *)key->x);
+ mbedtls_mpi_copy(&PB.Y, (mbedtls_mpi *)key->y);
+ mbedtls_mpi_lset(&PB.Z, 1);
+
+ mres = mbedtls_ecp_mul(&grp, &x2y2p, &k, &PB, mbd_rand, NULL);
+ if (mres) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+
+ if (mbedtls_mpi_size(&x2y2p.X) > SM2_INT_SIZE_BYTES ||
+ mbedtls_mpi_size(&x2y2p.Y) > SM2_INT_SIZE_BYTES) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+
+ mres = mbedtls_mpi_write_binary(&x2y2p.X, x2y2, SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+ mres = mbedtls_mpi_write_binary(&x2y2p.Y, x2y2 + SM2_INT_SIZE_BYTES,
+ SM2_INT_SIZE_BYTES);
+ if (mres) {
+ res = TEE_ERROR_BAD_STATE;
+ goto out;
+ }
+
+ /* Step A5: compute t = KDF(x2 || y2, klen) */
+
+ t = calloc(1, src_len);
+ if (!t) {
+ res = TEE_ERROR_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ res = sm2_kdf(x2y2, sizeof(x2y2), t, src_len);
+ if (res)
+ goto out;
+
+ if (is_zero(t, src_len)) {
+ res = TEE_ERROR_CIPHERTEXT_INVALID;
+ goto out;
+ }
+
+ /*
+ * Steps A6, A7, A8:
+ * Compute C2 = M (+) t
+ * Compute C3 = Hash(x2 || M || y2)
+ * Output C = C1 || C2 || C3
+ */
+
+ /* C1 */
+ C1_len = *dst_len;
+ res = sm2_point_to_bytes(dst, &C1_len, &C1);
+ if (res)
+ goto out;
+
+ if (*dst_len < C1_len + src_len + TEE_SM3_HASH_SIZE) {
+ *dst_len = C1_len + src_len + TEE_SM3_HASH_SIZE;
+ res = TEE_ERROR_SHORT_BUFFER;
+ goto out;
+ }
+
+ /* C2 */
+ for (i = 0; i < src_len; i++)
+ dst[i + C1_len] = src[i] ^ t[i];
+
+ /* C3 */
+ res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SM3);
+ if (res)
+ goto out;
+ res = crypto_hash_init(ctx);
+ if (res)
+ goto out;
+ res = crypto_hash_update(ctx, x2y2, SM2_INT_SIZE_BYTES);
+ if (res)
+ goto out;
+ res = crypto_hash_update(ctx, src, src_len);
+ if (res)
+ goto out;
+ res = crypto_hash_update(ctx, x2y2 + SM2_INT_SIZE_BYTES,
+ SM2_INT_SIZE_BYTES);
+ if (res)
+ goto out;
+ res = crypto_hash_final(ctx, dst + C1_len + src_len, TEE_SM3_HASH_SIZE);
+ if (res)
+ goto out;
+
+ *dst_len = C1_len + src_len + TEE_SM3_HASH_SIZE;
+out:
+ crypto_hash_free_ctx(ctx);
+ free(t);
+ mbedtls_ecp_point_free(&x2y2p);
+ mbedtls_ecp_point_free(&PB);
+ mbedtls_ecp_point_free(&C1);
+ return res;
+}
diff --git a/lib/libmbedtls/core/sm2-pke.h b/lib/libmbedtls/core/sm2-pke.h
new file mode 100644
index 0000000..7e8d013
--- /dev/null
+++ b/lib/libmbedtls/core/sm2-pke.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2021 Huawei Technologies Co., Ltd
+ */
+
+#ifndef _SM2_PKE_H_
+
+#include <crypto/crypto.h>
+#include <stdint.h>
+#include <tee_api_types.h>
+
+TEE_Result sm2_mbedtls_pke_encrypt(struct ecc_public_key *key,
+ const uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t *dst_len);
+
+TEE_Result sm2_mbedtls_pke_decrypt(struct ecc_keypair *key, const uint8_t *src,
+ size_t src_len, uint8_t *dst,
+ size_t *dst_len);
+#endif /* _SM2_PKE_H_ */
diff --git a/lib/libmbedtls/core/sub.mk b/lib/libmbedtls/core/sub.mk
index f3b953d..b04dc23 100644
--- a/lib/libmbedtls/core/sub.mk
+++ b/lib/libmbedtls/core/sub.mk
@@ -1,3 +1,4 @@
+srcs-y += mbed_helpers.c
srcs-y += tomcrypt.c
srcs-$(call cfg-one-enabled, CFG_CRYPTO_MD5 CFG_CRYPTO_SHA1 CFG_CRYPTO_SHA224 \
CFG_CRYPTO_SHA256 CFG_CRYPTO_SHA384 \
@@ -26,3 +27,6 @@
srcs-$(CFG_CRYPTO_RSA) += rsa.c
srcs-$(CFG_CRYPTO_DH) += dh.c
srcs-$(CFG_CRYPTO_ECC) += ecc.c
+srcs-$(CFG_CRYPTO_SM2_DSA) += sm2-dsa.c
+srcs-$(CFG_CRYPTO_SM2_KEP) += sm2-kep.c
+srcs-$(CFG_CRYPTO_SM2_PKE) += sm2-pke.c
diff --git a/lib/libmbedtls/include/mbedtls_config_kernel.h b/lib/libmbedtls/include/mbedtls_config_kernel.h
index 51a78f3..cd4d975 100644
--- a/lib/libmbedtls/include/mbedtls_config_kernel.h
+++ b/lib/libmbedtls/include/mbedtls_config_kernel.h
@@ -111,6 +111,10 @@
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECDH_LEGACY_CONTEXT
+#if defined(CFG_CRYPTO_DSA) || defined(CFG_CRYPTO_SM2_PKE) || \
+ defined(CFG_CRYPTO_SM2_KEP)
+#define MBEDTLS_ECP_DP_SM2_ENABLED
+#endif
#endif
#endif /*CFG_CRYPTOLIB_NAME_mbedtls*/