Raw access to trusted application secure storage
This change provides basics for creating, reading and deleting an
object in a TA secure storage.
The TA implementation shows how to use the GPD TEE Internal Core API
for some basic data persistent object manipulations.
A TA command allows to create an object in the TA secure storage.
A TA command allows to read an object in the TA secure storage.
A TA command allows to delete an object from the TA secure storage.
This example does not cover all the possibilities of secure storage API
provided to TAs: seeking into a object data stream, manipulating
key material objects instead of raw data objects, etc.
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
Acked-by: Jerome Forissier <jerome.forissier@linaro.org>
Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/secure_storage/host/main.c b/secure_storage/host/main.c
new file mode 100644
index 0000000..64b9fae
--- /dev/null
+++ b/secure_storage/host/main.c
@@ -0,0 +1,241 @@
+/*
+ * 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;
+}