| /* |
| * Copyright (c) 2014, STMicroelectronics International N.V. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License Version 2 as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include "xtest_helpers.h" |
| #include "xtest_test.h" |
| |
| #include <ta_crypt.h> |
| #include <utee_defines.h> |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include <malloc.h> |
| #include <assert.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(_device, &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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| |
| 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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| |
| 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; |
| uint8_t *b; |
| size_t bl; |
| size_t n; |
| |
| *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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| uint8_t *buf; |
| size_t blen; |
| |
| 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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| |
| 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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| |
| 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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| uint8_t *buf; |
| size_t blen; |
| |
| 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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| |
| 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_Operation op = TEEC_OPERATION_INITIALIZER; |
| uint32_t ret_orig; |
| |
| 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; |
| } |