diff --git a/ecdh/Android.mk b/ecdh/Android.mk new file mode 100644 index 0000000..c096f53 --- /dev/null +++ b/ecdh/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_CFLAGS += -DANDROID_BUILD +LOCAL_CFLAGS += -Wall + +LOCAL_SRC_FILES += host/main.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include + +LOCAL_SHARED_LIBRARIES := libteec +LOCAL_MODULE := optee_example_ecdh +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional +include $(BUILD_EXECUTABLE) + +include $(LOCAL_PATH)/ta/Android.mk diff --git a/ecdh/CMakeLists.txt b/ecdh/CMakeLists.txt new file mode 100644 index 0000000..17a2013 --- /dev/null +++ b/ecdh/CMakeLists.txt @@ -0,0 +1,13 @@ +project (optee_example_ecdh C) + +set (SRC host/main.c) + +add_executable (${PROJECT_NAME} ${SRC}) + +target_include_directories(${PROJECT_NAME} + PRIVATE ta/include + PRIVATE include) + +target_link_libraries (${PROJECT_NAME} PRIVATE teec) + +install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/ecdh/Makefile b/ecdh/Makefile new file mode 100644 index 0000000..dfa4f8b --- /dev/null +++ b/ecdh/Makefile @@ -0,0 +1,15 @@ +export V ?= 0 + +# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE +HOST_CROSS_COMPILE ?= $(CROSS_COMPILE) +TA_CROSS_COMPILE ?= $(CROSS_COMPILE) + +.PHONY: all +all: + $(MAKE) -C host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables + $(MAKE) -C ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS="" + +.PHONY: clean +clean: + $(MAKE) -C host clean + $(MAKE) -C ta clean diff --git a/ecdh/host/Makefile b/ecdh/host/Makefile new file mode 100644 index 0000000..f5861bd --- /dev/null +++ b/ecdh/host/Makefile @@ -0,0 +1,28 @@ +CC ?= $(CROSS_COMPILE)gcc +LD ?= $(CROSS_COMPILE)ld +AR ?= $(CROSS_COMPILE)ar +NM ?= $(CROSS_COMPILE)nm +OBJCOPY ?= $(CROSS_COMPILE)objcopy +OBJDUMP ?= $(CROSS_COMPILE)objdump +READELF ?= $(CROSS_COMPILE)readelf + +OBJS = main.o + +CFLAGS += -Wall -I../ta/include -I./include +CFLAGS += -I$(TEEC_EXPORT)/include +LDADD += -lteec -L$(TEEC_EXPORT)/lib + +BINARY = optee_example_ecdh + +.PHONY: all +all: $(BINARY) + +$(BINARY): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $< $(LDADD) + +.PHONY: clean +clean: + rm -f $(OBJS) $(BINARY) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/ecdh/host/main.c b/ecdh/host/main.c new file mode 100644 index 0000000..50da0dc --- /dev/null +++ b/ecdh/host/main.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2025, Advanced Micro Devices, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +static void hexdump(const void *p, size_t len) +{ + const unsigned char *b = (const unsigned char *)p; + + for (size_t i = 0; i < len; i++) { + printf("%02x", b[i]); + if ((i + 1) % 32 == 0) + printf("\n"); + } + if (len % 32) + printf("\n"); +} + +int main(void) +{ + TEEC_Result res = TEEC_ERROR_GENERIC; + TEEC_Context ctx = {0}; + TEEC_Session sess = {0}; + TEEC_Operation op = {0}; + TEEC_UUID uuid = TA_ECDH_UUID; + uint32_t err_origin = 0; + size_t secret_len = 0; + uint32_t curve = TA_ECDH_ECC_CURVE_NIST_P384; + uint8_t secret[ECDH_BUF_BYTES]; + + res = TEEC_InitializeContext(NULL, &ctx); + if (res != TEEC_SUCCESS) + errx(1, "TEEC_InitializeContext failed with code 0x%x", res); + + res = TEEC_OpenSession(&ctx, &sess, &uuid, TEEC_LOGIN_PUBLIC, NULL, + NULL, &err_origin); + if (res != TEEC_SUCCESS) + errx(1, "TEEC_OpenSession failed 0x%x origin 0x%x", + res, err_origin); + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, + TEEC_NONE, + TEEC_NONE, + TEEC_MEMREF_TEMP_OUTPUT); + + op.params[0].value.a = curve; /* IN: curve id */ + op.params[0].value.b = 0; /* OUT: secret len */ + op.params[3].tmpref.buffer = secret; /* OUT buffer for secret */ + op.params[3].tmpref.size = sizeof(secret); + + res = TEEC_InvokeCommand(&sess, TA_ECDH_CMD_DERIVE_SELFTEST, + &op, &err_origin); + if (res != TEEC_SUCCESS) + errx(1, "Invoke TA_ECDH_CMD_DERIVE_SELFTEST failed 0x%x origin 0x%x", + res, err_origin); + + secret_len = op.params[0].value.b; + + printf("ECDH shared secret (%zu bytes) on curve id %u:\n", + secret_len, curve); + hexdump(secret, secret_len); + + TEEC_CloseSession(&sess); + TEEC_FinalizeContext(&ctx); + return 0; +} diff --git a/ecdh/ta/Android.mk b/ecdh/ta/Android.mk new file mode 100644 index 0000000..7904968 --- /dev/null +++ b/ecdh/ta/Android.mk @@ -0,0 +1,3 @@ +LOCAL_PATH := $(call my-dir) +local_module := 50c82425-94da-4072-a3e0-58ef063767c0.ta +include $(BUILD_OPTEE_MK) diff --git a/ecdh/ta/Makefile b/ecdh/ta/Makefile new file mode 100644 index 0000000..d576fa1 --- /dev/null +++ b/ecdh/ta/Makefile @@ -0,0 +1,13 @@ +CFG_TEE_TA_LOG_LEVEL ?= 4 +CFG_TA_OPTEE_CORE_API_COMPAT_1_1=y + +# The UUID for the Trusted Application +BINARY=50c82425-94da-4072-a3e0-58ef063767c0 + +-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk + +ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) +clean: + @echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' + @echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' +endif diff --git a/ecdh/ta/ecdh_ta.c b/ecdh/ta/ecdh_ta.c new file mode 100644 index 0000000..b8a1bab --- /dev/null +++ b/ecdh/ta/ecdh_ta.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2025, Advanced Micro Devices, Inc. All rights reserved. + */ + +#include +#include + +#include + +#define CHECK(res, msg) \ + do { if ((res) != TEE_SUCCESS) { EMSG(msg); TEE_Panic((res)); } } while (0) + +static uint32_t curve_bits(uint32_t curve_id) +{ + switch (curve_id) { + case TEE_ECC_CURVE_NIST_P192: + return 192; + case TEE_ECC_CURVE_NIST_P224: + return 224; + case TEE_ECC_CURVE_NIST_P256: + return 256; + case TEE_ECC_CURVE_NIST_P384: + return 384; + default: + return 0; + } +} + +static uint32_t select_curve(uint32_t curve_id) +{ + switch (curve_id) { + case TA_ECDH_ECC_CURVE_NIST_P192: + return TEE_ECC_CURVE_NIST_P192; + case TA_ECDH_ECC_CURVE_NIST_P224: + return TEE_ECC_CURVE_NIST_P224; + case TA_ECDH_ECC_CURVE_NIST_P256: + return TEE_ECC_CURVE_NIST_P256; + case TA_ECDH_ECC_CURVE_NIST_P384: + return TEE_ECC_CURVE_NIST_P384; + default: + return TEE_CRYPTO_ELEMENT_NONE; + } + +} + +static TEE_Result gen_ec_keypair(TEE_ObjectHandle *key, uint32_t curve) +{ + TEE_Result res = TEE_ERROR_GENERIC; + uint32_t bits = curve_bits(curve); + TEE_Attribute attrs[1] = { }; + + if (!bits) + return TEE_ERROR_BAD_PARAMETERS; + + res = TEE_AllocateTransientObject(TEE_TYPE_ECDH_KEYPAIR, bits, key); + if (res) + return res; + + TEE_InitValueAttribute(&attrs[0], TEE_ATTR_ECC_CURVE, curve, 0); + return TEE_GenerateKey(*key, bits, attrs, 1); +} + +static TEE_Result get_pub_xy(TEE_ObjectHandle key, + uint8_t *x, uint32_t *x_len, + uint8_t *y, uint32_t *y_len) +{ + TEE_Result res = TEE_ERROR_GENERIC; + + res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_ECC_PUBLIC_VALUE_X, + x, x_len); + if (res) + return res; + res = TEE_GetObjectBufferAttribute(key, TEE_ATTR_ECC_PUBLIC_VALUE_Y, + y, y_len); + return res; +} + +static TEE_Result derive_secret(TEE_ObjectHandle my_key, + uint8_t *peer_x, uint32_t peer_x_len, + uint8_t *peer_y, uint32_t peer_y_len, + uint8_t *secret, uint32_t *secret_len, + uint32_t curve) +{ + TEE_Result res = TEE_ERROR_GENERIC; + uint32_t bits = curve_bits(curve); + TEE_OperationHandle op = TEE_HANDLE_NULL; + TEE_ObjectHandle derived = TEE_HANDLE_NULL; + TEE_Attribute params[2] = { }; + + if (!bits) + return TEE_ERROR_BAD_PARAMETERS; + + /* Allocate operation for ECDH derive */ + res = TEE_AllocateOperation(&op, TEE_ALG_ECDH_DERIVE_SHARED_SECRET, + TEE_MODE_DERIVE, bits); + if (res) + return res; + + res = TEE_SetOperationKey(op, my_key); + if (res) + goto out; + + /* Provide peer public coordinates as derivation parameters */ + TEE_InitRefAttribute(¶ms[0], TEE_ATTR_ECC_PUBLIC_VALUE_X, + peer_x, peer_x_len); + TEE_InitRefAttribute(¶ms[1], TEE_ATTR_ECC_PUBLIC_VALUE_Y, + peer_y, peer_y_len); + + /* Derived secret goes into a GENERIC_SECRET transient object */ + res = TEE_AllocateTransientObject(TEE_TYPE_GENERIC_SECRET, bits, &derived); + if (res) + goto out; + + TEE_DeriveKey(op, params, 2, derived); + + /* Fetch the raw shared secret bytes */ + res = TEE_GetObjectBufferAttribute(derived, TEE_ATTR_SECRET_VALUE, + secret, secret_len); + +out: + TEE_FreeTransientObject(derived); + TEE_FreeOperation(op); + return res; +} + +static TEE_Result cmd_ecdh_selftest(uint32_t param_types, TEE_Param params[4]) +{ + TEE_Result res = TEE_ERROR_GENERIC; + const uint32_t exp_pt = + TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INOUT, /* curve id in,secret len out */ + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_MEMREF_OUTPUT); /* shared secret out */ + + uint32_t curve_ta = params[0].value.a; + uint32_t curve = select_curve(curve_ta); + uint32_t bits = curve_bits(curve); + uint8_t a_x[ECDH_BUF_BYTES] = {0}; + uint8_t a_y[ECDH_BUF_BYTES] = {0}; + uint8_t b_x[ECDH_BUF_BYTES] = {0}; + uint8_t b_y[ECDH_BUF_BYTES] = {0}; + uint32_t a_x_len = ECDH_BUF_BYTES; + uint32_t a_y_len = ECDH_BUF_BYTES; + uint32_t b_x_len = ECDH_BUF_BYTES; + uint32_t b_y_len = ECDH_BUF_BYTES; + uint8_t s_a[ECDH_BUF_BYTES] = {0}; + uint8_t s_b[ECDH_BUF_BYTES] = {0}; + uint32_t s_a_len = ECDH_BUF_BYTES; + uint32_t s_b_len = ECDH_BUF_BYTES; + TEE_ObjectHandle key_a = TEE_HANDLE_NULL; + TEE_ObjectHandle key_b = TEE_HANDLE_NULL; + + if (param_types != exp_pt) + return TEE_ERROR_BAD_PARAMETERS; + + DMSG("curve = %"PRIu32, curve); + DMSG("bits = %"PRIu32, bits); + + if (!bits || curve == TEE_CRYPTO_ELEMENT_NONE) + return TEE_ERROR_BAD_PARAMETERS; + + res = gen_ec_keypair(&key_a, curve); + CHECK(res, "gen key A"); + + res = gen_ec_keypair(&key_b, curve); + CHECK(res, "gen key B"); + + res = get_pub_xy(key_a, a_x, &a_x_len, a_y, &a_y_len); + CHECK(res, "get A pub"); + + res = get_pub_xy(key_b, b_x, &b_x_len, b_y, &b_y_len); + CHECK(res, "get B pub"); + + res = derive_secret(key_a, b_x, b_x_len, b_y, b_y_len, s_a, &s_a_len, curve); + CHECK(res, "derive A"); + + res = derive_secret(key_b, a_x, a_x_len, a_y, a_y_len, s_b, &s_b_len, curve); + CHECK(res, "derive B"); + + /* They must be identical in length and value */ + if (s_a_len != s_b_len || TEE_MemCompare(s_a, s_b, s_a_len) != 0) { + res = TEE_ERROR_GENERIC; + goto out; + } + + /* Copy to output */ + if (params[3].memref.size < s_a_len) { + /* Tell host needed size */ + params[0].value.b = s_a_len; + res = TEE_ERROR_SHORT_BUFFER; + goto out; + } + + TEE_MemMove(params[3].memref.buffer, s_a, s_a_len); + params[0].value.b = s_a_len; + params[3].memref.size = s_a_len; + res = TEE_SUCCESS; + +out: + TEE_FreeTransientObject(key_a); + TEE_FreeTransientObject(key_b); + return res; +} + +/* TA entry points */ + +TEE_Result TA_CreateEntryPoint(void) +{ + return TEE_SUCCESS; +} + +void TA_DestroyEntryPoint(void) +{ +} + +TEE_Result TA_OpenSessionEntryPoint(uint32_t pt __unused, + TEE_Param params[4] __unused, + void **ctx __unused) +{ + return TEE_SUCCESS; +} + +void TA_CloseSessionEntryPoint(void *ctx __unused) +{ +} + +TEE_Result TA_InvokeCommandEntryPoint(void *ctx __unused, uint32_t cmd_id, + uint32_t param_types, TEE_Param params[4]) +{ + switch (cmd_id) { + case TA_ECDH_CMD_DERIVE_SELFTEST: + return cmd_ecdh_selftest(param_types, params); + default: + return TEE_ERROR_BAD_PARAMETERS; + } +} diff --git a/ecdh/ta/include/ecdh_ta.h b/ecdh/ta/include/ecdh_ta.h new file mode 100644 index 0000000..f41e7ae --- /dev/null +++ b/ecdh/ta/include/ecdh_ta.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2025, Advanced Micro Devices, Inc. All rights reserved. + */ + +#ifndef __ECDH_TA_H__ +#define __ECDH_TA_H__ + +/* UUID of the ECDH example trusted application */ + +#define TA_ECDH_UUID \ + { 0x50c82425, 0x94da, 0x4072, \ + { 0xa3, 0xe0, 0x58, 0xef, 0x06, 0x37, 0x67, 0xc0 } } + +#define TA_ECDH_CMD_DERIVE_SELFTEST 0 +/* + * TA_ECDH_CMD_DERIVE_SELFTEST - Test EC keys generation and ECDH derivation + * + * in params[0].value.a EC curve ID (one of TA_ECDH_ECC_CURVE_*) + * out params[3].memref Generated shared secret key from ECDH + * + * Return TEE_SUCCESS upon success. + * Return TEE_ERROR_SHORT_BUFFER is output buffer is too short in which case + * size is provided output in param[3]memref.size) + * Return another compliant TEE_Result error code in case of failure. + */ + +#define TA_ECDH_ECC_CURVE_NIST_P192 0 +#define TA_ECDH_ECC_CURVE_NIST_P224 1 +#define TA_ECDH_ECC_CURVE_NIST_P256 2 +#define TA_ECDH_ECC_CURVE_NIST_P384 3 + +#define ECDH_MAX_BITS 521 +#define ECDH_MAX_BYTES ((ECDH_MAX_BITS + 7) / 8) +#define ECDH_BUF_BYTES (ECDH_MAX_BYTES + 14) + +#endif diff --git a/ecdh/ta/sub.mk b/ecdh/ta/sub.mk new file mode 100644 index 0000000..ae33971 --- /dev/null +++ b/ecdh/ta/sub.mk @@ -0,0 +1,2 @@ +global-incdirs-y += include +srcs-y += ecdh_ta.c diff --git a/ecdh/ta/user_ta_header_defines.h b/ecdh/ta/user_ta_header_defines.h new file mode 100644 index 0000000..5d31fe7 --- /dev/null +++ b/ecdh/ta/user_ta_header_defines.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2025, Advanced Micro Devices, Inc. All rights reserved. + */ + +#ifndef USER_TA_HEADER_DEFINES_H +#define USER_TA_HEADER_DEFINES_H + +#include + +#define TA_UUID TA_ECDH_UUID + +#define TA_FLAGS 0 + +/* Provisioned stack size */ +#define TA_STACK_SIZE (2 * 1024) + +/* Provisioned heap size for TEE_Malloc() and friends */ +#define TA_DATA_SIZE (32 * 1024) + +/* The gpd.ta.version property */ +#define TA_VERSION "1.0" + +/* The gpd.ta.description property */ +#define TA_DESCRIPTION "Example of TA using an ECDH sequence" + +#endif /*USER_TA_HEADER_DEFINES_H*/