| // 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; |
| } |