blob: 5126c1231cebe9824ab2a16843e5854e0bd1a0ea [file] [log] [blame]
/*
* 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 <assert.h>
#include <err.h>
#include <malloc.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <ta_crypt.h>
#include <ta_os_test.h>
#include <utee_defines.h>
#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(_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_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;
}