blob: f29c8e997c9b0d4226843f2c5b1f8d2709923b6d [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
* Copyright (c) 2017, Linaro Limited
*/
#include <printk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tee_api_defines.h>
#include <tee_api.h>
#include <tee_api_types.h>
#include <tee_arith_internal.h>
#include <tee_internal_api_extensions.h>
#include <tee_isocket.h>
#include <user_ta_header.h>
#include <utee_syscalls.h>
#include <util.h>
#include "string_ext.h"
#include "base64.h"
#define PROP_STR_MAX 80
#define PROP_ENUMERATOR_NOT_STARTED 0xffffffff
struct prop_enumerator {
uint32_t idx; /* current index */
TEE_PropSetHandle prop_set; /* part of TEE_PROPSET_xxx */
};
const struct user_ta_property tee_props[] = {
{
"gpd.tee.arith.maxBigIntSize",
USER_TA_PROP_TYPE_U32,
&(const uint32_t){CFG_TA_BIGNUM_MAX_BITS}
},
{
"gpd.tee.sockets.version",
USER_TA_PROP_TYPE_U32,
&(const uint32_t){TEE_ISOCKET_VERSION}
},
{
"gpd.tee.sockets.tcp.version",
USER_TA_PROP_TYPE_U32,
&(const uint32_t){TEE_ISOCKET_VERSION}
},
};
static TEE_Result propset_get(TEE_PropSetHandle h,
const struct user_ta_property **eps,
size_t *eps_len)
{
if (h == TEE_PROPSET_CURRENT_TA) {
*eps = ta_props;
*eps_len = ta_num_props;
} else if (h == TEE_PROPSET_CURRENT_CLIENT) {
*eps = NULL;
*eps_len = 0;
} else if (h == TEE_PROPSET_TEE_IMPLEMENTATION) {
*eps = tee_props;
*eps_len = ARRAY_SIZE(tee_props);
} else {
return TEE_ERROR_ITEM_NOT_FOUND;
}
return TEE_SUCCESS;
}
static TEE_Result propget_get_ext_prop(const struct user_ta_property *ep,
enum user_ta_prop_type *type,
void *buf, uint32_t *len)
{
size_t l;
*type = ep->type;
switch (*type) {
case USER_TA_PROP_TYPE_BOOL:
l = sizeof(bool);
break;
case USER_TA_PROP_TYPE_U32:
l = sizeof(uint32_t);
break;
case USER_TA_PROP_TYPE_UUID:
l = sizeof(TEE_UUID);
break;
case USER_TA_PROP_TYPE_IDENTITY:
l = sizeof(TEE_Identity);
break;
case USER_TA_PROP_TYPE_STRING:
/* take the leading 0 into account */
l = strlen(ep->value) + 1;
break;
case USER_TA_PROP_TYPE_BINARY_BLOCK:
/*
* in case of TA property, a binary block is provided as a
* string, which is base64 encoded. We must first decode it,
* without taking into account the zero termination of the
* string
*/
l = *len;
if (!base64_dec(ep->value, strlen(ep->value), buf, &l) &&
(l <= *len))
return TEE_ERROR_GENERIC;
if (*len < l) {
*len = l;
return TEE_ERROR_SHORT_BUFFER;
}
*len = l;
return TEE_SUCCESS;
default:
return TEE_ERROR_GENERIC;
}
if (*len < l) {
*len = l;
return TEE_ERROR_SHORT_BUFFER;
}
*len = l;
memcpy(buf, ep->value, l);
return TEE_SUCCESS;
}
static TEE_Result propget_get_property(TEE_PropSetHandle h, const char *name,
enum user_ta_prop_type *type,
void *buf, uint32_t *len)
{
TEE_Result res;
const struct user_ta_property *eps;
size_t eps_len;
uint32_t prop_type;
uint32_t index;
if (h == TEE_PROPSET_CURRENT_TA || h == TEE_PROPSET_CURRENT_CLIENT ||
h == TEE_PROPSET_TEE_IMPLEMENTATION) {
size_t n;
res = propset_get(h, &eps, &eps_len);
if (res != TEE_SUCCESS)
return res;
for (n = 0; n < eps_len; n++) {
if (!strcmp(name, eps[n].name))
return propget_get_ext_prop(eps + n, type,
buf, len);
}
/* get the index from the name */
res = utee_get_property_name_to_index((unsigned long)h, name,
strlen(name) + 1, &index);
if (res != TEE_SUCCESS)
return res;
res = utee_get_property((unsigned long)h, index, NULL, NULL,
buf, len, &prop_type);
} else {
struct prop_enumerator *pe = (struct prop_enumerator *)h;
uint32_t idx = pe->idx;
if (idx == PROP_ENUMERATOR_NOT_STARTED)
return TEE_ERROR_ITEM_NOT_FOUND;
res = propset_get(pe->prop_set, &eps, &eps_len);
if (res != TEE_SUCCESS)
return res;
if (idx < eps_len)
return propget_get_ext_prop(eps + idx, type, buf, len);
idx -= eps_len;
res = utee_get_property((unsigned long)pe->prop_set, idx,
NULL, NULL, buf, len, &prop_type);
if (res == TEE_ERROR_ITEM_NOT_FOUND)
res = TEE_ERROR_BAD_PARAMETERS;
}
*type = prop_type;
return res;
}
TEE_Result TEE_GetPropertyAsString(TEE_PropSetHandle propsetOrEnumerator,
const char *name, char *value,
uint32_t *value_len)
{
TEE_Result res;
size_t l;
enum user_ta_prop_type type;
void *tmp_buf = 0;
uint32_t tmp_len;
uint32_t uint32_val;
bool bool_val;
TEE_Identity *p_identity_val;
if (!value || !value_len) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
tmp_len = *value_len;
if (tmp_len < sizeof(TEE_Identity))
tmp_len = sizeof(TEE_Identity);
tmp_buf = TEE_Malloc(tmp_len, TEE_USER_MEM_HINT_NO_FILL_ZERO);
if (!tmp_buf) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto out;
}
res = propget_get_property(propsetOrEnumerator, name, &type,
tmp_buf, &tmp_len);
if (res != TEE_SUCCESS) {
if (res == TEE_ERROR_SHORT_BUFFER) {
if (type == USER_TA_PROP_TYPE_BINARY_BLOCK) {
/*
* in this case, we must enlarge the buffer
* with the size of the of the base64 encoded
* see base64_enc() function
*/
tmp_len = base64_enc_len(tmp_len);
}
*value_len = tmp_len;
}
goto out;
}
switch (type) {
case USER_TA_PROP_TYPE_BOOL:
bool_val = *((bool *)tmp_buf);
l = strlcpy(value, (bool_val ? "true" : "false"), *value_len);
break;
case USER_TA_PROP_TYPE_U32:
uint32_val = *((uint32_t *)tmp_buf);
l = snprintf(value, *value_len, "%u", uint32_val);
break;
case USER_TA_PROP_TYPE_UUID:
l = snprintk(value, *value_len, "%pUl", tmp_buf);
break;
case USER_TA_PROP_TYPE_IDENTITY:
p_identity_val = ((TEE_Identity *)tmp_buf);
l = snprintk(value, *value_len, "%u:%pUl",
p_identity_val->login,
(void *)(&(p_identity_val->uuid)));
break;
case USER_TA_PROP_TYPE_STRING:
l = strlcpy(value, tmp_buf, *value_len);
break;
case USER_TA_PROP_TYPE_BINARY_BLOCK:
l = *value_len; /* l includes the zero-termination */
if (!base64_enc(tmp_buf, tmp_len, value, &l) &&
(l <= *value_len)) {
res = TEE_ERROR_GENERIC;
goto out;
}
l--; /* remove the zero-termination that is added later */
break;
default:
res = TEE_ERROR_BAD_FORMAT;
goto out;
}
l++; /* include zero termination */
if (l > *value_len)
res = TEE_ERROR_SHORT_BUFFER;
*value_len = l;
out:
if (tmp_buf)
TEE_Free(tmp_buf);
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND &&
res != TEE_ERROR_SHORT_BUFFER)
TEE_Panic(0);
return res;
}
TEE_Result TEE_GetPropertyAsBool(TEE_PropSetHandle propsetOrEnumerator,
const char *name, bool *value)
{
TEE_Result res;
enum user_ta_prop_type type;
uint32_t bool_len = sizeof(bool);
if (value == NULL) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
type = USER_TA_PROP_TYPE_BOOL;
res = propget_get_property(propsetOrEnumerator, name, &type,
value, &bool_len);
if (type != USER_TA_PROP_TYPE_BOOL)
res = TEE_ERROR_BAD_FORMAT;
if (res != TEE_SUCCESS)
goto out;
out:
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND &&
res != TEE_ERROR_BAD_FORMAT)
TEE_Panic(0);
return res;
}
TEE_Result TEE_GetPropertyAsU32(TEE_PropSetHandle propsetOrEnumerator,
const char *name, uint32_t *value)
{
TEE_Result res;
enum user_ta_prop_type type;
uint32_t uint32_len = sizeof(uint32_t);
if (!value) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
type = USER_TA_PROP_TYPE_U32;
res = propget_get_property(propsetOrEnumerator, name, &type,
value, &uint32_len);
if (type != USER_TA_PROP_TYPE_U32)
res = TEE_ERROR_BAD_FORMAT;
out:
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND &&
res != TEE_ERROR_BAD_FORMAT)
TEE_Panic(0);
return res;
}
TEE_Result TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator,
const char *name, void *value,
uint32_t *value_len)
{
TEE_Result res;
enum user_ta_prop_type type;
if (!value || !value_len) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
type = USER_TA_PROP_TYPE_BINARY_BLOCK;
res = propget_get_property(propsetOrEnumerator, name, &type,
value, value_len);
if (type != USER_TA_PROP_TYPE_BINARY_BLOCK)
res = TEE_ERROR_BAD_FORMAT;
out:
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND &&
res != TEE_ERROR_BAD_FORMAT &&
res != TEE_ERROR_SHORT_BUFFER)
TEE_Panic(0);
return res;
}
TEE_Result TEE_GetPropertyAsUUID(TEE_PropSetHandle propsetOrEnumerator,
const char *name, TEE_UUID *value)
{
TEE_Result res;
enum user_ta_prop_type type;
uint32_t uuid_len = sizeof(TEE_UUID);
if (!value) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
type = USER_TA_PROP_TYPE_UUID;
res = propget_get_property(propsetOrEnumerator, name, &type,
value, &uuid_len);
if (type != USER_TA_PROP_TYPE_UUID)
res = TEE_ERROR_BAD_FORMAT;
out:
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND &&
res != TEE_ERROR_BAD_FORMAT)
TEE_Panic(0);
return res;
}
TEE_Result TEE_GetPropertyAsIdentity(TEE_PropSetHandle propsetOrEnumerator,
const char *name, TEE_Identity *value)
{
TEE_Result res;
enum user_ta_prop_type type;
uint32_t identity_len = sizeof(TEE_Identity);
if (!value) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
type = USER_TA_PROP_TYPE_IDENTITY;
res = propget_get_property(propsetOrEnumerator, name, &type,
value, &identity_len);
if (type != USER_TA_PROP_TYPE_IDENTITY)
res = TEE_ERROR_BAD_FORMAT;
out:
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND &&
res != TEE_ERROR_BAD_FORMAT)
TEE_Panic(0);
return res;
}
TEE_Result TEE_AllocatePropertyEnumerator(TEE_PropSetHandle *enumerator)
{
TEE_Result res;
struct prop_enumerator *pe;
if (!enumerator) {
res = TEE_ERROR_BAD_PARAMETERS;
goto err;
}
pe = TEE_Malloc(sizeof(struct prop_enumerator),
TEE_USER_MEM_HINT_NO_FILL_ZERO);
if (pe == NULL) {
res = TEE_ERROR_OUT_OF_MEMORY;
goto err;
}
*enumerator = (TEE_PropSetHandle) pe;
TEE_ResetPropertyEnumerator(*enumerator);
goto out;
err:
if (res == TEE_ERROR_OUT_OF_MEMORY)
return res;
TEE_Panic(0);
out:
return TEE_SUCCESS;
}
void TEE_ResetPropertyEnumerator(TEE_PropSetHandle enumerator)
{
struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
pe->idx = PROP_ENUMERATOR_NOT_STARTED;
}
void TEE_FreePropertyEnumerator(TEE_PropSetHandle enumerator)
{
struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
TEE_Free(pe);
}
void TEE_StartPropertyEnumerator(TEE_PropSetHandle enumerator,
TEE_PropSetHandle propSet)
{
struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
if (!pe)
return;
pe->idx = 0;
pe->prop_set = propSet;
}
TEE_Result TEE_GetPropertyName(TEE_PropSetHandle enumerator,
void *name, uint32_t *name_len)
{
TEE_Result res;
struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
const struct user_ta_property *eps;
size_t eps_len;
const char *str;
size_t bufferlen;
if (!pe || !name || !name_len) {
res = TEE_ERROR_BAD_PARAMETERS;
goto err;
}
bufferlen = *name_len;
res = propset_get(pe->prop_set, &eps, &eps_len);
if (res != TEE_SUCCESS)
goto err;
if (pe->idx < eps_len) {
str = eps[pe->idx].name;
bufferlen = strlcpy(name, str, *name_len) + 1;
if (bufferlen > *name_len)
res = TEE_ERROR_SHORT_BUFFER;
*name_len = bufferlen;
} else {
res = utee_get_property((unsigned long)pe->prop_set,
pe->idx - eps_len,
name, name_len, NULL, NULL, NULL);
if (res != TEE_SUCCESS)
goto err;
}
err:
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND &&
res != TEE_ERROR_SHORT_BUFFER)
TEE_Panic(0);
return res;
}
TEE_Result TEE_GetNextProperty(TEE_PropSetHandle enumerator)
{
TEE_Result res;
struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
uint32_t next_idx;
const struct user_ta_property *eps;
size_t eps_len;
if (!pe) {
res = TEE_ERROR_BAD_PARAMETERS;
goto out;
}
if (pe->idx == PROP_ENUMERATOR_NOT_STARTED) {
res = TEE_ERROR_ITEM_NOT_FOUND;
goto out;
}
res = propset_get(pe->prop_set, &eps, &eps_len);
if (res != TEE_SUCCESS)
goto out;
next_idx = pe->idx + 1;
pe->idx = next_idx;
if (next_idx < eps_len)
res = TEE_SUCCESS;
else
res = utee_get_property((unsigned long)pe->prop_set,
next_idx - eps_len,
NULL, NULL, NULL, NULL, NULL);
out:
if (res != TEE_SUCCESS &&
res != TEE_ERROR_ITEM_NOT_FOUND)
TEE_Panic(0);
return res;
}