/* * Copyright (c) 2014, STMicroelectronics International N.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include "string_ext.h" #include "base64.h" #define PROP_STR_MAX 80 #define PROP_ENUMERATOR_NOT_STARTED 0xffffffff struct prop_enumerator { uint32_t idx; TEE_PropSetHandle prop_set; }; struct prop_value { enum user_ta_prop_type type; union { bool bool_val; uint32_t int_val; TEE_UUID uuid_val; TEE_Identity identity_val; char str_val[PROP_STR_MAX]; } u; }; typedef TEE_Result(*ta_propget_func_t) (struct prop_value *pv); struct prop_set { const char *str; ta_propget_func_t get; }; static TEE_Result propget_gpd_ta_app_id(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_UUID; return utee_get_property(UTEE_PROP_TA_APP_ID, &pv->u.uuid_val, sizeof(pv->u.uuid_val)); } static TEE_Result propget_gpd_client_identity(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_IDENTITY; return utee_get_property(UTEE_PROP_CLIENT_ID, &pv->u.identity_val, sizeof(pv->u.identity_val)); } static TEE_Result propget_gpd_tee_api_version(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_STRING; return utee_get_property(UTEE_PROP_TEE_API_VERSION, &pv->u.str_val, sizeof(pv->u.str_val)); } static TEE_Result propget_gpd_tee_description(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_STRING; return utee_get_property(UTEE_PROP_TEE_DESCR, &pv->u.str_val, sizeof(pv->u.str_val)); } static TEE_Result propget_gpd_tee_device_id(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_UUID; return utee_get_property(UTEE_PROP_TEE_DEV_ID, &pv->u.uuid_val, sizeof(pv->u.uuid_val)); } static TEE_Result propget_gpd_tee_sys_time_protection_level(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_U32; return utee_get_property(UTEE_PROP_TEE_SYS_TIME_PROT_LEVEL, &pv->u.int_val, sizeof(pv->u.int_val)); } static TEE_Result propget_gpd_tee_ta_time_protection_level(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_U32; return utee_get_property(UTEE_PROP_TEE_TA_TIME_PROT_LEVEL, &pv->u.int_val, sizeof(pv->u.int_val)); } static TEE_Result propget_gpd_tee_arith_max_big_int_size(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_U32; pv->u.int_val = TEE_MAX_NUMBER_OF_SUPPORTED_BITS; return TEE_SUCCESS; } static TEE_Result propget_gpd_tee_cryptography_ecc(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_BOOL; return utee_get_property(UTEE_PROP_TEE_CRYPTOGRAPHY_ECC, &pv->u.bool_val, sizeof(pv->u.bool_val)); } static TEE_Result propget_gpd_tee_ts_antiroll_protection_level( struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_U32; return utee_get_property(UTEE_PROP_TEE_TS_ANTIROLL_PROT_LEVEL, &pv->u.int_val, sizeof(pv->u.int_val)); } static TEE_Result propget_gpd_tee_trustedos_impl_version(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_STRING; return utee_get_property(UTEE_PROP_TEE_TRUSTEDOS_IMPL_VERSION, &pv->u.str_val, sizeof(pv->u.str_val)); } static TEE_Result propget_gpd_tee_trustedos_impl_bin_version( struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_U32; return utee_get_property(UTEE_PROP_TEE_TRUSTEDOS_IMPL_BIN_VERSION, &pv->u.int_val, sizeof(pv->u.int_val)); } static TEE_Result propget_gpd_tee_trustedos_manufacturer(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_STRING; return utee_get_property(UTEE_PROP_TEE_TRUSTEDOS_MANUFACTURER, &pv->u.str_val, sizeof(pv->u.str_val)); } static TEE_Result propget_gpd_tee_fw_impl_version(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_STRING; return utee_get_property(UTEE_PROP_TEE_FW_IMPL_VERSION, &pv->u.str_val, sizeof(pv->u.str_val)); } static TEE_Result propget_gpd_tee_fw_impl_bin_version(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_U32; return utee_get_property(UTEE_PROP_TEE_FW_IMPL_BIN_VERSION, &pv->u.int_val, sizeof(pv->u.int_val)); } static TEE_Result propget_gpd_tee_fw_manufacturer(struct prop_value *pv) { pv->type = USER_TA_PROP_TYPE_STRING; return utee_get_property(UTEE_PROP_TEE_FW_MANUFACTURER, &pv->u.str_val, sizeof(pv->u.str_val)); } static const struct prop_set propset_current_ta[] = { {"gpd.ta.appID", propget_gpd_ta_app_id}, }; static const size_t propset_current_ta_len = sizeof(propset_current_ta) / sizeof(propset_current_ta[0]); static const struct prop_set propset_current_client[] = { {"gpd.client.identity", propget_gpd_client_identity}, }; static const size_t propset_current_client_len = sizeof(propset_current_client) / sizeof(propset_current_client[0]); static const struct prop_set propset_implementation[] = { {"gpd.tee.apiversion", propget_gpd_tee_api_version}, {"gpd.tee.description", propget_gpd_tee_description}, {"gpd.tee.deviceID", propget_gpd_tee_device_id}, {"gpd.tee.systemTime.protectionLevel", propget_gpd_tee_sys_time_protection_level}, {"gpd.tee.TAPersistentTime.protectionLevel", propget_gpd_tee_ta_time_protection_level}, {"gpd.tee.arith.maxBigIntSize", propget_gpd_tee_arith_max_big_int_size}, {"gpd.tee.cryptography.ecc", propget_gpd_tee_cryptography_ecc}, {"gpd.tee.trustedStorage.antiRollback.protectionLevel", propget_gpd_tee_ts_antiroll_protection_level}, {"gpd.tee.trustedos.implementation.version", propget_gpd_tee_trustedos_impl_version}, {"gpd.tee.trustedos.implementation.binaryversion", propget_gpd_tee_trustedos_impl_bin_version}, {"gpd.tee.trustedos.manufacturer", propget_gpd_tee_trustedos_manufacturer}, {"gpd.tee.firmware.implementation.version", propget_gpd_tee_fw_impl_version}, {"gpd.tee.firmware.implementation.binaryversion", propget_gpd_tee_fw_impl_bin_version}, {"gpd.tee.firmware.manufacturer", propget_gpd_tee_fw_manufacturer}, }; static const size_t propset_implementation_len = sizeof(propset_implementation) / sizeof(propset_implementation[0]); static TEE_Result propset_get(TEE_PropSetHandle h, const struct prop_set **ps, size_t *ps_len, const struct user_ta_property **eps, size_t *eps_len) { if (h == TEE_PROPSET_CURRENT_TA) { *ps = propset_current_ta; *ps_len = propset_current_ta_len; *eps = ta_props; *eps_len = ta_num_props; } else if (h == TEE_PROPSET_CURRENT_CLIENT) { *ps = propset_current_client; *ps_len = propset_current_client_len; *eps = NULL; *eps_len = 0; } else if (h == TEE_PROPSET_TEE_IMPLEMENTATION) { *ps = propset_implementation; *ps_len = propset_implementation_len; *eps = NULL; *eps_len = 0; } else { return TEE_ERROR_ITEM_NOT_FOUND; } return TEE_SUCCESS; } static TEE_Result propget_get_ext_prop(const struct user_ta_property *ep, struct prop_value *pv) { size_t l; pv->type = ep->type; switch (ep->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: case USER_TA_PROP_TYPE_BINARY_BLOCK: /* Handle too large strings by truncating them */ strlcpy(pv->u.str_val, ep->value, sizeof(pv->u.str_val)); return TEE_SUCCESS; default: return TEE_ERROR_GENERIC; } memcpy(&pv->u, ep->value, l); return TEE_SUCCESS; } static TEE_Result propget_get_property(TEE_PropSetHandle h, char *name, struct prop_value *pv) { TEE_Result res; const struct prop_set *ps; size_t ps_len; const struct user_ta_property *eps; size_t eps_len; if (h == TEE_PROPSET_CURRENT_TA || h == TEE_PROPSET_CURRENT_CLIENT || h == TEE_PROPSET_TEE_IMPLEMENTATION) { size_t n; res = propset_get(h, &ps, &ps_len, &eps, &eps_len); if (res != TEE_SUCCESS) return res; for (n = 0; n < ps_len; n++) { if (strcmp(name, ps[n].str) == 0) return ps[n].get(pv); } for (n = 0; n < eps_len; n++) { if (strcmp(name, eps[n].name) == 0) return propget_get_ext_prop(eps + n, pv); } return TEE_ERROR_ITEM_NOT_FOUND; } 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, &ps, &ps_len, &eps, &eps_len); if (res != TEE_SUCCESS) return res; if (idx < ps_len) return ps[idx].get(pv); idx -= ps_len; if (idx < eps_len) return propget_get_ext_prop(eps + idx, pv); return TEE_ERROR_BAD_PARAMETERS; } } TEE_Result TEE_GetPropertyAsString(TEE_PropSetHandle propsetOrEnumerator, char *name, char *valueBuffer, uint32_t *valueBufferLen) { TEE_Result res; struct prop_value pv; size_t l; size_t bufferlen; if (valueBuffer == NULL || valueBufferLen == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } bufferlen = *valueBufferLen; res = propget_get_property(propsetOrEnumerator, name, &pv); if (res != TEE_SUCCESS) goto err; switch (pv.type) { case USER_TA_PROP_TYPE_BOOL: l = strlcpy(valueBuffer, pv.u.bool_val ? "true" : "false", bufferlen); break; case USER_TA_PROP_TYPE_U32: l = snprintf(valueBuffer, bufferlen, "%u", (unsigned int)pv.u.int_val); break; case USER_TA_PROP_TYPE_UUID: l = snprintf(valueBuffer, bufferlen, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", (unsigned int)pv.u.uuid_val.timeLow, pv.u.uuid_val.timeMid, pv.u.uuid_val.timeHiAndVersion, pv.u.uuid_val.clockSeqAndNode[0], pv.u.uuid_val.clockSeqAndNode[1], pv.u.uuid_val.clockSeqAndNode[2], pv.u.uuid_val.clockSeqAndNode[3], pv.u.uuid_val.clockSeqAndNode[4], pv.u.uuid_val.clockSeqAndNode[5], pv.u.uuid_val.clockSeqAndNode[6], pv.u.uuid_val.clockSeqAndNode[7]); break; case USER_TA_PROP_TYPE_IDENTITY: l = snprintf(valueBuffer, bufferlen, "%u:%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", (unsigned int)pv.u.identity_val.login, (unsigned int)pv.u.identity_val.uuid.timeLow, pv.u.identity_val.uuid.timeMid, pv.u.identity_val.uuid.timeHiAndVersion, pv.u.identity_val.uuid.clockSeqAndNode[0], pv.u.identity_val.uuid.clockSeqAndNode[1], pv.u.identity_val.uuid.clockSeqAndNode[2], pv.u.identity_val.uuid.clockSeqAndNode[3], pv.u.identity_val.uuid.clockSeqAndNode[4], pv.u.identity_val.uuid.clockSeqAndNode[5], pv.u.identity_val.uuid.clockSeqAndNode[6], pv.u.identity_val.uuid.clockSeqAndNode[7]); break; case USER_TA_PROP_TYPE_STRING: case USER_TA_PROP_TYPE_BINARY_BLOCK: l = strlcpy(valueBuffer, pv.u.str_val, bufferlen); break; default: res = TEE_ERROR_BAD_FORMAT; goto err; } /* The size "must account for the zero terminator" */ *valueBufferLen = l + 1; if (l >= bufferlen) { res = TEE_ERROR_SHORT_BUFFER; goto err; } goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND || res == TEE_ERROR_SHORT_BUFFER) return res; TEE_Panic(0); out: return TEE_SUCCESS; } TEE_Result TEE_GetPropertyAsBool(TEE_PropSetHandle propsetOrEnumerator, char *name, bool *value) { TEE_Result res; struct prop_value pv; if (value == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } res = propget_get_property(propsetOrEnumerator, name, &pv); if (res != TEE_SUCCESS) goto err; if (pv.type != USER_TA_PROP_TYPE_BOOL) { res = TEE_ERROR_BAD_FORMAT; goto err; } *value = pv.u.bool_val; goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND || res == TEE_ERROR_BAD_FORMAT) return res; TEE_Panic(0); out: return TEE_SUCCESS; } TEE_Result TEE_GetPropertyAsU32(TEE_PropSetHandle propsetOrEnumerator, char *name, uint32_t *value) { TEE_Result res; struct prop_value pv; if (value == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } res = propget_get_property(propsetOrEnumerator, name, &pv); if (res != TEE_SUCCESS) goto err; if (pv.type != USER_TA_PROP_TYPE_U32) { res = TEE_ERROR_BAD_FORMAT; goto err; } *value = pv.u.int_val; goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND || res == TEE_ERROR_BAD_FORMAT) return res; TEE_Panic(0); out: return TEE_SUCCESS; } TEE_Result TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator, char *name, void *valueBuffer, uint32_t *valueBufferLen) { TEE_Result res; struct prop_value pv; void *val; int val_len; size_t size; if (valueBuffer == NULL || valueBufferLen == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } res = propget_get_property(propsetOrEnumerator, name, &pv); if (res != TEE_SUCCESS) goto err; if (pv.type != USER_TA_PROP_TYPE_BINARY_BLOCK) { res = TEE_ERROR_BAD_FORMAT; goto err; } val = pv.u.str_val; val_len = strlen(val); size = *valueBufferLen; if (!base64_dec(val, val_len, valueBuffer, &size)) { res = TEE_ERROR_SHORT_BUFFER; goto err; } *valueBufferLen = size; goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND || res == TEE_ERROR_BAD_FORMAT || res == TEE_ERROR_SHORT_BUFFER) return res; TEE_Panic(0); out: return TEE_SUCCESS; } TEE_Result TEE_GetPropertyAsUUID(TEE_PropSetHandle propsetOrEnumerator, char *name, TEE_UUID *value) { TEE_Result res; struct prop_value pv; if (value == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } res = propget_get_property(propsetOrEnumerator, name, &pv); if (res != TEE_SUCCESS) goto err; if (pv.type != USER_TA_PROP_TYPE_UUID) { res = TEE_ERROR_BAD_FORMAT; goto err; } *value = pv.u.uuid_val; /* struct copy */ goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND || res == TEE_ERROR_BAD_FORMAT) return res; TEE_Panic(0); out: return TEE_SUCCESS; } TEE_Result TEE_GetPropertyAsIdentity(TEE_PropSetHandle propsetOrEnumerator, char *name, TEE_Identity *value) { TEE_Result res; struct prop_value pv; if (value == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } res = propget_get_property(propsetOrEnumerator, name, &pv); if (res != TEE_SUCCESS) goto err; if (pv.type != USER_TA_PROP_TYPE_IDENTITY) { res = TEE_ERROR_BAD_FORMAT; goto err; } *value = pv.u.identity_val; /* struct copy */ goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND || res == TEE_ERROR_BAD_FORMAT) return res; TEE_Panic(0); out: return TEE_SUCCESS; } TEE_Result TEE_AllocatePropertyEnumerator(TEE_PropSetHandle *enumerator) { TEE_Result res; struct prop_enumerator *pe; if (enumerator == NULL) { 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 == NULL) return; pe->idx = 0; pe->prop_set = propSet; } TEE_Result TEE_GetPropertyName(TEE_PropSetHandle enumerator, void *nameBuffer, uint32_t *nameBufferLen) { TEE_Result res; struct prop_enumerator *pe = (struct prop_enumerator *)enumerator; const struct prop_set *ps; size_t ps_len; const struct user_ta_property *eps; size_t eps_len; size_t l; const char *str; size_t bufferlen; if (pe == NULL || nameBuffer == NULL || nameBufferLen == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } bufferlen = *nameBufferLen; res = propset_get(pe->prop_set, &ps, &ps_len, &eps, &eps_len); if (res != TEE_SUCCESS) goto err; if (pe->idx < ps_len) str = ps[pe->idx].str; else if ((pe->idx - ps_len) < eps_len) str = ta_props[pe->idx - ps_len].name; else { res = TEE_ERROR_ITEM_NOT_FOUND; goto err; } l = strlcpy(nameBuffer, str, bufferlen); /* The size "must account for the zero terminator" */ *nameBufferLen = l + 1; if (l >= bufferlen) { res = TEE_ERROR_SHORT_BUFFER; goto err; } goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND || res == TEE_ERROR_SHORT_BUFFER) return res; TEE_Panic(0); out: return TEE_SUCCESS; } TEE_Result TEE_GetNextProperty(TEE_PropSetHandle enumerator) { TEE_Result res; struct prop_enumerator *pe = (struct prop_enumerator *)enumerator; uint32_t next_idx; const struct prop_set *ps; size_t ps_len; const struct user_ta_property *eps; size_t eps_len; if (pe == NULL) { res = TEE_ERROR_BAD_PARAMETERS; goto err; } if (pe->idx == PROP_ENUMERATOR_NOT_STARTED) { res = TEE_ERROR_ITEM_NOT_FOUND; goto err; } res = propset_get(pe->prop_set, &ps, &ps_len, &eps, &eps_len); if (res != TEE_SUCCESS) goto err; next_idx = pe->idx + 1; pe->idx = next_idx; if (next_idx >= (ps_len + eps_len)) { res = TEE_ERROR_ITEM_NOT_FOUND; goto err; } goto out; err: if (res == TEE_ERROR_ITEM_NOT_FOUND) return res; TEE_Panic(0); out: return TEE_SUCCESS; }