| /* |
| * 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 <err.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| /* OP-TEE TEE client API (built by optee_client) */ |
| #include <tee_client_api.h> |
| |
| /* TA API: UUID and command IDs */ |
| #include <secure_storage_ta.h> |
| |
| /* 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(int argc, char *argv[]) |
| { |
| 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; |
| } |