core: crypto: add support for SM2 KEP
Adds SM2 Key Exchange Protocol [1] using LibTomCrypt. The TA interface
complies with the GlobalPlatform TEE Internal Core API version 1.2.
SM2 KEP is enabled with CFG_CRYPTO_SM2_KEP=y (default y) wich currently
requires that CFG_CRYPTOLIB_NAME=tomcrypt. An Mbed TLS implementation
could be added later if needed.
[1] http://www.gmbz.org.cn/main/postDetail.html?id=20180724110812
Signed-off-by: Jerome Forissier <jerome@forissier.org>
Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/core/crypto.mk b/core/crypto.mk
index 0fdbac6..4727045 100644
--- a/core/crypto.mk
+++ b/core/crypto.mk
@@ -42,6 +42,7 @@
ifeq ($(CFG_CRYPTOLIB_NAME),tomcrypt)
CFG_CRYPTO_SM2_PKE ?= y
CFG_CRYPTO_SM2_DSA ?= y
+CFG_CRYPTO_SM2_KEP ?= y
endif
ifeq ($(CFG_CRYPTOLIB_NAME)-$(CFG_CRYPTO_SM2_PKE),mbedtls-y)
$(error Error: CFG_CRYPTO_SM2_PKE=y requires CFG_CRYPTOLIB_NAME=tomcrypt)
@@ -49,6 +50,9 @@
ifeq ($(CFG_CRYPTOLIB_NAME)-$(CFG_CRYPTO_SM2_DSA),mbedtls-y)
$(error Error: CFG_CRYPTO_SM2_DSA=y requires CFG_CRYPTOLIB_NAME=tomcrypt)
endif
+ifeq ($(CFG_CRYPTOLIB_NAME)-$(CFG_CRYPTO_SM2_KEP),mbedtls-y)
+$(error Error: CFG_CRYPTO_SM2_KEP=y requires CFG_CRYPTOLIB_NAME=tomcrypt)
+endif
# Authenticated encryption
CFG_CRYPTO_CCM ?= y
@@ -142,6 +146,7 @@
# SM2 is Elliptic Curve Cryptography, it uses some generic ECC functions
$(eval $(call cryp-dep-one, SM2_PKE, ECC))
$(eval $(call cryp-dep-one, SM2_DSA, ECC))
+$(eval $(call cryp-dep-one, SM2_KEP, ECC))
###############################################################
# libtomcrypt (LTC) specifics, phase #1
@@ -174,6 +179,7 @@
core-ltc-vars += SIZE_OPTIMIZATION
core-ltc-vars += SM2_PKE
core-ltc-vars += SM2_DSA
+core-ltc-vars += SM2_KEP
# Assigned selected CFG_CRYPTO_xxx as _CFG_CORE_LTC_xxx
$(foreach v, $(core-ltc-vars), $(eval _CFG_CORE_LTC_$(v) := $(CFG_CRYPTO_$(v))))
_CFG_CORE_LTC_MPI := $(CFG_CORE_MBEDTLS_MPI)
diff --git a/core/crypto/crypto.c b/core/crypto/crypto.c
index 578514d..7a4f22c 100644
--- a/core/crypto/crypto.c
+++ b/core/crypto/crypto.c
@@ -733,3 +733,16 @@
return TEE_ERROR_NOT_IMPLEMENTED;
}
#endif /* !CFG_CRYPTO_SM2_DSA */
+#if !defined(CFG_CRYPTO_SM2_KEP)
+TEE_Result crypto_acipher_sm2_kep_derive(struct ecc_keypair *my_key __unused,
+ struct ecc_keypair *my_eph_key
+ __unused,
+ struct ecc_public_key *peer_key
+ __unused,
+ struct ecc_public_key *peer_eph_key
+ __unused,
+ struct sm2_kep_parms *p __unused)
+{
+ return TEE_ERROR_NOT_IMPLEMENTED;
+}
+#endif
diff --git a/core/include/crypto/crypto.h b/core/include/crypto/crypto.h
index e913875..7f9b14a 100644
--- a/core/include/crypto/crypto.h
+++ b/core/include/crypto/crypto.h
@@ -252,6 +252,26 @@
const uint8_t *msg, size_t msg_len,
const uint8_t *sig, size_t sig_len);
+struct sm2_kep_parms {
+ uint8_t *out;
+ size_t out_len;
+ bool is_initiator;
+ const uint8_t *initiator_id;
+ size_t initiator_id_len;
+ const uint8_t *responder_id;
+ size_t responder_id_len;
+ const uint8_t *conf_in;
+ size_t conf_in_len;
+ uint8_t *conf_out;
+ size_t conf_out_len;
+};
+
+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);
+
/*
* Verifies a SHA-256 hash, doesn't require crypto_init() to be called in
* advance and has as few dependencies as possible.
diff --git a/core/lib/libtomcrypt/ecc.c b/core/lib/libtomcrypt/ecc.c
index 57632d2..97f6b39 100644
--- a/core/lib/libtomcrypt/ecc.c
+++ b/core/lib/libtomcrypt/ecc.c
@@ -129,7 +129,8 @@
size_bytes = 32;
name = "SM2";
if ((algo != 0) && (algo != TEE_ALG_SM2_PKE) &&
- (algo != TEE_ALG_SM2_DSA_SM3))
+ (algo != TEE_ALG_SM2_DSA_SM3) &&
+ (algo != TEE_ALG_SM2_KEP))
return TEE_ERROR_BAD_PARAMETERS;
break;
default:
diff --git a/core/lib/libtomcrypt/sm2-kep.c b/core/lib/libtomcrypt/sm2-kep.c
index 8e47ebd..12a25f8 100644
--- a/core/lib/libtomcrypt/sm2-kep.c
+++ b/core/lib/libtomcrypt/sm2-kep.c
@@ -440,4 +440,3 @@
ecc_free(<c_my_key);
return res;
}
-
diff --git a/core/tee/tee_svc_cryp.c b/core/tee/tee_svc_cryp.c
index 17d8dec..00c85de 100644
--- a/core/tee/tee_svc_cryp.c
+++ b/core/tee/tee_svc_cryp.c
@@ -339,7 +339,7 @@
{
.attr_id = TEE_ATTR_ECC_CURVE,
- .flags = TEE_TYPE_ATTR_REQUIRED,
+ .flags = TEE_TYPE_ATTR_REQUIRED | TEE_TYPE_ATTR_SIZE_INDICATOR,
.ops_index = ATTR_OPS_INDEX_VALUE,
RAW_DATA(struct ecc_public_key, curve)
},
@@ -502,6 +502,14 @@
PROP(TEE_TYPE_SM2_PKE_KEYPAIR, 1, 256, 256,
sizeof(struct ecc_keypair),
tee_cryp_obj_ecc_keypair_attrs),
+
+ PROP(TEE_TYPE_SM2_KEP_PUBLIC_KEY, 1, 256, 256,
+ sizeof(struct ecc_public_key),
+ tee_cryp_obj_ecc_pub_key_attrs),
+
+ PROP(TEE_TYPE_SM2_KEP_KEYPAIR, 1, 256, 256,
+ sizeof(struct ecc_keypair),
+ tee_cryp_obj_ecc_keypair_attrs),
};
struct attr_ops {
@@ -1159,6 +1167,9 @@
} else if (o->info.objectType == TEE_TYPE_SM2_PKE_PUBLIC_KEY) {
if (src->info.objectType != TEE_TYPE_SM2_PKE_KEYPAIR)
return TEE_ERROR_BAD_PARAMETERS;
+ } else if (o->info.objectType == TEE_TYPE_SM2_KEP_PUBLIC_KEY) {
+ if (src->info.objectType != TEE_TYPE_SM2_KEP_KEYPAIR)
+ return TEE_ERROR_BAD_PARAMETERS;
} else {
return TEE_ERROR_BAD_PARAMETERS;
}
@@ -1249,6 +1260,7 @@
case TEE_TYPE_ECDH_PUBLIC_KEY:
case TEE_TYPE_SM2_DSA_PUBLIC_KEY:
case TEE_TYPE_SM2_PKE_PUBLIC_KEY:
+ case TEE_TYPE_SM2_KEP_PUBLIC_KEY:
res = crypto_acipher_alloc_ecc_public_key(o->attr,
max_key_size);
break;
@@ -1256,6 +1268,7 @@
case TEE_TYPE_ECDH_KEYPAIR:
case TEE_TYPE_SM2_DSA_KEYPAIR:
case TEE_TYPE_SM2_PKE_KEYPAIR:
+ case TEE_TYPE_SM2_KEP_KEYPAIR:
res = crypto_acipher_alloc_ecc_keypair(o->attr, max_key_size);
break;
default:
@@ -2052,6 +2065,12 @@
else
req_key_type = TEE_TYPE_SM2_DSA_KEYPAIR;
break;
+#if defined(CFG_CRYPTO_SM2_KEP)
+ case TEE_MAIN_ALGO_SM2_KEP:
+ req_key_type = TEE_TYPE_SM2_KEP_KEYPAIR;
+ req_key_type2 = TEE_TYPE_SM2_KEP_PUBLIC_KEY;
+ break;
+#endif
#if defined(CFG_CRYPTO_HKDF)
case TEE_MAIN_ALGO_HKDF:
req_key_type = TEE_TYPE_HKDF_IKM;
@@ -2174,8 +2193,13 @@
res = TEE_ERROR_BAD_PARAMETERS;
break;
case TEE_OPERATION_KEY_DERIVATION:
- if (key1 == 0 || key2 != 0)
- res = TEE_ERROR_BAD_PARAMETERS;
+ if (algo == TEE_ALG_SM2_KEP) {
+ if (key1 == 0 || key2 == 0)
+ res = TEE_ERROR_BAD_PARAMETERS;
+ } else {
+ if (key1 == 0 || key2 != 0)
+ res = TEE_ERROR_BAD_PARAMETERS;
+ }
break;
default:
res = TEE_ERROR_NOT_SUPPORTED;
@@ -2756,6 +2780,110 @@
}
#endif
+#if defined(CFG_CRYPTO_SM2_KEP)
+static TEE_Result get_sm2_kep_params(const TEE_Attribute *params,
+ uint32_t param_count,
+ struct ecc_public_key *peer_key,
+ struct ecc_public_key *peer_eph_key,
+ struct sm2_kep_parms *kep_parms)
+{
+ TEE_Result res = TEE_ERROR_GENERIC;
+ size_t n;
+ enum {
+ IS_INITIATOR,
+ PEER_KEY_X,
+ PEER_KEY_Y,
+ PEER_EPH_KEY_X,
+ PEER_EPH_KEY_Y,
+ INITIATOR_ID,
+ RESPONDER_ID,
+ };
+ uint8_t mandatory = BIT(IS_INITIATOR) | BIT(PEER_KEY_X) |
+ BIT(PEER_KEY_Y) | BIT(PEER_EPH_KEY_X) | BIT(PEER_EPH_KEY_Y) |
+ BIT(INITIATOR_ID) | BIT(RESPONDER_ID);
+ uint8_t found = 0;
+
+ res = crypto_acipher_alloc_ecc_public_key(peer_key, 256);
+ if (res)
+ goto out;
+
+ res = crypto_acipher_alloc_ecc_public_key(peer_eph_key, 256);
+ if (res)
+ goto out;
+
+ peer_key->curve = TEE_ECC_CURVE_SM2;
+ peer_eph_key->curve = TEE_ECC_CURVE_SM2;
+
+ for (n = 0; n < param_count; n++) {
+ const TEE_Attribute *p = ¶ms[n];
+
+ switch (p->attributeID) {
+ case TEE_ATTR_SM2_KEP_USER:
+ kep_parms->is_initiator = !p->content.value.a;
+ found |= BIT(IS_INITIATOR);
+ break;
+ case TEE_ATTR_ECC_PUBLIC_VALUE_X:
+ crypto_bignum_bin2bn(p->content.ref.buffer,
+ p->content.ref.length,
+ peer_key->x);
+ found |= BIT(PEER_KEY_X);
+ break;
+ case TEE_ATTR_ECC_PUBLIC_VALUE_Y:
+ crypto_bignum_bin2bn(p->content.ref.buffer,
+ p->content.ref.length,
+ peer_key->y);
+ found |= BIT(PEER_KEY_Y);
+ break;
+ case TEE_ATTR_ECC_EPHEMERAL_PUBLIC_VALUE_X:
+ crypto_bignum_bin2bn(p->content.ref.buffer,
+ p->content.ref.length,
+ peer_eph_key->x);
+ found |= BIT(PEER_EPH_KEY_X);
+ break;
+ case TEE_ATTR_ECC_EPHEMERAL_PUBLIC_VALUE_Y:
+ crypto_bignum_bin2bn(p->content.ref.buffer,
+ p->content.ref.length,
+ peer_eph_key->y);
+ found |= BIT(PEER_EPH_KEY_Y);
+ break;
+ case TEE_ATTR_SM2_ID_INITIATOR:
+ kep_parms->initiator_id = p->content.ref.buffer;
+ kep_parms->initiator_id_len = p->content.ref.length;
+ found |= BIT(INITIATOR_ID);
+ break;
+ case TEE_ATTR_SM2_ID_RESPONDER:
+ kep_parms->responder_id = p->content.ref.buffer;
+ kep_parms->responder_id_len = p->content.ref.length;
+ found |= BIT(RESPONDER_ID);
+ break;
+ case TEE_ATTR_SM2_KEP_CONFIRMATION_IN:
+ kep_parms->conf_in = p->content.ref.buffer;
+ kep_parms->conf_in_len = p->content.ref.length;
+ break;
+ case TEE_ATTR_SM2_KEP_CONFIRMATION_OUT:
+ kep_parms->conf_out = p->content.ref.buffer;
+ kep_parms->conf_out_len = p->content.ref.length;
+ break;
+ default:
+ /* Unexpected attribute */
+ res = TEE_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+ }
+
+ if ((found & mandatory) != mandatory) {
+ res = TEE_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+
+ return TEE_SUCCESS;
+out:
+ crypto_acipher_free_ecc_public_key(peer_key);
+ crypto_acipher_free_ecc_public_key(peer_eph_key);
+ return res;
+}
+#endif
+
TEE_Result syscall_cryp_derive_key(unsigned long state,
const struct utee_attribute *usr_params,
unsigned long param_count, unsigned long derived_key)
@@ -2995,6 +3123,42 @@
}
}
#endif
+#if defined(CFG_CRYPTO_SM2_KEP)
+ else if (cs->algo == TEE_ALG_SM2_KEP) {
+ struct ecc_public_key peer_eph_key = { };
+ struct ecc_public_key peer_key = { };
+ struct sm2_kep_parms kep_parms = {
+ .out = (uint8_t *)(sk + 1),
+ .out_len = so->info.maxKeySize,
+ };
+ struct tee_obj *ko2 = NULL;
+
+ res = tee_obj_get(utc, cs->key2, &ko2);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ res = get_sm2_kep_params(params, param_count, &peer_key,
+ &peer_eph_key, &kep_parms);
+ if (res != TEE_SUCCESS)
+ goto out;
+
+ /*
+ * key1 is our private keypair, key2 is our ephemeral public key
+ */
+ res = crypto_acipher_sm2_kep_derive(ko->attr, /* key1 */
+ ko2->attr, /* key2 */
+ &peer_key, &peer_eph_key,
+ &kep_parms);
+
+ if (res == TEE_SUCCESS) {
+ sk->key_size = kep_parms.out_len;
+ so->info.handleFlags |= TEE_HANDLE_FLAG_INITIALIZED;
+ set_attribute(so, type_props, TEE_ATTR_SECRET_VALUE);
+ }
+ crypto_acipher_free_ecc_public_key(&peer_key);
+ crypto_acipher_free_ecc_public_key(&peer_eph_key);
+ }
+#endif
else
res = TEE_ERROR_NOT_SUPPORTED;
diff --git a/lib/libutee/include/tee_api_defines.h b/lib/libutee/include/tee_api_defines.h
index fa64d3a..6ebd34e 100644
--- a/lib/libutee/include/tee_api_defines.h
+++ b/lib/libutee/include/tee_api_defines.h
@@ -163,6 +163,7 @@
#define TEE_ALG_DSA_SHA256 0x70004131
#define TEE_ALG_SM2_DSA_SM3 0x70006045
#define TEE_ALG_DH_DERIVE_SHARED_SECRET 0x80000032
+#define TEE_ALG_SM2_KEP 0x60000045
#define TEE_ALG_MD5 0x50000001
#define TEE_ALG_SHA1 0x50000002
#define TEE_ALG_SHA224 0x50000003
@@ -224,6 +225,8 @@
#define TEE_TYPE_ECDH_KEYPAIR 0xA1000042
#define TEE_TYPE_SM2_DSA_PUBLIC_KEY 0xA0000045
#define TEE_TYPE_SM2_DSA_KEYPAIR 0xA1000045
+#define TEE_TYPE_SM2_KEP_PUBLIC_KEY 0xA0000046
+#define TEE_TYPE_SM2_KEP_KEYPAIR 0xA1000046
#define TEE_TYPE_SM2_PKE_PUBLIC_KEY 0xA0000047
#define TEE_TYPE_SM2_PKE_KEYPAIR 0xA1000047
#define TEE_TYPE_GENERIC_SECRET 0xA0000000
@@ -258,6 +261,13 @@
#define TEE_ATTR_ECC_PUBLIC_VALUE_Y 0xD0000241
#define TEE_ATTR_ECC_PRIVATE_VALUE 0xC0000341
#define TEE_ATTR_ECC_CURVE 0xF0000441
+#define TEE_ATTR_SM2_ID_INITIATOR 0xD0000446
+#define TEE_ATTR_SM2_ID_RESPONDER 0xD0000546
+#define TEE_ATTR_SM2_KEP_USER 0xF0000646
+#define TEE_ATTR_SM2_KEP_CONFIRMATION_IN 0xD0000746
+#define TEE_ATTR_SM2_KEP_CONFIRMATION_OUT 0xD0000846
+#define TEE_ATTR_ECC_EPHEMERAL_PUBLIC_VALUE_X 0xD0000946 /* Missing in 1.2.1 */
+#define TEE_ATTR_ECC_EPHEMERAL_PUBLIC_VALUE_Y 0xD0000A46 /* Missing in 1.2.1 */
#define TEE_ATTR_BIT_PROTECTED (1 << 28)
#define TEE_ATTR_BIT_VALUE (1 << 29)
diff --git a/lib/libutee/include/utee_defines.h b/lib/libutee/include/utee_defines.h
index e442cb3..7aa1c84 100644
--- a/lib/libutee/include/utee_defines.h
+++ b/lib/libutee/include/utee_defines.h
@@ -31,6 +31,7 @@
#define TEE_MAIN_ALGO_ECDSA 0x41
#define TEE_MAIN_ALGO_ECDH 0x42
#define TEE_MAIN_ALGO_SM2_DSA_SM3 0x45 /* Not in v1.2 spec */
+#define TEE_MAIN_ALGO_SM2_KEP 0x46 /* Not in v1.2 spec */
#define TEE_MAIN_ALGO_SM2_PKE 0x47 /* Not in v1.2 spec */
#define TEE_MAIN_ALGO_HKDF 0xC0 /* OP-TEE extension */
#define TEE_MAIN_ALGO_CONCAT_KDF 0xC1 /* OP-TEE extension */
@@ -53,6 +54,8 @@
{
if (algo == TEE_ALG_SM2_PKE)
return TEE_OPERATION_ASYMMETRIC_CIPHER;
+ if (algo == TEE_ALG_SM2_KEP)
+ return TEE_OPERATION_KEY_DERIVATION;
return (algo >> 28) & 0xF; /* Bits [31:28] */
}
@@ -64,6 +67,8 @@
switch (algo) {
case TEE_ALG_SM2_PKE:
return TEE_MAIN_ALGO_SM2_PKE;
+ case TEE_ALG_SM2_KEP:
+ return TEE_MAIN_ALGO_SM2_KEP;
default:
break;
}
diff --git a/lib/libutee/tee_api_operations.c b/lib/libutee/tee_api_operations.c
index e8a9efb..56ea2e1 100644
--- a/lib/libutee/tee_api_operations.c
+++ b/lib/libutee/tee_api_operations.c
@@ -46,7 +46,7 @@
if (!operation)
TEE_Panic(0);
- if (algorithm == TEE_ALG_AES_XTS)
+ if (algorithm == TEE_ALG_AES_XTS || algorithm == TEE_ALG_SM2_KEP)
handle_state = TEE_HANDLE_FLAG_EXPECT_TWO_KEYS;
/* Check algorithm max key size */
@@ -90,6 +90,12 @@
return TEE_ERROR_NOT_SUPPORTED;
break;
+ case TEE_ALG_SM2_KEP:
+ /* Two 256-bit keys */
+ if (maxKeySize != 512)
+ return TEE_ERROR_NOT_SUPPORTED;
+ break;
+
case TEE_ALG_ECDSA_P384:
case TEE_ALG_ECDH_P384:
if (maxKeySize != 384)
@@ -218,6 +224,7 @@
case TEE_ALG_CONCAT_KDF_SHA384_DERIVE_KEY:
case TEE_ALG_CONCAT_KDF_SHA512_DERIVE_KEY:
case TEE_ALG_PBKDF2_HMAC_SHA1_DERIVE_KEY:
+ case TEE_ALG_SM2_KEP:
if (mode != TEE_MODE_DERIVE)
return TEE_ERROR_NOT_SUPPORTED;
with_private_key = true;
@@ -623,7 +630,7 @@
goto out;
}
- /* Two keys flag expected (TEE_ALG_AES_XTS only) */
+ /* Two keys flag expected (TEE_ALG_AES_XTS and TEE_ALG_SM2_KEP only) */
if ((operation->info.handleState & TEE_HANDLE_FLAG_EXPECT_TWO_KEYS) ==
0) {
res = TEE_ERROR_BAD_PARAMETERS;
@@ -658,11 +665,10 @@
}
/*
- * AES-XTS (the only multi key algorithm supported, requires the
- * keys to be of equal size.
+ * All the multi key algorithm currently supported requires the keys to
+ * be of equal size.
*/
- if (operation->info.algorithm == TEE_ALG_AES_XTS &&
- key_info1.keySize != key_info2.keySize) {
+ if (key_info1.keySize != key_info2.keySize) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
@@ -686,7 +692,6 @@
res = TEE_CopyObjectAttributes1(operation->key1, key1);
if (res != TEE_SUCCESS)
goto out;
-
res = TEE_CopyObjectAttributes1(operation->key2, key2);
if (res != TEE_SUCCESS) {
if (res == TEE_ERROR_CORRUPT_OBJECT)