diff --git a/test/CA/libqca/Makefile b/test/CA/libqca/Makefile index 51d51122f804e4fb82e7be698a59743c0bd5df31..bf50e8206f1f7c931f0bd416d1c30daaec041112 100644 --- a/test/CA/libqca/Makefile +++ b/test/CA/libqca/Makefile @@ -11,6 +11,12 @@ LIB_SOURCES := src/ra_operate_api.c LIB_SOURCES += $(ITRUSTEE_BUILD_PATH)/src/CA/libteec_adaptor.c LIB_CFLAGS += -Werror -Wall -Wextra -fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIC -D_FORTIFY_SOURCE=2 -O2 +ifeq ($(TARGET_HOST_QCA), y) +LIB_CFLAGS += -DHOST_QCA +endif +ifeq ($(TARGET_CONTAINER_QCA), y) +LIB_CFLAGS += -DCONTAINER_QCA +endif LIB_CFLAGS += -I$(ITRUSTEE_BUILD_PATH)/thirdparty/open_source/libboundscheck/include LIB_CFLAGS += -I$(ITRUSTEE_BUILD_PATH)/include/CA diff --git a/test/CA/libqca/include/ra_client_api.h b/test/CA/libqca/include/ra_client_api.h index dd793a33ff59086bf5192e3ea8524e719fb54544..afa9e074188426ea70410a4e4a304839686baefb 100644 --- a/test/CA/libqca/include/ra_client_api.h +++ b/test/CA/libqca/include/ra_client_api.h @@ -19,4 +19,9 @@ struct ra_buffer_data { }; TEEC_Result RemoteAttest(struct ra_buffer_data *in, struct ra_buffer_data *out); +#ifdef HOST_QCA +TEEC_Result RegisterContainer(struct ra_buffer_data *container_info, TEEC_Context *context, + TEEC_Session *session, uint32_t *origin); +#endif + #endif diff --git a/test/CA/libqca/src/ra_operate_api.c b/test/CA/libqca/src/ra_operate_api.c index 810f11fe9b576e884ec2f4df0630d849ac481882..fea5142d030158bbfbd6ba4e778b8aa0c025268d 100644 --- a/test/CA/libqca/src/ra_operate_api.c +++ b/test/CA/libqca/src/ra_operate_api.c @@ -17,11 +17,19 @@ #include "ra_log.h" #include "ra_client_api.h" +#ifdef CONTAINER_QCA +static const TEEC_UUID g_tee_qta_report_uuid = { + 0x4f84c0e0, 0x4c3f, 0x422f, { + 0x97, 0xdc, 0x14, 0xbf, 0xa2, 0x31, 0x4a, 0xd1 + } +}; +#else static const TEEC_UUID g_tee_qta_uuid = { 0xe08f7eca, 0xe875, 0x440e, { 0x9a, 0xb0, 0x5f, 0x38, 0x11, 0x36, 0xc6, 0x00 } }; +#endif static TEEC_Result set_remote_attest_out_data(TEEC_SharedMemory *shared_out, uint32_t out_size, struct ra_buffer_data *out) @@ -117,7 +125,11 @@ TEEC_Result RemoteAttest(struct ra_buffer_data *in, struct ra_buffer_data *out) TEEC_Context context = {0}; TEEC_Session session = {0}; TEEC_Operation operation = {0}; +#ifdef CONTAINER_QCA + TEEC_UUID uuid = g_tee_qta_report_uuid; +#else TEEC_UUID uuid = g_tee_qta_uuid; +#endif TEEC_Result result = TEEC_InitializeContext(NULL, &context); if (result != TEEC_SUCCESS) { @@ -145,3 +157,48 @@ cleanup_1: TEEC_FinalizeContext(&context); return result; } + +#ifdef HOST_QCA +static TEEC_Result container_info_ops(struct ra_buffer_data *info, uint32_t cmd, + TEEC_Context *context, TEEC_Session *session, uint32_t *origin) +{ + /* invoke command */ + TEEC_Operation operation = {0}; + operation.started = 1; + operation.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_PARTIAL_INPUT, TEEC_NONE, + TEEC_NONE, TEEC_NONE); + + TEEC_SharedMemory shared_info; + (void)memset_s(&shared_info, sizeof(shared_info), 0, sizeof(shared_info)); + shared_info.size = info->size; + shared_info.flags = TEEC_MEM_INPUT; + TEEC_Result result = TEEC_AllocateSharedMemory(context, &shared_info); + if (result != TEEC_SUCCESS) { + tloge("allocate shared container info failed, result = 0x%x.\n", result); + return result; + } + operation.params[0].memref.parent = &shared_info; + operation.params[0].memref.size = shared_info.size; + operation.params[0].memref.offset = 0; + (void)memcpy_s(shared_info.buffer, shared_info.size, info->buf, info->size); + + result = TEEC_InvokeCommand(session, cmd, &operation, origin); + if (result != TEEC_SUCCESS) + tloge("invoke command failed, result = 0x%x\n", result); + + TEEC_ReleaseSharedMemory(&shared_info); + return result; +} + +TEEC_Result RegisterContainer(struct ra_buffer_data *container_info, TEEC_Context *context, + TEEC_Session *session, uint32_t *origin) +{ + if (container_info == NULL || container_info->buf == NULL || + container_info->size == 0 || container_info->size > PARAMS_RESERVED_SIZE || + context == NULL || session == NULL || origin == NULL) { + tloge("invalid input\n"); + return TEEC_ERROR_BAD_PARAMETERS; + } + return container_info_ops(container_info, REGISTER_CONTAINER_CMD, context, session, origin); +} +#endif diff --git a/test/CA/libqca/src/ra_operate_api.h b/test/CA/libqca/src/ra_operate_api.h index 0269712a1c5cd721486ea5859196b2cd5948bd6e..4925409c00778a1c5975034c58e1fd8c6dc60949 100644 --- a/test/CA/libqca/src/ra_operate_api.h +++ b/test/CA/libqca/src/ra_operate_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved. * Licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: @@ -20,5 +20,8 @@ #define PARAMS_RESERVED_SIZE (0x2000) #define OUT_DATA_RESERVED_SIZE (0x3000) #define REMOTE_ATTEST_CMD (0x1001) +#ifdef HOST_QCA +#define REGISTER_CONTAINER_CMD (0x1002) +#endif #endif diff --git a/test/TA/qta/CMakeLists.txt b/test/TA/qta/CMakeLists.txt index e39ca5ef3a32785dbe0a2682ae944d770630ee14..0fa1cde9b563b09bd4aa7e0b4ba34646579ec4ec 100644 --- a/test/TA/qta/CMakeLists.txt +++ b/test/TA/qta/CMakeLists.txt @@ -13,6 +13,32 @@ include($ENV{ITRUSTEE_BUILD_PATH}/build/cmake/common.cmake) set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) set(CURRENT_TARGET_SO "combine") +if ("${TARGET_QTA_REPORT}" STREQUAL "y") + # qta-report in container + add_definitions(-DCONFIG_QTA_REPORT) + set(CONTAINER_INC + ${CMAKE_CURRENT_SOURCE_DIR}/src/container/ + ) + set(CONTAINER_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/container/container_verify.c + ) +elseif ("${TARGET_HOST_QTA}" STREQUAL "y") + # host_qta for container scenario + add_definitions(-DCONFIG_HOST_QTA) + set(CONTAINER_INC + ${CMAKE_CURRENT_SOURCE_DIR}/src/container/ + ) + set(CONTAINER_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/src/container/container_info.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/container/container_verify.c + ) +else () + # qta for itrustee(without container) + set(CONTAINER_INC "") + set(CONTAINER_SRC "") +endif() + + # enable check daa pairing using MIRACAL library # you should download the opensource library: miracl/core, copy its dir c/ into src/, and compile core.a # for instance: @@ -41,6 +67,7 @@ set(SDK_C_SOURCES src/tee_qta.c ${CJSON_SRC} ${DAA_PAIR_MIRACL_C_SRC} + ${CONTAINER_SRC} ) set(COMMON_INCLUDES @@ -48,6 +75,7 @@ set(COMMON_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/src/. ${CJSON_INC} ${DAA_PAIR_MIRACL_C_INC} + ${CONTAINER_INC} ) add_library(${CURRENT_TARGET_SO} SHARED ${SDK_C_SOURCES}) diff --git a/test/TA/qta/Makefile b/test/TA/qta/Makefile index cefce0662ba296872448839b77c809f31ab2fd2b..2f56fedfd2d28838fc99c0fb6445393b72cad498 100644 --- a/test/TA/qta/Makefile +++ b/test/TA/qta/Makefile @@ -20,12 +20,27 @@ SRC += ./src/daa/validate_akcert.c \ ./src/daa/daa_structure.c endif +MANIFEST := manifest.txt +ifeq ($(TARGET_QTA_REPORT), true) +INCLUDEDIR += -I./src/container +CFLAGS += -DCONFIG_QTA_REPORT +SRC += ./src/container/container_verify.c +MANIFEST := manifest-report.txt +else ifeq ($(TARGET_HOST_QTA), true) +INCLUDEDIR += -I./src/container +CFLAGS += -DCONFIG_HOST_QTA +SRC += ./src/container/container_verify.c \ + ./src/container/container_info.c +endif + # set target COBJS := $(SRC:%.c=%.o) TARGET = $(COBJS) sec_binary:combine + cp ./manifest/${MANIFEST} ./manifest.txt python3 -B ${SIGNTOOL_DIR}/signtool_v3.py ${CUR_DIR} ${CUR_DIR} --privateCfg ${SIGNTOOL_DIR}/config_cloud.ini + [ -f manifest.txt ] && rm -f manifest.txt combine: $(TARGET) $(LD) $(LDFLAGS) $(TARGET) $(EXTRAO) -o libcombine.so @@ -38,4 +53,5 @@ src/%.o: ./src/%.c $(CC) $(CFLAGS) $(INCLUDEDIR) -c $< -o $@ clean: - rm -f $(COBJS) *.so *.sec + rm -f *.so *.sec manifest.txt + find -name *.o | xargs rm -f diff --git a/test/TA/qta/config.sh b/test/TA/qta/config.sh index f1170b992fbd0872b5c1a2ffbbe4588867e96631..f4e27a17d5a4ca029e489e0133ad94d69e2d7737 100644 --- a/test/TA/qta/config.sh +++ b/test/TA/qta/config.sh @@ -7,9 +7,10 @@ export SOURCE_PATH=$(dirname $0) export ABS_SOURCE_PATH=$(cd ${SOURCE_PATH};pwd) export ITRUSTEE_BUILD_PATH=${ABS_SOURCE_PATH}/../../.. -#clean +# clean if [ "$#" -eq 1 ] && [ "$1"x = "clean"x ]; then rm -f *.o *.so *.sec + [ -f manifest.txt ] && rm -f manifest.txt if [ -d "cmake_build" ]; then rm -rf cmake_build echo "rm -rf cmake_build" @@ -17,6 +18,19 @@ if [ "$#" -eq 1 ] && [ "$1"x = "clean"x ]; then exit 0 fi +# set target +MANIFEST=manifest.txt +if [ "$#" -eq 1 ]; then + if [ "$1"x = "qta_report"x ]; then + TARGET=-DTARGET_QTA_REPORT=y + MANIFEST=manifest-report.txt + fi + if [ "$1"x = "host_qta"x ]; then + TARGET=-DTARGET_HOST_QTA=y + fi +fi +cp -f ./manifest/${MANIFEST} ./manifest.txt + echo "Cmake compile TA begin" if [ -d "cmake_build" ]; then rm -rf cmake_build @@ -26,9 +40,10 @@ mkdir -p cmake_build echo "mkdir cmake_build" cd cmake_build/ -cmake -DCMAKE_TOOLCHAIN_FILE=${ITRUSTEE_BUILD_PATH}/build/cmake/aarch64_toolchain.cmake .. +cmake -DCMAKE_TOOLCHAIN_FILE=${ITRUSTEE_BUILD_PATH}/build/cmake/aarch64_toolchain.cmake ${TARGET} .. make VERBOSE=1 cd .. +[ -f manifest.txt ] && rm -f manifest.txt rm -rf cmake_build diff --git a/test/TA/qta/manifest/manifest-report.txt b/test/TA/qta/manifest/manifest-report.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff7185b8030b7373665309c9c045f8b40b027158 --- /dev/null +++ b/test/TA/qta/manifest/manifest-report.txt @@ -0,0 +1,7 @@ +gpd.ta.appID: 4f84c0e0-4c3f-422f-97dc-14bfa2314ad1 +gpd.ta.service_name: tee_qta_report +gpd.ta.singleInstance: true +gpd.ta.multiSession: true +gpd.ta.instanceKeepAlive: false +gpd.ta.dataSize: 304857 +gpd.ta.stackSize: 64768 diff --git a/test/TA/qta/manifest.txt b/test/TA/qta/manifest/manifest.txt similarity index 100% rename from test/TA/qta/manifest.txt rename to test/TA/qta/manifest/manifest.txt diff --git a/test/TA/qta/src/container/container_info.c b/test/TA/qta/src/container/container_info.c new file mode 100644 index 0000000000000000000000000000000000000000..0e602ed375efd4460546b76265de179d4b91e4cc --- /dev/null +++ b/test/TA/qta/src/container/container_info.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "container_info.h" +#include +#include +#include +#include +#include +#include "dlist.h" +#include "container_verify.h" + +#define MAX_CONTAINER_CNT 0xFF +static pthread_mutex_t g_container_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static bool g_container_list_init = false; +static uint32_t g_container_cnt; +static struct dlist_node g_container_list; + +struct container_info { + struct dlist_node list; + char container_id[CONTAINER_ID_STR_LEN + 1]; + uint32_t nsid; +}; + +TEE_Result init_container_list(void) +{ + if (pthread_mutex_lock(&g_container_list_mutex) != 0) { + tloge("lock container list failed\n"); + return TEE_ERROR_GENERIC; + } + + if (!g_container_list_init) { + dlist_init(&g_container_list); + g_container_list_init = true; + } + + (void)pthread_mutex_unlock(&g_container_list_mutex); + return TEE_SUCCESS; +} + +TEE_Result get_nsid_by_container_id(char container_id[], uint32_t *nsid) +{ + if (check_container_id(container_id) != TEE_SUCCESS || nsid == NULL) { + tloge("get nsid check failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + if (pthread_mutex_lock(&g_container_list_mutex) != 0) { + tloge("lock container list failed\n"); + return TEE_ERROR_GENERIC; + } + + *nsid = 0; + struct container_info *node = NULL; + dlist_for_each_entry(node, &g_container_list, struct container_info, list) { + if (strcmp(node->container_id, container_id) == 0) { + *nsid = node->nsid; + break; + } + } + + (void)pthread_mutex_unlock(&g_container_list_mutex); + return TEE_SUCCESS; +} + +TEE_Result register_container(char container_id[], uint32_t nsid) +{ + TEE_Result ret = TEE_ERROR_GENERIC; + if (check_container_id(container_id) != TEE_SUCCESS || nsid == 0) { + tloge("register check failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + if (pthread_mutex_lock(&g_container_list_mutex) != 0) { + tloge("lock container list failed\n"); + return TEE_ERROR_GENERIC; + } + + /* if already registered, update nsid */ + struct container_info *info_node = NULL; + dlist_for_each_entry(info_node, &g_container_list, struct container_info, list) { + if (strcmp(info_node->container_id, container_id) == 0) { + info_node->nsid = nsid; + ret = TEE_SUCCESS; + goto end; + } + } + + struct container_info *node = malloc(sizeof(*node)); + if (node == NULL) { + tloge("malloc info node failed\n"); + ret = TEE_ERROR_OUT_OF_MEMORY; + goto end; + } + errno_t rc = strcpy_s(node->container_id, sizeof(node->container_id), container_id); + if (rc != EOK) { + tloge("failed to set container id, rc %d\n", rc); + free(node); + ret = TEE_ERROR_GENERIC; + goto end; + } + node->nsid = nsid; + + if (g_container_cnt < MAX_CONTAINER_CNT) { + dlist_insert_head(&node->list, &g_container_list); + g_container_cnt++; + ret = TEE_SUCCESS; + } else { + tloge("container count exceeds limit\n"); + free(node); + } +end: + (void)pthread_mutex_unlock(&g_container_list_mutex); + return ret; +} diff --git a/test/TA/qta/src/container/container_info.h b/test/TA/qta/src/container/container_info.h new file mode 100644 index 0000000000000000000000000000000000000000..7955e410a96551d865c1b760369ec2df2baa02c2 --- /dev/null +++ b/test/TA/qta/src/container/container_info.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef QTA_CONTAINER_INFO_H +#define QTA_CONTAINER_INFO_H + +#include +#include +#include + +TEE_Result init_container_list(void); +TEE_Result get_nsid_by_container_id(char container_id[], uint32_t *nsid); +TEE_Result register_container(char container_id[], uint32_t nsid); +#endif diff --git a/test/TA/qta/src/container/container_verify.c b/test/TA/qta/src/container/container_verify.c new file mode 100644 index 0000000000000000000000000000000000000000..0822174610202d5f795c5125936f2121f786c15a --- /dev/null +++ b/test/TA/qta/src/container/container_verify.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "container_verify.h" +#include +#include +#include +#include "tee_qta.h" +#include +#ifndef CONFIG_QTA_REPORT +#include +#include "container_info.h" +#endif + +#define PARAM_NUM 4 + +#ifdef CONFIG_QTA_REPORT +#define TEE_QTA_UUID \ + { \ + 0xe08f7eca, 0xe875, 0x440e, \ + { \ + 0x9a, 0xb0, 0x5f, 0x38, 0x11, 0x36, 0xc6, 0x00 \ + } \ + } +#else +#define TEE_QTA_REPORT_UUID \ + { \ + 0x4f84c0e0, 0x4c3f, 0x422f, \ + { \ + 0x97, 0xdc, 0x14, 0xbf, 0xa2, 0x31, 0x4a, 0xd1 \ + } \ + } +#endif + +TEE_Result check_container_id(const char container_id[]) +{ + if (container_id == NULL || strnlen(container_id, CONTAINER_ID_STR_LEN + 1) != CONTAINER_ID_STR_LEN) { + tloge("check container id failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + return TEE_SUCCESS; +} + +#ifdef CONFIG_QTA_REPORT +TEE_Result call_qta_verify_container(const char *id, uint32_t nsid) +{ + if (check_container_id(id) != TEE_SUCCESS || nsid == 0) { + tloge("verify container: check input failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + TEE_TASessionHandle session; + TEE_Param params[PARAM_NUM]; + TEE_UUID uuid = TEE_QTA_UUID; + char container_id[CONTAINER_ID_STR_LEN + 1] = {0}; + errno_t rc = strcpy_s(container_id, sizeof(container_id), id); + if (rc != EOK) { + tloge("verify container: strcpy failed, %d\n", rc); + return TEE_ERROR_GENERIC; + } + (void)memset_s(params, PARAM_NUM * sizeof(TEE_Param), 0, PARAM_NUM * sizeof(TEE_Param)); + uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + TEE_Result ret = TEE_OpenTASession(&uuid, 0, param_types, params, &session, NULL); + if (ret != TEE_SUCCESS) { + tloge("verify container: failed to OpenTASession, ret is 0x%x\n", ret); + return ret; + } + + param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + params[0].memref.buffer = container_id; + params[0].memref.size = sizeof(container_id); + params[1].value.a = nsid; + + ret = TEE_InvokeTACommand(session, 0, VERIFY_CONTAINER_CMD, param_types, params, NULL); + if (ret != TEE_SUCCESS) + tloge("verify container: invoke cmd failed, ret is 0x%x\n", ret); + TEE_CloseTASession(session); + return ret; +} +#else +TEE_Result handle_container_verify(uint32_t param_types, TEE_Param *params) +{ + caller_info cinfo; + TEE_UUID uuid = TEE_QTA_REPORT_UUID; + (void)memset_s(&cinfo, sizeof(cinfo), 0, sizeof(cinfo)); + if (init_container_list() != TEE_SUCCESS) + return TEE_ERROR_GENERIC; + + TEE_Result ret = TEE_EXT_GetCallerInfo(&cinfo, sizeof(cinfo)); + if (ret != TEE_SUCCESS) { + tloge("verify container get caller info failed.\n"); + return ret; + } + if (cinfo.session_type != SESSION_FROM_TA || cinfo.caller_identity.group_id == 0 || + TEE_MemCompare(&cinfo.caller_identity.caller_uuid, &uuid, sizeof(uuid)) != 0) { + tloge("verify container check caller failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + + bool param_ret = check_param_type(param_types, TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_VALUE_INPUT, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + if (!param_ret || params == NULL) { + tloge("verify container check param type failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + if (params[0].memref.buffer == NULL || params[0].memref.size == 0 || + params[0].memref.size > IN_RESERVED_SIZE || params[1].value.a == 0) { + tloge("verify container check params failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + + uint32_t tmp_nsid = 0; + ret = get_nsid_by_container_id(params[0].memref.buffer, &tmp_nsid); + if (ret != TEE_SUCCESS) { + tloge("verify container get nsid failed\n"); + return ret; + } + if (tmp_nsid == params[1].value.a) + return TEE_SUCCESS; + tloge("verify container failed\n"); + return TEE_ERROR_GENERIC; +} +#endif diff --git a/test/TA/qta/src/container/container_verify.h b/test/TA/qta/src/container/container_verify.h new file mode 100644 index 0000000000000000000000000000000000000000..ffb239da358d21835f0189c9d5c4cdcf93dc573e --- /dev/null +++ b/test/TA/qta/src/container/container_verify.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef QTA_CONTAINER_VERIFY_H +#define QTA_CONTAINER_VERIFY_H + +#include +#define CONTAINER_ID_STR_LEN 64 + +TEE_Result check_container_id(const char container_id[]); +#ifdef CONFIG_QTA_REPORT +TEE_Result call_qta_verify_container(const char *id, uint32_t nsid); +#else +TEE_Result handle_container_verify(uint32_t param_types, TEE_Param *params); +#endif +#endif diff --git a/test/TA/qta/src/container/dlist.h b/test/TA/qta/src/container/dlist.h new file mode 100644 index 0000000000000000000000000000000000000000..0c129ebf2193fe23e4eba773f7d4506cd257e529 --- /dev/null +++ b/test/TA/qta/src/container/dlist.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + * Licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef HOST_QTA_DLIST_H +#define HOST_QTA_DLIST_H + +#include + +#define offset_of(type, member) (unsigned long)(&(((type *)0)->member)) +#ifndef container_of +#define container_of(ptr, type, member) (type *)(void *)((uintptr_t)(ptr) - offset_of(type, member)) +#endif + +/* + * The dlist node structure + * representing the head node and the body nodes of the dlist + */ +struct dlist_node { + struct dlist_node *prev; + struct dlist_node *next; +}; + +/* + * Initialize the empty dlist + * PRE: a dlist_node struct for the head node, with unspecified field values + * POST: the field set to point to the head node itself, thus initialized to be an empty dlist + */ +static inline void dlist_init(struct dlist_node *head) +{ + head->prev = head; + head->next = head; +} + +/* + * Insert after a given position of the dlist + * PRE: pos points to a node(can be the head node) in a well formed dlist, node points to a node to be inserted(not in + * the dlist) POST: node has been inserted into the dlist after pos, the new dlist is well formed + */ +static inline void dlist_insert(struct dlist_node *pos, struct dlist_node *node) +{ + struct dlist_node *tmp = NULL; + + tmp = pos->next; + tmp->prev = node; + node->prev = pos; + node->next = pos->next; + pos->next = node; +} + +/* + * Insert a new node at head of a dlist + * PRE: head points to the head node of a well formed dlist, node points to the node to be inserted(not in the dlist) + * POST: the new node has been inserted to the head of the dlist, the new dlist is well formed + */ +static inline void dlist_insert_head(struct dlist_node *node, struct dlist_node *head) +{ + dlist_insert(head, node); +} + +/* get the address of the containing struct */ +#define dlist_entry(ptr, type, member) container_of(ptr, type, member) + +/* dlist_first_entry */ +#define dlist_first_entry(ptr, type, member) dlist_entry((ptr)->next, type, member) + +/* dlist_last_entry */ +#define dlist_last_entry(ptr, type, member) dlist_entry((ptr)->prev, type, member) + +/* get the address of the next containing struct on the dlist */ +#define dlist_next_entry(pos, type, member) dlist_entry((pos)->member.next, type, member) + +/* get the address of the previous containing struct on the dlist */ +#define dlist_prev_entry(pos, type, member) dlist_entry((pos)->member.prev, type, member) + +/* dlist for each struct entry */ +#define dlist_for_each_entry(pos, head, type, member) \ + for ((pos) = dlist_first_entry(head, type, member); &((pos)->member) != (head); \ + pos = dlist_next_entry(pos, type, member)) + +#define dlist_for_each_entry_safe(pos, n, head, type, member) \ + for ((pos) = dlist_first_entry(head, type, member), (n) = dlist_next_entry(pos, type, member); \ + (&(pos)->member != (head)); (pos) = (n), (n) = dlist_next_entry(n, type, member)) + +#endif diff --git a/test/TA/qta/src/tee_qta.c b/test/TA/qta/src/tee_qta.c index 8dff8a6f22635b88abfbb09d1bc970269df94a52..d84a5baa198bebe1a8fc839327b7f005bc90311d 100644 --- a/test/TA/qta/src/tee_qta.c +++ b/test/TA/qta/src/tee_qta.c @@ -1,5 +1,5 @@ /* - * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved. * Licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: @@ -15,6 +15,12 @@ #include "tee_ra_api.h" #include "securec.h" #include +#ifdef CONFIG_HOST_QTA +#include "container_info.h" +#endif +#if defined(CONFIG_QTA_REPORT) || defined(CONFIG_HOST_QTA) +#include "container_verify.h" +#endif #ifdef ENABLE_DAA_PAIR_MIRACL #include "daa/validate_akcert.h" @@ -43,6 +49,23 @@ TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types, TEE_Param params[PARAM return TEE_SUCCESS; } +static cJSON *parse(uint8_t *buffer, uint32_t length) +{ + char *buf = REINTERPRET_CAST(char *, uint8_t *, buffer); + char *json_buffer = TEE_Malloc(length + 1, 0); + if (json_buffer == NULL) { + tloge("malloc buffer failed\n"); + return NULL; + } + (void)memcpy_s(json_buffer, length, buf, length); + cJSON *json = cJSON_Parse(json_buffer); + if (json == NULL) + tloge("check akcert json failed\n"); + + TEE_Free(json_buffer); + return json; +} + static bool check_akcert_params_valid(struct ra_buffer_data *akcert) { bool result = false; @@ -51,10 +74,9 @@ static bool check_akcert_params_valid(struct ra_buffer_data *akcert) return result; } - char *akcert_buf = REINTERPRET_CAST(char *, uint8_t *, akcert->buffer); - cJSON *json = cJSON_Parse(akcert_buf); + cJSON *json = parse(akcert->buffer, akcert->length); if (json == NULL) { - tloge("check akcert json failed\n"); + tloge("json parse failed\n"); return result; } @@ -94,6 +116,32 @@ clear: return result; } +static bool is_report_request(cJSON *json) +{ + char *handler = cJSON_GetStringValue(cJSON_GetObjectItem(json, "handler")); + if (handler == NULL) { + tloge("in handler is null\n"); + return false; + } + if (strcmp(handler, "report-input") != 0) + return false; + return true; +} + +static TEE_Result insert_request_uuid(cJSON *json, char *uuid) +{ + cJSON *payload = cJSON_GetObjectItem(json, "payload"); + if (payload == NULL) { + tloge("payload is null\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + if (cJSON_AddStringToObject(payload, "requester_uuid", uuid) == NULL) { + tloge("insert requester uuid failed\n"); + return TEE_ERROR_GENERIC; + } + return TEE_SUCCESS; +} + static TEE_Result qta_validate_akcert(struct ra_buffer_data *akcert) { TEE_Result result = TEE_ERROR_GENERIC; @@ -102,8 +150,12 @@ static TEE_Result qta_validate_akcert(struct ra_buffer_data *akcert) return TEE_ERROR_BAD_PARAMETERS; } - char *akcert_buf = REINTERPRET_CAST(char *, uint8_t *, akcert->buffer); - cJSON *json = cJSON_Parse(akcert_buf); + cJSON *json = parse(akcert->buffer, akcert->length); + if (json == NULL) { + tloge("qta validate akcert: json parse failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + cJSON *handler = cJSON_CreateString("validateakcert-input"); if (handler == NULL) { tloge("qta validate akcert: handler is null\n"); @@ -140,34 +192,78 @@ clear1: return result; } -static TEE_Result local_attest(struct ra_buffer_data *in, struct ra_buffer_data *out) +#define UUID_STR_FORMAT_LEN 37 +static TEE_Result get_uuid_str(const TEE_UUID *uuid, char *buff, uint32_t len) +{ + if (uuid == NULL || buff == NULL || len < UUID_STR_FORMAT_LEN) { + tloge("invalid input parameter\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + + int ret = snprintf_s(buff, len, UUID_STR_FORMAT_LEN - 1, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, uuid->clockSeqAndNode[0], + uuid->clockSeqAndNode[1], uuid->clockSeqAndNode[2], uuid->clockSeqAndNode[3], + uuid->clockSeqAndNode[4], uuid->clockSeqAndNode[5], uuid->clockSeqAndNode[6], + uuid->clockSeqAndNode[7]); + if (ret <= 0) { + tloge("convert uuid to string failed\n"); + return TEE_ERROR_GENERIC; + } + return TEE_SUCCESS; +} + +static TEE_Result local_attest(struct ra_buffer_data *in, struct ra_buffer_data *out, const TEE_UUID *uuid) { TEE_Result result; - char *buf = REINTERPRET_CAST(char *, uint8_t *, in->buffer); - cJSON *json = cJSON_Parse(buf); + cJSON *json = parse(in->buffer, in->length); if (json == NULL) { tloge("check local attest json failed\n"); return TEE_ERROR_BAD_PARAMETERS; } - char *handler = cJSON_GetStringValue(cJSON_GetObjectItem(json, "handler")); - if (handler == NULL) { - tloge("handler is null\n"); + if (!is_report_request(json)) { + tloge("check report request failed\n"); result = TEE_ERROR_BAD_PARAMETERS; - goto clear; + goto clear1; } - if (strcmp(handler, "report-input") != 0) { - tloge("check local attest handler failed\n"); - result = TEE_ERROR_BAD_PARAMETERS; - goto clear; + + char str_uuid[UUID_STR_FORMAT_LEN] = { 0 }; + result = get_uuid_str(uuid, str_uuid, UUID_STR_FORMAT_LEN); + if (result != TEE_SUCCESS) { + tloge("get uuid str failed\n"); + goto clear1; + } + + result = insert_request_uuid(json, str_uuid); + if (result != TEE_SUCCESS) { + tloge("insert request uuid failed\n"); + goto clear1; + } + + char *json_buf = cJSON_Print(json); + if (json_buf == NULL) { + tloge("json buf is null\n"); + result = TEE_ERROR_GENERIC; + goto clear1; + } + + if (strlen(json_buf) > IN_RESERVED_SIZE) { + tloge("json size is invalid\n"); + result = TEE_ERROR_GENERIC; + goto clear2; } + + in->length = strlen(json_buf); + in->buffer = REINTERPRET_CAST(uint8_t *, char *, json_buf); result = ra_qsi_invoke(in, out); -clear: +clear2: + cJSON_free(json_buf); +clear1: cJSON_Delete(json); return result; } -static TEE_Result qta_local_attest(uint32_t param_types, TEE_Param *params) +static TEE_Result qta_local_attest(uint32_t param_types, TEE_Param *params, const TEE_UUID *uuid) { bool ret = check_param_type(param_types, TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_VALUE_OUTPUT, TEE_PARAM_TYPE_NONE); @@ -190,7 +286,7 @@ static TEE_Result qta_local_attest(uint32_t param_types, TEE_Param *params) out.buffer = params[1].memref.buffer; out.length = params[1].memref.size; - TEE_Result result = local_attest(&in, &out); + TEE_Result result = local_attest(&in, &out, uuid); if (result != TEE_SUCCESS) { tloge("local attest failed\n"); return result; @@ -199,6 +295,92 @@ static TEE_Result qta_local_attest(uint32_t param_types, TEE_Param *params) return result; } +#ifdef CONFIG_QTA_REPORT +static TEE_Result verify_container_info(cJSON *json) +{ + cJSON *payload = cJSON_GetObjectItem(json, "payload"); + if (payload == NULL) { + tloge("verify container info: get payload failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + cJSON *info = cJSON_GetObjectItem(payload, "container_info"); + if (info == NULL) { + tloge("verify container info: get container_info failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + + char *id = cJSON_GetStringValue(cJSON_GetObjectItem(info, "id")); + if (id == NULL) { + tloge("verify container info: get id failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + uint32_t nsid = 0; + TEE_Result ret = tee_ext_get_nsid(&nsid); + if (ret != TEE_SUCCESS) { + tloge("verify container info: get nsid failed\n"); + return ret; + } + ret = call_qta_verify_container(id, nsid); + if (ret != TEE_SUCCESS) + tloge("verify container info failed, 0x%x\n", ret); + return ret; +} +#endif + +static TEE_Result remote_attest(struct ra_buffer_data *in, struct ra_buffer_data *out, uint32_t *value) +{ + TEE_Result result; + cJSON *json = parse(in->buffer, in->length); + if (json == NULL) { + tloge("check in json failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + if (is_report_request(json)) { +#ifdef CONFIG_QTA_REPORT + result = verify_container_info(json); + if (result != TEE_SUCCESS) { + tloge("verify container info failed\n"); + goto clear; + } +#endif + result = insert_request_uuid(json, ""); + if (result != TEE_SUCCESS) { + tloge("insert request uuid failed\n"); + goto clear; + } + char *json_buf = cJSON_Print(json); + if (json_buf == NULL) { + tloge("json buf is null\n"); + result = TEE_ERROR_GENERIC; + goto clear; + } + + if (strlen(json_buf) > IN_RESERVED_SIZE) { + tloge("json size is invalid\n"); + result = TEE_ERROR_GENERIC; + cJSON_free(json_buf); + goto clear; + } + + in->length = strlen(json_buf); + in->buffer = REINTERPRET_CAST(uint8_t *, char *, json_buf); + result = ra_qsi_invoke(in, out); + if (result == TEE_SUCCESS) + *value = out->length; + cJSON_free(json_buf); + } else { + result = ra_qsi_invoke(in, out); + if (result == TEE_PENDING) { + result = qta_validate_akcert(out); + } else if (result == TEE_SUCCESS) { + *value = out->length; + } + } +clear: + cJSON_Delete(json); + return result; +} + static TEE_Result qta_remote_attest(uint32_t param_types, TEE_Param *params) { bool ret = check_param_type(param_types, TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, @@ -222,27 +404,62 @@ static TEE_Result qta_remote_attest(uint32_t param_types, TEE_Param *params) in.length = params[0].memref.size; out.buffer = params[1].memref.buffer; out.length = params[1].memref.size; - TEE_Result result = ra_qsi_invoke(&in, &out); - if (result == TEE_PENDING) { - return qta_validate_akcert(&out); - } else if (result == TEE_SUCCESS) { - params[PARAM_TWO].value.a = out.length; - return result; - } - tloge("ra qsi invoke failed\n"); + + TEE_Result result = remote_attest(&in, &out, ¶ms[PARAM_TWO].value.a); + if (result != TEE_SUCCESS) + tloge("qta remote attest: ra qsi invoke failed\n"); return result; } -TEE_Result TA_InvokeCommandEntryPoint(void *session_context, uint32_t cmd_id, - uint32_t param_types, TEE_Param params[PARAM_NUM]) +#ifdef CONFIG_HOST_QTA +static TEE_Result handle_container_info(uint32_t cmd_id, uint32_t param_types, + TEE_Param *params) { - tlogi("tee_qta: Enter TA_InvokeCommandEntryPoint.\n"); - (void)session_context; - if (cmd_id != REMOTE_ATTEST_CMD) { - tloge("tee_qta: InvokeCommandEntryPoint failed, cmd: 0x%x.\n", cmd_id); - return TEE_ERROR_INVALID_CMD; + (void)cmd_id; + TEE_Result ret = TEE_ERROR_GENERIC; + if (init_container_list() != TEE_SUCCESS) + return ret; + bool check = check_param_type(param_types, TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE); + if (!check || params == NULL) { + tloge("qta container info: check param type failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + if (params[0].memref.buffer == NULL || params[0].memref.size == 0 || + params[0].memref.size > IN_RESERVED_SIZE) { + tloge("qta container info: check params failed\n"); + return TEE_ERROR_BAD_PARAMETERS; + } + + cJSON *input = parse(params[0].memref.buffer, params[0].memref.size); + if (input == NULL) { + tloge("qta container info: parse failed\n"); + return TEE_ERROR_GENERIC; + } + char *id = cJSON_GetStringValue(cJSON_GetObjectItem(input, "container_id")); + if (id == NULL) { + tloge("qta container info: get id failed\n"); + goto clean; + } + + /* register */ + cJSON *json_nsid = cJSON_GetObjectItem(input, "nsid"); + if (json_nsid == NULL) { + tloge("qta container info: get nsid failed\n"); + goto clean; } + uint32_t nsid = cJSON_GetNumberValue(json_nsid); + ret = register_container(id, nsid); +clean: + cJSON_Delete(input); + if (ret != TEE_SUCCESS) + tloge("qta container info: handle cmd 0x%x failed\n", cmd_id); + return ret; +} +#endif +static TEE_Result handle_remote_attest(uint32_t cmd_id, uint32_t param_types, TEE_Param *params) +{ caller_info cinfo; (void)memset_s(&cinfo, sizeof(cinfo), 0, sizeof(cinfo)); TEE_Result ret = TEE_EXT_GetCallerInfo(&cinfo, sizeof(cinfo)); @@ -251,7 +468,7 @@ TEE_Result TA_InvokeCommandEntryPoint(void *session_context, uint32_t cmd_id, return ret; } if (cinfo.session_type == SESSION_FROM_TA) { - ret = qta_local_attest(param_types, params); + ret = qta_local_attest(param_types, params, &(cinfo.caller_identity.caller_uuid)); if (ret != TEE_SUCCESS) tloge("tee_qta: local attest failed, cmd: 0x%x, ret: 0x%x.\n", cmd_id, ret); else @@ -267,6 +484,30 @@ TEE_Result TA_InvokeCommandEntryPoint(void *session_context, uint32_t cmd_id, return ret; } +TEE_Result TA_InvokeCommandEntryPoint(void *session_context, uint32_t cmd_id, + uint32_t param_types, TEE_Param params[PARAM_NUM]) +{ + tlogi("tee_qta: Enter TA_InvokeCommandEntryPoint.\n"); + (void)session_context; + TEE_Result ret = TEE_ERROR_GENERIC; + switch (cmd_id) { + case REMOTE_ATTEST_CMD: + ret = handle_remote_attest(cmd_id, param_types, params); + break; +#ifdef CONFIG_HOST_QTA + case REGISTER_CONTAINER_CMD: + ret = handle_container_info(cmd_id, param_types, params); + break; + case VERIFY_CONTAINER_CMD: + ret = handle_container_verify(param_types, params); + break; +#endif + default: + tloge("tee_qta: invalid cmd 0x%x\n", cmd_id); + } + return ret; +} + void TA_CloseSessionEntryPoint(void *session_context) { (void)session_context; diff --git a/test/TA/qta/src/tee_qta.h b/test/TA/qta/src/tee_qta.h index 0dfb1d57f2fbefe4a15c249b299ce1579d0d53fc..4246254f2d417d208fca6ee6231518b365ca1320 100644 --- a/test/TA/qta/src/tee_qta.h +++ b/test/TA/qta/src/tee_qta.h @@ -1,5 +1,5 @@ /* - * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved. + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved. * Licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: @@ -20,7 +20,13 @@ #define SHAREMEM_LIMIT 0x100000 #define IN_RESERVED_SIZE 0x2000 #define OUT_RESERVED_SIZE 0x3000 -#define REMOTE_ATTEST_CMD 0x1001 +#define REMOTE_ATTEST_CMD 0x1001 +#ifdef CONFIG_HOST_QTA +#define REGISTER_CONTAINER_CMD 0x1002 +#endif +#if defined(CONFIG_HOST_QTA) || defined(CONFIG_QTA_REPORT) +#define VERIFY_CONTAINER_CMD 0x1003 +#endif #define REINTERPRET_CAST(dest_type, source_type, temp) \ ((__extension__(union { source_type source; dest_type dest; })(temp)).dest)