// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014, STMicroelectronics International N.V. */ #include #include #include #include #include #include #include #include #include #include "xtest_helpers.h" #include "xtest_test.h" /* Round up the even multiple of size, size has to be a multiple of 2 */ #define ROUNDUP(v, size) (((v) + (size - 1)) & ~(size - 1)) TEEC_Context xtest_teec_ctx; TEEC_Result xtest_teec_ctx_init(void) { return TEEC_InitializeContext(xtest_tee_name, &xtest_teec_ctx); } TEEC_Result xtest_teec_open_session(TEEC_Session *session, const TEEC_UUID *uuid, TEEC_Operation *op, uint32_t *ret_orig) { return TEEC_OpenSession(&xtest_teec_ctx, session, uuid, TEEC_LOGIN_PUBLIC, NULL, op, ret_orig); } void xtest_teec_ctx_deinit(void) { TEEC_FinalizeContext(&xtest_teec_ctx); } TEEC_Result ta_crypt_cmd_allocate_operation(ADBG_Case_t *c, TEEC_Session *s, TEE_OperationHandle *oph, uint32_t algo, uint32_t mode, uint32_t max_key_size) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; op.params[0].value.a = 0; op.params[0].value.b = algo; op.params[1].value.a = mode; op.params[1].value.b = max_key_size; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_ALLOCATE_OPERATION, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } if (res == TEEC_SUCCESS) *oph = (TEE_OperationHandle)(uintptr_t)op.params[0].value.a; return res; } TEEC_Result ta_crypt_cmd_allocate_transient_object(ADBG_Case_t *c, TEEC_Session *s, TEE_ObjectType obj_type, uint32_t max_obj_size, TEE_ObjectHandle *o) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; op.params[0].value.a = obj_type; op.params[0].value.b = max_obj_size; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_ALLOCATE_TRANSIENT_OBJECT, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } if (res == TEEC_SUCCESS) *o = (TEE_ObjectHandle)(uintptr_t)op.params[1].value.a; return res; } void xtest_add_attr(size_t *attr_count, TEE_Attribute *attrs, uint32_t attr_id, const void *buf, size_t len) { attrs[*attr_count].attributeID = attr_id; attrs[*attr_count].content.ref.buffer = (void *)buf; attrs[*attr_count].content.ref.length = len; (*attr_count)++; } void xtest_add_attr_value(size_t *attr_count, TEE_Attribute *attrs, uint32_t attr_id, uint32_t value_a, uint32_t value_b) { attrs[*attr_count].attributeID = attr_id; attrs[*attr_count].content.value.a = value_a; attrs[*attr_count].content.value.b = value_b; (*attr_count)++; } struct tee_attr_packed { uint32_t attr_id; uint32_t a; uint32_t b; }; TEE_Result pack_attrs(const TEE_Attribute *attrs, uint32_t attr_count, uint8_t **buf, size_t *blen) { struct tee_attr_packed *a = NULL; uint8_t *b = NULL; size_t bl = 0; size_t n = 0; *buf = NULL; *blen = 0; if (attr_count == 0) return TEE_SUCCESS; bl = sizeof(uint32_t) + sizeof(struct tee_attr_packed) * attr_count; for (n = 0; n < attr_count; n++) { if ((attrs[n].attributeID & TEE_ATTR_BIT_VALUE) != 0) continue; /* Only memrefs need to be updated */ if (!attrs[n].content.ref.buffer) continue; /* Make room for padding */ bl += ROUNDUP(attrs[n].content.ref.length, 4); } b = calloc(1, bl); if (!b) return TEE_ERROR_OUT_OF_MEMORY; *buf = b; *blen = bl; *(uint32_t *)(void *)b = attr_count; b += sizeof(uint32_t); a = (struct tee_attr_packed *)(void *)b; b += sizeof(struct tee_attr_packed) * attr_count; for (n = 0; n < attr_count; n++) { a[n].attr_id = attrs[n].attributeID; if (attrs[n].attributeID & TEE_ATTR_BIT_VALUE) { a[n].a = attrs[n].content.value.a; a[n].b = attrs[n].content.value.b; continue; } a[n].b = attrs[n].content.ref.length; if (!attrs[n].content.ref.buffer) { a[n].a = 0; continue; } memcpy(b, attrs[n].content.ref.buffer, attrs[n].content.ref.length); /* Make buffer pointer relative to *buf */ a[n].a = (uint32_t)(uintptr_t)(b - *buf); /* Round up to good alignment */ b += ROUNDUP(attrs[n].content.ref.length, 4); } return TEE_SUCCESS; } TEEC_Result ta_crypt_cmd_populate_transient_object(ADBG_Case_t *c, TEEC_Session *s, TEE_ObjectHandle o, const TEE_Attribute *attrs, uint32_t attr_count) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; uint8_t *buf = NULL; size_t blen = 0; res = pack_attrs(attrs, attr_count, &buf, &blen); if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) return res; assert((uintptr_t)o <= UINT32_MAX); op.params[0].value.a = (uint32_t)(uintptr_t)o; op.params[1].tmpref.buffer = buf; op.params[1].tmpref.size = blen; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_POPULATE_TRANSIENT_OBJECT, &op, &ret_orig); if (res != TEEC_SUCCESS && res != TEEC_ERROR_TARGET_DEAD) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } free(buf); return res; } TEE_Result ta_crypt_cmd_set_operation_key(ADBG_Case_t *c, TEEC_Session *s, TEE_OperationHandle oph, TEE_ObjectHandle key) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; assert((uintptr_t)oph <= UINT32_MAX); op.params[0].value.a = (uint32_t)(uintptr_t)oph; assert((uintptr_t)key <= UINT32_MAX); op.params[0].value.b = (uint32_t)(uintptr_t)key; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_SET_OPERATION_KEY, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } return res; } TEEC_Result ta_crypt_cmd_free_transient_object(ADBG_Case_t *c, TEEC_Session *s, TEE_ObjectHandle o) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; assert((uintptr_t)o <= UINT32_MAX); op.params[0].value.a = (uint32_t)(uintptr_t)o; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_FREE_TRANSIENT_OBJECT, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } return res; } TEEC_Result ta_crypt_cmd_derive_key(ADBG_Case_t *c, TEEC_Session *s, TEE_OperationHandle oph, TEE_ObjectHandle o, const TEE_Attribute *params, uint32_t paramCount) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; uint8_t *buf = NULL; size_t blen = 0; res = pack_attrs(params, paramCount, &buf, &blen); if (!ADBG_EXPECT_TEEC_SUCCESS(c, res)) return res; assert((uintptr_t)oph <= UINT32_MAX); op.params[0].value.a = (uint32_t)(uintptr_t)oph; assert((uintptr_t)o <= UINT32_MAX); op.params[0].value.b = (uint32_t)(uintptr_t)o; op.params[1].tmpref.buffer = buf; op.params[1].tmpref.size = blen; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_DERIVE_KEY, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } free(buf); return res; } TEEC_Result ta_crypt_cmd_get_object_buffer_attribute(ADBG_Case_t *c, TEEC_Session *s, TEE_ObjectHandle o, uint32_t attr_id, void *buf, size_t *blen) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; assert((uintptr_t)o <= UINT32_MAX); op.params[0].value.a = (uint32_t)(uintptr_t)o; op.params[0].value.b = attr_id; op.params[1].tmpref.buffer = buf; op.params[1].tmpref.size = *blen; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_GET_OBJECT_BUFFER_ATTRIBUTE, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } if (res == TEEC_SUCCESS) *blen = op.params[1].tmpref.size; return res; } TEEC_Result ta_crypt_cmd_free_operation(ADBG_Case_t *c, TEEC_Session *s, TEE_OperationHandle oph) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; op.params[0].value.a = (uint32_t)(uintptr_t)oph; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_FREE_OPERATION, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); } return res; } bool ta_crypt_cmd_is_algo_supported(ADBG_Case_t *c, TEEC_Session *s, uint32_t algo, uint32_t element) { TEEC_Result res = TEEC_ERROR_GENERIC; TEEC_Operation op = TEEC_OPERATION_INITIALIZER; uint32_t ret_orig = 0; TEEC_Result st = TEEC_ERROR_GENERIC; op.params[0].value.a = algo; op.params[0].value.b = element; op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE); res = TEEC_InvokeCommand(s, TA_CRYPT_CMD_IS_ALGO_SUPPORTED, &op, &ret_orig); if (res != TEEC_SUCCESS) { (void)ADBG_EXPECT_TEEC_ERROR_ORIGIN(c, TEEC_ORIGIN_TRUSTED_APP, ret_orig); return res; } st = op.params[1].value.a; ADBG_EXPECT_TRUE(c, st == TEEC_SUCCESS || st == TEEC_ERROR_NOT_SUPPORTED); if (st == TEE_SUCCESS) return true; return false; } TEEC_Result ta_os_test_cmd_client_identity(TEEC_Session *session, uint32_t *login, TEEC_UUID *client_uuid) { TEEC_Operation operation = { }; TEEC_Result result = TEEC_ERROR_GENERIC; operation.params[1].tmpref.buffer = client_uuid; operation.params[1].tmpref.size = sizeof(*client_uuid); operation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE); result = TEEC_InvokeCommand(session, TA_OS_TEST_CMD_CLIENT_IDENTITY, &operation, NULL); if (result != TEEC_SUCCESS) return result; *login = operation.params[0].value.a; return TEEC_SUCCESS; } void xtest_mutex_init(pthread_mutex_t *mutex) { int e = pthread_mutex_init(mutex, NULL); if (e) errx(1, "pthread_mutex_init: %s", strerror(e)); } void xtest_mutex_destroy(pthread_mutex_t *mutex) { int e = pthread_mutex_destroy(mutex); if (e) errx(1, "pthread_mutex_destroy: %s", strerror(e)); } void xtest_mutex_lock(pthread_mutex_t *mutex) { int e = pthread_mutex_lock(mutex); if (e) errx(1, "pthread_mutex_lock: %s", strerror(e)); } void xtest_mutex_unlock(pthread_mutex_t *mutex) { int e = pthread_mutex_unlock(mutex); if (e) errx(1, "pthread_mutex_unlock: %s", strerror(e)); } void xtest_barrier_init(pthread_barrier_t *barrier, unsigned count) { int e = pthread_barrier_init(barrier, NULL, count); if (e) errx(1, "pthread_barrier_init: %s", strerror(e)); } void xtest_barrier_destroy(pthread_barrier_t *barrier) { int e = pthread_barrier_destroy(barrier); if (e) errx(1, "pthread_barrier_destroy: %s", strerror(e)); } int xtest_barrier_wait(pthread_barrier_t *barrier) { int e = pthread_barrier_wait(barrier); if (e && e != PTHREAD_BARRIER_SERIAL_THREAD) errx(1, "pthread _barrier_wait: %s", strerror(e)); return e; }