diff --git a/test/CA/libqca/Makefile b/test/CA/libqca/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..841c91a76f57f8ad282b5599e721ea37f2869e3f --- /dev/null +++ b/test/CA/libqca/Makefile @@ -0,0 +1,42 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2018-2021. All rights reserved. +CUR_DIR=$(shell pwd) +ITRUSTEE_BUILD_PATH=${CUR_DIR}/../../../ + +TARGET_LIB := libqca.so +TARGET_DIR := output +TARGET_LIB_BOUNDSCHECK := libboundscheck.so + +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 + +LIB_CFLAGS += -I$(ITRUSTEE_BUILD_PATH)/thirdparty/open_source/libboundscheck/include +LIB_CFLAGS += -I$(ITRUSTEE_BUILD_PATH)/include/CA +LIB_CFLAGS += -I./include + +LIB_LDFLAGS += -ldl -lpthread +LIB_LDFLAGS += -lboundscheck -L$(ITRUSTEE_BUILD_PATH)/thirdparty/open_source/libboundscheck/lib/ + +LIB_OBJECTS := $(LIB_SOURCES:.c=.o) + +all: $(TARGET_LIB_BOUNDSCHECK) $(TARGET_LIB) + +LIB_BOUNDSCHECK_DIR := $(ITRUSTEE_BUILD_PATH)/thirdparty/open_source/libboundscheck/ +$(TARGET_LIB_BOUNDSCHECK): + @echo "compile libboundscheck start" + @$(MAKE) -C $(LIB_BOUNDSCHECK_DIR) + @echo "compile libboundscheck finish" + +$(TARGET_LIB): $(TARGET_LIB_BOUNDSCHECK) $(LIB_SOURCES) + @echo "start compile libqca.so ......" + @$(CC) -shared $(LIB_CFLAGS) -o $@ $(LIB_SOURCES) $(LIB_LDFLAGS) + @mkdir -p $(TARGET_DIR) + @mv $(TARGET_LIB) $(TARGET_DIR) + @echo "compile libqca.so done!" + +clean: + $(MAKE) -C $(LIB_BOUNDSCHECK_DIR) clean + rm -rf $(TARGET_DIR) + rm -rf $(LIB_OBJECTS) diff --git a/test/CA/libqca/include/ra_client_api.h b/test/CA/libqca/include/ra_client_api.h new file mode 100644 index 0000000000000000000000000000000000000000..8f39136b74d4ee3561291735c7d192bf245efff9 --- /dev/null +++ b/test/CA/libqca/include/ra_client_api.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. 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 LIBQCA_H +#define LIBQCA_H +#include + +#define KEY_TAG_TYPE_MOVE_BITS 28 +#define RA_INTEGER (1 << KEY_TAG_TYPE_MOVE_BITS) +#define RA_BYTES (2 << KEY_TAG_TYPE_MOVE_BITS) + +/* scenario number */ +#define RA_SCENARIO_NO_AS 0 +#define RA_SCENARIO_AS_NO_DAA 1 +#define RA_SCENARIO_AS_WITH_DAA 2 + +enum ra_alg_types { + RA_ALG_RSA_3072 = 0x20000, + RA_ALG_RSA_4096 = 0x20001, + RA_ALG_SHA_256 = 0x20002, + RA_ALG_SHA_384 = 0x20003, + RA_ALG_SHA_512 = 0x20004, + RA_ALG_ECDSA = 0x20005, + RA_ALG_ED25519 = 0x20006, + RA_ALG_SM2_DSA_SM3 = 0x20007, + RA_ALG_SM3 = 0x20008, +}; + +enum ra_tags { + RA_TAG_SIGN_TYPE = RA_INTEGER | 0, + RA_TAG_HASH_TYPE = RA_INTEGER | 1, + RA_TAG_QTA_IMG_HASH = RA_BYTES | 0, + RA_TAG_TA_IMG_HASH = RA_BYTES | 1, + RA_TAG_QTA_MEM_HASH = RA_BYTES | 2, + RA_TAG_TA_MEM_HASH = RA_BYTES | 3, + RA_TAG_RESERVED = RA_BYTES | 4, + RA_TAG_AK_PUB = RA_BYTES | 5, + RA_TAG_SIGN_DRK = RA_BYTES | 6, + RA_TAG_SIGN_AK = RA_BYTES | 7, + RA_TAG_CERT_DRK = RA_BYTES | 8, + RA_TAG_CERT_AK = RA_BYTES | 9, +}; + +struct ra_buffer_data { + uint32_t size; + uint8_t *buf; +}; + +struct ra_data_offset { + uint32_t data_len; + uint32_t data_offset; +}; + +struct ra_params { + uint32_t tags; + union { + uint32_t integer; + struct ra_data_offset blob; + } data; +} __attribute__((__packed__)); + +struct ra_params_set_t { + uint32_t param_count; + struct ra_params params[0]; +}__attribute__((__packed__)); + +TEEC_Result RemoteAttestProvision(uint32_t scenario, + struct ra_buffer_data *param_set, + struct ra_buffer_data *out_data); + +TEEC_Result RemoteAttestReport(TEEC_UUID ta_uuid, + struct ra_buffer_data *usr_data, + struct ra_buffer_data *param_set, + struct ra_buffer_data *report, + bool with_tcb); + +TEEC_Result RemoteAttestSaveAKCert(struct ra_buffer_data *akcert); + +#endif diff --git a/test/CA/libqca/src/ra_log.h b/test/CA/libqca/src/ra_log.h new file mode 100644 index 0000000000000000000000000000000000000000..7e400beb2c55ccc47573c0fddc2ab495a51220d1 --- /dev/null +++ b/test/CA/libqca/src/ra_log.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. 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 LIBQCA_RA_LOG_H +#define LIBQCA_RA_LOG_H + +#define TAG_WARN "[warn]" +#define TAG_INFO "[info]" +#define TAG_ERROR "[error]" +#define TAG_DEBUG "[debug]" + +#define LIBQCA_PREFIX "libqca" + +#define tloge(fmt, args...) printf("[%s] %s %d:" fmt " ", LIBQCA_PREFIX, TAG_ERROR, __LINE__, ##args) +#define tlogd(fmt, args...) printf("[%s] %s %d:" fmt " ", LIBQCA_PREFIX, TAG_DEBUG, __LINE__, ##args) +#define tlogi(fmt, args...) printf("[%s] %s %d:" fmt " ", LIBQCA_PREFIX, TAG_INFO, __LINE__, ##args) +#define tlogw(fmt, args...) printf("[%s] %s %d:" fmt " ", LIBQCA_PREFIX, TAG_WARN, __LINE__, ##args) + +#endif diff --git a/test/CA/libqca/src/ra_operate_api.c b/test/CA/libqca/src/ra_operate_api.c new file mode 100644 index 0000000000000000000000000000000000000000..6fd208b1fcde41975c5bee6e418971b9752d9a92 --- /dev/null +++ b/test/CA/libqca/src/ra_operate_api.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. 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 "ra_operate_api.h" +#include +#include +#include "tee_client_api.h" +#include "securec.h" +#include "ra_log.h" +#include "ra_client_api.h" + +static const TEEC_UUID g_tee_qta_uuid = { + 0xe08f7eca, 0xe875, 0x440e, { + 0x9a, 0xb0, 0x5f, 0x38, 0x11, 0x36, 0xc6, 0x00 + } +}; + +static const enum ra_tags g_tag_white_list [] = { + RA_TAG_HASH_TYPE, +}; + +static bool check_provision_scenario_invalid(uint32_t scenario) +{ + if (scenario == RA_SCENARIO_NO_AS || scenario == RA_SCENARIO_AS_NO_DAA) + return false; + return true; +} + +#define WHITE_LIST_TAG_COUNT (sizeof(g_tag_white_list) / sizeof(g_tag_white_list[0])) + +static bool check_tag_is_valid(uint32_t tag) +{ + uint32_t index = 0; + for (index = 0; index < WHITE_LIST_TAG_COUNT; ++index) { + if (tag == g_tag_white_list[index]) + return true; + } + return false; +} + +static bool check_input_paramset_invalid(struct ra_buffer_data *param_set) +{ + uint32_t length = param_set->size; + struct ra_params_set_t *ra_param_set = (struct ra_params_set_t *)param_set->buf; + uint32_t param_count = ra_param_set->param_count; + if (length != sizeof(uint32_t) + param_count * sizeof(struct ra_params) || length > SHAREMEM_LIMIT) { + tloge("invalid param length\n"); + return true; + } + struct ra_params *param = NULL; + for (uint32_t index = 0; index < param_count; ++index) { + param = &(ra_param_set->params[index]); + if (check_tag_is_valid(param->tags) == false) { + tloge("invalid param tag\n"); + return true; + } + } + return false; +} + +static int32_t init_opera_and_shared_mem(TEEC_Context *context, TEEC_SharedMemory *shared_mem, + TEEC_Operation *operation, struct ra_buffer_data *rsp, struct ra_buffer_data *msg) +{ + TEEC_Result result; + (void)memset_s(operation, sizeof(TEEC_Operation), 0, sizeof(TEEC_Operation)); + (*operation).started = 1; + (*operation).paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_WHOLE, TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE); + shared_mem->size = (rsp == NULL ? msg->size : rsp->size); + shared_mem->flags = TEEC_MEM_OUTPUT | TEEC_MEM_INPUT; + if (shared_mem->size > SHAREMEM_LIMIT) { + tloge("too large shared mem size to be allocated\n"); + return -1; + } + result = TEEC_AllocateSharedMemory(context, shared_mem); + if (result != TEEC_SUCCESS) { + tloge("allocate shared memory failed, result = 0x%x\n", result); + return -1; + } + (*operation).params[0].memref.parent = shared_mem; + (*operation).params[0].memref.size = shared_mem->size; + (*operation).params[0].memref.offset = 0; + return 0; +} + +static int32_t handle_cmd_id(uint32_t cmd_id, TEEC_SharedMemory *shared_mem, struct ra_buffer_data *msg) +{ + int32_t ret = 0; + if (cmd_id == INIT_PROVISION || cmd_id == REQUEST_REPORT || cmd_id == SAVE_AKCERT) { + if (memcpy_s((void *)shared_mem->buffer, shared_mem->size, msg->buf, msg->size) != EOK) { + tloge("memcpy buffer failed\n"); + ret = -1; + } + } else { + tloge("cmd id invalid!\n"); + return -1; + } + return ret; +} + +static TEEC_Result handle_cmd(uint32_t cmd_id, struct ra_buffer_data *msg, struct ra_buffer_data *rsp) +{ + TEEC_Context context = {0}; + TEEC_Session session = {0}; + TEEC_Operation operation = {0}; + TEEC_Result result; + uint32_t origin; + TEEC_UUID uuid = g_tee_qta_uuid; + + result = TEEC_InitializeContext(NULL, &context); + if (result != TEEC_SUCCESS) { + tloge("init context is failed! result is 0x%x\n", result); + return TEEC_ERROR_GENERIC; + } + + (void)memset_s(&operation, sizeof(TEEC_Operation), 0, sizeof(TEEC_Operation)); + operation.started = 1; + operation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE); + result = TEEC_OpenSession(&context, &session, &uuid, TEEC_LOGIN_IDENTIFY, NULL, &operation, NULL); + if (result != TEEC_SUCCESS) { + tloge("open session is failed! result is 0x%x\n", result); + goto cleanup_0; + } + + TEEC_SharedMemory shared_mem; + result = init_opera_and_shared_mem(&context, &shared_mem, &operation, rsp, msg); + if (result != 0) + goto cleanup_1; + result = handle_cmd_id(cmd_id, &shared_mem, msg); + if (result != 0) + goto cleanup_2; + + result = TEEC_InvokeCommand(&session, cmd_id, &operation, &origin); + if (result != TEEC_SUCCESS) { + tloge("invoke cmd 0x%x failed, result = 0x%x, origin = 0x%x\n", cmd_id, result, origin); + goto cleanup_2; + } + if (rsp != NULL) { + rsp->size = operation.params[1].value.a; + if (memcpy_s(rsp->buf, rsp->size, (void *)shared_mem.buffer, rsp->size) != EOK) { + tloge("memcpy buffer failed\n"); + result = TEEC_ERROR_GENERIC; + goto cleanup_2; + } + } +cleanup_2: + TEEC_ReleaseSharedMemory(&shared_mem); +cleanup_1: + TEEC_CloseSession(&session); +cleanup_0: + TEEC_FinalizeContext(&context); + return result; +} + +TEEC_Result RemoteAttestSaveAKCert(struct ra_buffer_data *akcert) +{ + if (akcert == NULL || akcert->buf == NULL || akcert->size == 0 || akcert->size > SAVE_AKCERT_RESERVED_SIZE) { + tloge("bad input params\n"); + return TEEC_ERROR_BAD_PARAMETERS; + } + TEEC_Result result = TEEC_SUCCESS; + struct ra_buffer_data msg; + msg.buf = akcert->buf; + msg.size = akcert->size; + + tlogi("Try to call save AK cert.\n"); + result = handle_cmd(SAVE_AKCERT, &msg, NULL); + if (result != TEEC_SUCCESS) { + tloge("Call Save AK Cert Failed, result = 0x%x\n", result); + return result; + } + tlogi("Call Save AK Cert success.\n"); + + return result; +} + +TEEC_Result RemoteAttestProvision(uint32_t scenario, struct ra_buffer_data *param_set, struct ra_buffer_data *out_data) +{ + if (param_set == NULL || param_set->buf == NULL || out_data == NULL || out_data->size == 0 || + out_data->size < PROVISION_RESERVED_SIZE || out_data->size > SHAREMEM_LIMIT) { + tloge("bad input params or short out data size\n"); + return TEEC_ERROR_BAD_PARAMETERS; + } + if (check_provision_scenario_invalid(scenario) == true || check_input_paramset_invalid(param_set) == true) { + tloge("invalid scenario number or input alg param\n"); + return TEEC_ERROR_BAD_PARAMETERS; + } + struct provision_input_params *ra_input = malloc(sizeof(uint32_t) + param_set->size); + if (ra_input == NULL) { + tloge("malloc provision input param failed\n"); + return TEEC_ERROR_OUT_OF_MEMORY; + } + ra_input->scenario = scenario; + (void)memcpy_s(&(ra_input->param_count), param_set->size, param_set->buf, param_set->size); + + TEEC_Result ret = TEEC_SUCCESS; + struct ra_buffer_data msg = {0}; + struct ra_buffer_data rsp; + + msg.buf = (uint8_t *)ra_input; + msg.size = param_set->size + sizeof(uint32_t); + + rsp.buf = malloc(out_data->size); + if (rsp.buf == NULL) { + tloge("malloc out data buffer failed\n"); + ret = TEEC_ERROR_OUT_OF_MEMORY; + goto cleanup_0; + } + rsp.size = out_data->size; + ret = handle_cmd(INIT_PROVISION, &msg, &rsp); + if (ret != TEEC_SUCCESS) { + tloge("Call Provision Failed, ret = 0x%x\n", ret); + goto cleanup_1; + } + /* handle out data buffer and size according to scenario number */ + if (scenario == RA_SCENARIO_NO_AS) { + out_data->size = 0; + } else { + out_data->size = rsp.size; + (void)memcpy_s(out_data->buf, out_data->size, rsp.buf, rsp.size); + } + tlogi("Call Provision success.\n"); + +cleanup_1: + free(rsp.buf); +cleanup_0: + free(ra_input); + return ret; +} + +TEEC_Result RemoteAttestReport(TEEC_UUID ta_uuid, struct ra_buffer_data *usr_data, struct ra_buffer_data *param_set, + struct ra_buffer_data *report, bool with_tcb) +{ + if (usr_data == NULL || usr_data->buf == NULL || usr_data->size == 0 || usr_data->size > USER_DATA_SIZE || + report == NULL || report->buf == NULL || report->size < REPORT_RESERVED_SIZE || + report->size > SHAREMEM_LIMIT || with_tcb != false) { + tloge("bad input params\n"); + return TEEC_ERROR_BAD_PARAMETERS; + } + if (check_input_paramset_invalid(param_set) == true) { + tloge("invalid input alg param\n"); + return TEEC_ERROR_BAD_PARAMETERS; + } + TEEC_Result result = TEEC_SUCCESS; + struct ra_buffer_data msg; + struct ra_buffer_data rsp; + struct report_input_params *ra_input = malloc(sizeof(struct report_input_params) + param_set->size); + if (ra_input == NULL) { + tloge("malloc report input param failed\n"); + return TEEC_ERROR_OUT_OF_MEMORY; + } + (void)memset_s(ra_input, sizeof(struct report_input_params), 0, sizeof(struct report_input_params)); + /* init struct report_input_params */ + ra_input->uuid = ta_uuid; + ra_input->with_tcb = with_tcb; + (void)memcpy_s(ra_input->user_data, USER_DATA_SIZE, usr_data->buf, usr_data->size); + ra_input->user_size = usr_data->size; + (void)memcpy_s(&(ra_input->param_count), param_set->size, param_set->buf, param_set->size); + + msg.buf = (uint8_t *)ra_input; + msg.size = sizeof(struct report_input_params) + param_set->size; + + rsp.buf = malloc(report->size); + if (rsp.buf == NULL) { + tloge("malloc report buffer failed\n"); + result = TEEC_ERROR_OUT_OF_MEMORY; + goto cleanup_0; + } + rsp.size = report->size; + tlogi("Try to call Attestation Report.\n"); + + result = handle_cmd(REQUEST_REPORT, &msg, &rsp); + if (result != TEEC_SUCCESS) { + tloge("Call Attestation Report Failed, result = 0x%x\n", result); + goto cleanup_1; + } + report->size = rsp.size; + (void)memcpy_s(report->buf, report->size, rsp.buf, rsp.size); + tlogi("Call Attestation Report success, report size = %u\n", report->size); + +cleanup_1: + free(rsp.buf); +cleanup_0: + free(ra_input); + return result; +} + diff --git a/test/CA/libqca/src/ra_operate_api.h b/test/CA/libqca/src/ra_operate_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b60dd913632399a43a80782843f9b62d1568aa88 --- /dev/null +++ b/test/CA/libqca/src/ra_operate_api.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. 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 LIBQCA_RA_OPERATE_H +#define LIBQCA_RA_OPERATE_H + +#include +#include "tee_client_api.h" +#include "ra_client_api.h" + +#define SHAREMEM_LIMIT 0x100000 /* 1MB */ +#define PROVISION_RESERVED_SIZE (0x1000) +#define SAVE_AKCERT_RESERVED_SIZE (0x2000) +#define REPORT_RESERVED_SIZE (0x3000) + +#define USER_DATA_SIZE 64 +/* scenario number */ +#define RA_SCENARIO_NO_AS 0 +#define RA_SCENARIO_AS_NO_DAA 1 +#define RA_SCENARIO_AS_WITH_DAA 2 + +enum qca_commands_id { + INIT_PROVISION = 0x1001, + REQUEST_REPORT = 0x1002, + SAVE_AKCERT = 0x1003, +}; + +struct report_input_params { + TEEC_UUID uuid; + uint8_t user_data[USER_DATA_SIZE]; + uint32_t user_size; + bool with_tcb; + uint32_t param_count; + struct ra_params params[0]; +} __attribute__((__packed__)); + +struct provision_input_params { + uint32_t scenario; + uint32_t param_count; + struct ra_params params[0]; +} __attribute__((__packed__)); + +#endif