diff --git a/host/xtest/CMakeLists.txt b/host/xtest/CMakeLists.txt index e29b04515..3e84b2c4e 100644 --- a/host/xtest/CMakeLists.txt +++ b/host/xtest/CMakeLists.txt @@ -59,6 +59,7 @@ set (SRC xtest_helpers.c xtest_main.c xtest_test.c + xtest_uuid_helpers.c ) set_source_files_properties( diff --git a/host/xtest/Makefile b/host/xtest/Makefile index 9f0998cee..7ac0a3b12 100644 --- a/host/xtest/Makefile +++ b/host/xtest/Makefile @@ -77,7 +77,8 @@ srcs += adbg/src/adbg_case.c \ stats.c \ xtest_helpers.c \ xtest_main.c \ - xtest_test.c + xtest_test.c \ + xtest_uuid_helpers.c ifeq ($(CFG_SECSTOR_TA_MGMT_PTA),y) srcs += install_ta.c diff --git a/host/xtest/regression_1000.c b/host/xtest/regression_1000.c index 38ccc931c..8142f3760 100644 --- a/host/xtest/regression_1000.c +++ b/host/xtest/regression_1000.c @@ -23,6 +23,7 @@ #include "xtest_test.h" #include "xtest_helpers.h" +#include "xtest_uuid_helpers.h" #include #include @@ -2036,3 +2037,145 @@ static void xtest_tee_test_1025(ADBG_Case_t *c) } ADBG_CASE_DEFINE(regression, 1025, xtest_tee_test_1025, "Test memref NULL and/or 0 bytes size"); + +#define TEE_UUID_NS_NAME_SIZE 128 + +/* + * TEE Client UUID name space identifier (UUIDv4) + * + * Value here is random UUID that is allocated as name space identifier for + * forming Client UUID's for TEE environment using UUIDv5 scheme. + */ +static const char *client_uuid_linux_ns = "58ac9ca0-2086-4683-a1b8-ec4bc08e01b6"; + +/* TEEC_LOGIN_PUBLIC's Client UUID is NIL UUID */ +static TEEC_UUID client_uuid_public = { }; + +static void xtest_tee_test_1026(ADBG_Case_t *c) +{ + TEEC_Result result = TEEC_ERROR_GENERIC; + uint32_t ret_orig = 0; + TEEC_Session session = { }; + uint32_t login = UINT32_MAX; + TEEC_UUID client_uuid = { }; + + result = TEEC_OpenSession(&xtest_teec_ctx, &session, &os_test_ta_uuid, + TEEC_LOGIN_PUBLIC, NULL, NULL, &ret_orig); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + return; + + result = ta_os_test_cmd_client_identity(&session, &login, + &client_uuid); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + goto out; + + ADBG_EXPECT_COMPARE_UNSIGNED(c, login, ==, TEEC_LOGIN_PUBLIC); + + ADBG_EXPECT_EQUAL(c, &client_uuid_public, &client_uuid, + sizeof(TEEC_UUID)); + +out: + TEEC_CloseSession(&session); +} + +ADBG_CASE_DEFINE(regression, 1026, xtest_tee_test_1026, + "Session: public login"); + +static void xtest_tee_test_1027(ADBG_Case_t *c) +{ + TEEC_Result result = TEEC_ERROR_GENERIC; + uint32_t ret_orig = 0; + TEEC_Session session = { }; + uint32_t login = UINT32_MAX; + TEEC_UUID client_uuid = { }; + TEEC_UUID expected_client_uuid = { }; + TEEC_UUID uuid_ns = { }; + char uuid_name[TEE_UUID_NS_NAME_SIZE] = { }; + + result = xtest_uuid_from_str(&uuid_ns, client_uuid_linux_ns); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + return; + + sprintf(uuid_name, "uid=%x", geteuid()); + + result = xtest_uuid_v5(&expected_client_uuid, &uuid_ns, uuid_name, + strlen(uuid_name)); + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + return; + + result = TEEC_OpenSession(&xtest_teec_ctx, &session, &os_test_ta_uuid, + TEEC_LOGIN_USER, NULL, NULL, &ret_orig); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + return; + + result = ta_os_test_cmd_client_identity(&session, &login, + &client_uuid); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + goto out; + + ADBG_EXPECT_COMPARE_UNSIGNED(c, login, ==, TEEC_LOGIN_USER); + + ADBG_EXPECT_EQUAL(c, &expected_client_uuid, &client_uuid, + sizeof(TEEC_UUID)); + +out: + TEEC_CloseSession(&session); +} + +ADBG_CASE_DEFINE(regression, 1027, xtest_tee_test_1027, + "Session: user login for current user"); + +static void xtest_tee_test_1028(ADBG_Case_t *c) +{ + TEEC_Result result = TEEC_ERROR_GENERIC; + uint32_t ret_orig = 0; + TEEC_Session session = { }; + uint32_t login = UINT32_MAX; + TEEC_UUID client_uuid = { }; + TEEC_UUID expected_client_uuid = { }; + TEEC_UUID uuid_ns = { }; + char uuid_name[TEE_UUID_NS_NAME_SIZE] = { }; + uint32_t group = 0; + + group = getegid(); + + result = xtest_uuid_from_str(&uuid_ns, client_uuid_linux_ns); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + return; + + sprintf(uuid_name, "gid=%x", group); + + result = xtest_uuid_v5(&expected_client_uuid, &uuid_ns, uuid_name, + strlen(uuid_name)); + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + return; + + result = TEEC_OpenSession(&xtest_teec_ctx, &session, &os_test_ta_uuid, + TEEC_LOGIN_GROUP, &group, NULL, &ret_orig); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + return; + + result = ta_os_test_cmd_client_identity(&session, &login, + &client_uuid); + + if (!ADBG_EXPECT_TEEC_SUCCESS(c, result)) + goto out; + + ADBG_EXPECT_COMPARE_UNSIGNED(c, login, ==, TEEC_LOGIN_GROUP); + + ADBG_EXPECT_EQUAL(c, &expected_client_uuid, &client_uuid, + sizeof(TEEC_UUID)); + +out: + TEEC_CloseSession(&session); +} + +ADBG_CASE_DEFINE(regression, 1028, xtest_tee_test_1028, + "Session: group login for current user's effective group"); diff --git a/host/xtest/xtest_helpers.c b/host/xtest/xtest_helpers.c index d8b286fdc..5126c1231 100644 --- a/host/xtest/xtest_helpers.c +++ b/host/xtest/xtest_helpers.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "xtest_helpers.h" @@ -413,6 +414,31 @@ bool ta_crypt_cmd_is_algo_supported(ADBG_Case_t *c, TEEC_Session *s, 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); diff --git a/host/xtest/xtest_helpers.h b/host/xtest/xtest_helpers.h index 9096c38ca..5cf55bfb1 100644 --- a/host/xtest/xtest_helpers.h +++ b/host/xtest/xtest_helpers.h @@ -97,6 +97,10 @@ TEEC_Result ta_crypt_cmd_free_operation(ADBG_Case_t *c, bool ta_crypt_cmd_is_algo_supported(ADBG_Case_t *c, TEEC_Session *s, uint32_t alg, uint32_t element); +TEEC_Result ta_os_test_cmd_client_identity(TEEC_Session *session, + uint32_t *login, + TEEC_UUID *client_uuid); + void xtest_add_attr(size_t *attr_count, TEE_Attribute *attrs, uint32_t attr_id, const void *buf, size_t len); void xtest_add_attr_value(size_t *attr_count, TEE_Attribute *attrs, diff --git a/host/xtest/xtest_uuid_helpers.c b/host/xtest/xtest_uuid_helpers.c new file mode 100644 index 000000000..529fff829 --- /dev/null +++ b/host/xtest/xtest_uuid_helpers.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xtest_uuid_helpers.h" + +static int hex(char c) +{ + char lc = tolower(c); + + if (isdigit(lc)) + return lc - '0'; + if (isxdigit(lc)) + return lc - 'a' + 10; + return -1; +} + +static uint32_t parse_hex(const char *s, size_t nchars, uint32_t *res) +{ + uint32_t v = 0; + size_t n = 0; + int c = 0; + + for (n = 0; n < nchars; n++) { + c = hex(s[n]); + if (c == -1) { + *res = TEE_ERROR_BAD_FORMAT; + goto out; + } + v = (v << 4) + c; + } + *res = TEE_SUCCESS; +out: + return v; +} + +TEEC_Result xtest_uuid_from_str(TEEC_UUID *uuid, const char *s) +{ + TEEC_Result res = TEEC_SUCCESS; + TEEC_UUID u = { }; + const char *p = s; + size_t i = 0; + + if (!p || strnlen(p, 37) != 36) + return TEEC_ERROR_BAD_FORMAT; + if (p[8] != '-' || p[13] != '-' || p[18] != '-' || p[23] != '-') + return TEEC_ERROR_BAD_FORMAT; + + u.timeLow = parse_hex(p, 8, &res); + if (res) + goto out; + p += 9; + u.timeMid = parse_hex(p, 4, &res); + if (res) + goto out; + p += 5; + u.timeHiAndVersion = parse_hex(p, 4, &res); + if (res) + goto out; + p += 5; + for (i = 0; i < 8; i++) { + u.clockSeqAndNode[i] = parse_hex(p, 2, &res); + if (res) + goto out; + if (i == 1) + p += 3; + else + p += 2; + } + *uuid = u; +out: + return res; +} + +TEEC_Result xtest_uuid_v5(TEEC_UUID *uuid, const TEEC_UUID *ns, + const void *name, size_t size) +{ + TEEC_Result res = TEEC_SUCCESS; + EVP_MD_CTX *mdctx = NULL; + const EVP_MD *md = NULL; + unsigned char hash[EVP_MAX_MD_SIZE] = { }; + unsigned int md_len = 0; + unsigned char nsbe[16] = { }; + uint32_t be32 = 0; + uint16_t be16 = 0; + int ret = 0; + + /* Convert from host to big endian */ + be32 = htobe32(ns->timeLow); + memcpy(&nsbe[0], &be32, sizeof(be32)); + be16 = htobe16(ns->timeMid); + memcpy(&nsbe[4], &be16, sizeof(be16)); + be16 = htobe16(ns->timeHiAndVersion); + memcpy(&nsbe[6], &be16, sizeof(be16)); + memcpy(&nsbe[8], &ns->clockSeqAndNode, sizeof(ns->clockSeqAndNode)); + + mdctx = EVP_MD_CTX_create(); + if (!mdctx) + return TEEC_ERROR_OUT_OF_MEMORY; + md = EVP_sha1(); + if (!md) { + res = TEEC_ERROR_NOT_SUPPORTED; + goto out; + } + ret = EVP_DigestInit_ex(mdctx, md, NULL); + if (!ret) { + res = TEEC_ERROR_GENERIC; + goto out; + } + ret = EVP_DigestUpdate(mdctx, nsbe, sizeof(nsbe)); + if (!ret) { + res = TEEC_ERROR_GENERIC; + goto out; + } + ret = EVP_DigestUpdate(mdctx, name, size); + if (!ret) { + res = TEEC_ERROR_GENERIC; + goto out; + } + ret = EVP_DigestFinal_ex(mdctx, hash, &md_len); + if (!ret) { + res = TEEC_ERROR_GENERIC; + goto out; + } + + /* Mark it as UUIDv5 */ + hash[6] = (hash[6] & 0x0F) | 0x50; + hash[8] = (hash[8] & 0x3F) | 0x80; + + /* Convert from big endian to host */ + memcpy(&be32, &hash[0], sizeof(uint32_t)); + uuid->timeLow = be32toh(be32); + memcpy(&be16, &hash[4], sizeof(uint16_t)); + uuid->timeMid = be16toh(be16); + memcpy(&be16, &hash[6], sizeof(uint16_t)); + uuid->timeHiAndVersion = be16toh(be16); + memcpy(uuid->clockSeqAndNode, &hash[8], sizeof(uuid->clockSeqAndNode)); +out: + EVP_MD_CTX_destroy(mdctx); + return res; +} diff --git a/host/xtest/xtest_uuid_helpers.h b/host/xtest/xtest_uuid_helpers.h new file mode 100644 index 000000000..a307a9565 --- /dev/null +++ b/host/xtest/xtest_uuid_helpers.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2014, STMicroelectronics International N.V. + */ + +#ifndef XTEST_UUID_HELPERS_H +#define XTEST_UUID_HELPERS_H + +#include + +/* + * Convert a UUID string @s into a TEEC_UUID @uuid + * Expected format for @s is: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + * 'x' being any hexadecimal digit (0-9a-fA-F) + */ +TEEC_Result xtest_uuid_from_str(TEEC_UUID *uuid, const char *s); + +/* + * Form UUIDv5 from given name space and name. + */ +TEEC_Result xtest_uuid_v5(TEEC_UUID *uuid, const TEEC_UUID *ns, + const void *name, size_t size); +#endif diff --git a/ta/os_test/include/os_test.h b/ta/os_test/include/os_test.h index 6c3d4c4b3..88124f0b8 100644 --- a/ta/os_test/include/os_test.h +++ b/ta/os_test/include/os_test.h @@ -48,5 +48,6 @@ TEE_Result ta_entry_call_lib_panic(uint32_t param_types, TEE_Param params[4]); TEE_Result ta_entry_call_lib_dl(uint32_t param_types, TEE_Param params[4]); TEE_Result ta_entry_call_lib_dl_panic(uint32_t param_types, TEE_Param params[4]); TEE_Result ta_entry_get_global_var(uint32_t param_types, TEE_Param params[4]); +TEE_Result ta_entry_client_identity(uint32_t param_types, TEE_Param params[4]); #endif /*OS_TEST_H */ diff --git a/ta/os_test/include/ta_os_test.h b/ta/os_test/include/ta_os_test.h index 4a53dd8db..fc0b010ee 100644 --- a/ta/os_test/include/ta_os_test.h +++ b/ta/os_test/include/ta_os_test.h @@ -50,5 +50,6 @@ #define TA_OS_TEST_CMD_CALL_LIB_DL_PANIC 17 #define TA_OS_TEST_CMD_GET_GLOBAL_VAR 18 #define TA_OS_TEST_CMD_NULL_MEMREF_PARAMS 19 +#define TA_OS_TEST_CMD_CLIENT_IDENTITY 20 #endif /*TA_OS_TEST_H */ diff --git a/ta/os_test/os_test.c b/ta/os_test/os_test.c index ccf16e316..9d22684af 100644 --- a/ta/os_test/os_test.c +++ b/ta/os_test/os_test.c @@ -1214,3 +1214,34 @@ TEE_Result ta_entry_get_global_var(uint32_t param_types, TEE_Param params[4]) return TEE_SUCCESS; } + +TEE_Result ta_entry_client_identity(uint32_t param_types, TEE_Param params[4]) +{ + TEE_PropSetHandle *propset = NULL; + TEE_Result res = TEE_ERROR_GENERIC; + TEE_Identity identity = { }; + + if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE)) + return TEE_ERROR_BAD_PARAMETERS; + + if (params[1].memref.size < sizeof(TEE_UUID)) { + params[1].memref.size = sizeof(TEE_UUID); + return TEE_ERROR_SHORT_BUFFER; + } + + res = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, + "gpd.client.identity", &identity); + if (res != TEE_SUCCESS) { + EMSG("TEE_GetPropertyAsIdentity: returned %#"PRIx32, res); + return res; + } + + params[0].value.a = identity.login; + memcpy(params[1].memref.buffer, &identity.uuid, sizeof(TEE_UUID)); + params[1].memref.size = sizeof(TEE_UUID); + + return res; +} diff --git a/ta/os_test/ta_entry.c b/ta/os_test/ta_entry.c index 7abda1c89..516e6f241 100644 --- a/ta/os_test/ta_entry.c +++ b/ta/os_test/ta_entry.c @@ -127,6 +127,9 @@ TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext, case TA_OS_TEST_CMD_GET_GLOBAL_VAR: return ta_entry_get_global_var(nParamTypes, pParams); + case TA_OS_TEST_CMD_CLIENT_IDENTITY: + return ta_entry_client_identity(nParamTypes, pParams); + default: return TEE_ERROR_BAD_PARAMETERS; }