/* * Copyright (c) 2017, Linaro Limited * 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 /* OP-TEE TEE client API (built by optee_client) */ #include /* TA API: UUID and command IDs */ #include /* TEE resources */ struct test_ctx { TEEC_Context ctx; TEEC_Session sess; }; void prepare_tee_session(struct test_ctx *ctx) { TEEC_UUID uuid = TA_SECURE_STORAGE_UUID; uint32_t origin; TEEC_Result res; /* Initialize a context connecting us to the TEE */ res = TEEC_InitializeContext(NULL, &ctx->ctx); if (res != TEEC_SUCCESS) errx(1, "TEEC_InitializeContext failed with code 0x%x", res); /* Open a session with the TA */ res = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid, TEEC_LOGIN_PUBLIC, NULL, NULL, &origin); if (res != TEEC_SUCCESS) errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x", res, origin); } void terminate_tee_session(struct test_ctx *ctx) { TEEC_CloseSession(&ctx->sess); TEEC_FinalizeContext(&ctx->ctx); } TEEC_Result read_secure_object(struct test_ctx *ctx, char *id, char *data, size_t data_len) { TEEC_Operation op; uint32_t origin; TEEC_Result res; size_t id_len = strlen(id); memset(&op, 0, sizeof(op)); op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE); op.params[0].tmpref.buffer = id; op.params[0].tmpref.size = id_len; op.params[1].tmpref.buffer = data; op.params[1].tmpref.size = data_len; res = TEEC_InvokeCommand(&ctx->sess, TA_SECURE_STORAGE_CMD_READ_RAW, &op, &origin); switch (res) { case TEEC_SUCCESS: case TEEC_ERROR_SHORT_BUFFER: case TEEC_ERROR_ITEM_NOT_FOUND: break; default: printf("Command READ_RAW failed: 0x%x / %u\n", res, origin); } return res; } TEEC_Result write_secure_object(struct test_ctx *ctx, char *id, char *data, size_t data_len) { TEEC_Operation op; uint32_t origin; TEEC_Result res; size_t id_len = strlen(id); memset(&op, 0, sizeof(op)); op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); op.params[0].tmpref.buffer = id; op.params[0].tmpref.size = id_len; op.params[1].tmpref.buffer = data; op.params[1].tmpref.size = data_len; res = TEEC_InvokeCommand(&ctx->sess, TA_SECURE_STORAGE_CMD_WRITE_RAW, &op, &origin); if (res != TEEC_SUCCESS) printf("Command WRITE_RAW failed: 0x%x / %u\n", res, origin); switch (res) { case TEEC_SUCCESS: break; default: printf("Command WRITE_RAW failed: 0x%x / %u\n", res, origin); } return res; } TEEC_Result delete_secure_object(struct test_ctx *ctx, char *id) { TEEC_Operation op; uint32_t origin; TEEC_Result res; size_t id_len = strlen(id); memset(&op, 0, sizeof(op)); op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); op.params[0].tmpref.buffer = id; op.params[0].tmpref.size = id_len; res = TEEC_InvokeCommand(&ctx->sess, TA_SECURE_STORAGE_CMD_DELETE, &op, &origin); switch (res) { case TEEC_SUCCESS: case TEEC_ERROR_ITEM_NOT_FOUND: break; default: printf("Command DELETE failed: 0x%x / %u\n", res, origin); } return res; } #define TEST_OBJECT_SIZE 7000 int main(void) { struct test_ctx ctx; char obj1_id[] = "object#1"; /* string identification for the object */ char obj2_id[] = "object#2"; /* string identification for the object */ char obj1_data[TEST_OBJECT_SIZE]; char read_data[TEST_OBJECT_SIZE]; TEEC_Result res; printf("Prepare session with the TA\n"); prepare_tee_session(&ctx); /* * Create object, read it, delete it. */ printf("\nTest on object \"%s\"\n", obj1_id); printf("- Create and load object in the TA secure storage\n"); memset(obj1_data, 0xA1, sizeof(obj1_data)); res = write_secure_object(&ctx, obj1_id, obj1_data, sizeof(obj1_data)); if (res != TEEC_SUCCESS) errx(1, "Failed to create an object in the secure storage"); printf("- Read back the object\n"); res = read_secure_object(&ctx, obj1_id, read_data, sizeof(read_data)); if (res != TEEC_SUCCESS) errx(1, "Failed to read an object from the secure storage"); if (memcmp(obj1_data, read_data, sizeof(obj1_data))) errx(1, "Unexpected content found in secure storage"); printf("- Delete the object\n"); res = delete_secure_object(&ctx, obj1_id); if (res != TEEC_SUCCESS) errx(1, "Failed to delete the object: 0x%x", res); /* * Non volatile storage: create object2 if not found, delete it if found */ printf("\nTest on object \"%s\"\n", obj2_id); res = read_secure_object(&ctx, obj2_id, read_data, sizeof(read_data)); if (res != TEEC_SUCCESS && res != TEEC_ERROR_ITEM_NOT_FOUND) errx(1, "Unexpected status when reading an object : 0x%x", res); if (res == TEEC_ERROR_ITEM_NOT_FOUND) { char data[] = "This is data stored in the secure storage.\n"; printf("- Object not found in TA secure storage, create it.\n"); res = write_secure_object(&ctx, obj2_id, data, sizeof(data)); if (res != TEEC_SUCCESS) errx(1, "Failed to create/load an object"); } else if (res == TEEC_SUCCESS) { printf("- Object found in TA secure storage, delete it.\n"); res = delete_secure_object(&ctx, obj2_id); if (res != TEEC_SUCCESS) errx(1, "Failed to delete an object"); } printf("\nWe're done, close and release TEE resources\n"); terminate_tee_session(&ctx); return 0; }