1 /*
2 * Copyright (c) 2017, Linaro Limited
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <err.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 /* OP-TEE TEE client API (built by optee_client) */
33 #include <tee_client_api.h>
34
35 /* TA API: UUID and command IDs */
36 #include <secure_storage_ta.h>
37
38 /* TEE resources */
39 struct test_ctx {
40 TEEC_Context ctx;
41 TEEC_Session sess;
42 };
43
prepare_tee_session(struct test_ctx * ctx)44 void prepare_tee_session(struct test_ctx *ctx)
45 {
46 TEEC_UUID uuid = TA_SECURE_STORAGE_UUID;
47 uint32_t origin;
48 TEEC_Result res;
49
50 /* Initialize a context connecting us to the TEE */
51 res = TEEC_InitializeContext(NULL, &ctx->ctx);
52 if (res != TEEC_SUCCESS)
53 errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
54
55 /* Open a session with the TA */
56 res = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid,
57 TEEC_LOGIN_PUBLIC, NULL, NULL, &origin);
58 if (res != TEEC_SUCCESS)
59 errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
60 res, origin);
61 }
62
terminate_tee_session(struct test_ctx * ctx)63 void terminate_tee_session(struct test_ctx *ctx)
64 {
65 TEEC_CloseSession(&ctx->sess);
66 TEEC_FinalizeContext(&ctx->ctx);
67 }
68
read_secure_object(struct test_ctx * ctx,char * id,char * data,size_t data_len)69 TEEC_Result read_secure_object(struct test_ctx *ctx, char *id,
70 char *data, size_t data_len)
71 {
72 TEEC_Operation op;
73 uint32_t origin;
74 TEEC_Result res;
75 size_t id_len = strlen(id);
76
77 memset(&op, 0, sizeof(op));
78 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
79 TEEC_MEMREF_TEMP_OUTPUT,
80 TEEC_NONE, TEEC_NONE);
81
82 op.params[0].tmpref.buffer = id;
83 op.params[0].tmpref.size = id_len;
84
85 op.params[1].tmpref.buffer = data;
86 op.params[1].tmpref.size = data_len;
87
88 res = TEEC_InvokeCommand(&ctx->sess,
89 TA_SECURE_STORAGE_CMD_READ_RAW,
90 &op, &origin);
91 switch (res) {
92 case TEEC_SUCCESS:
93 case TEEC_ERROR_SHORT_BUFFER:
94 case TEEC_ERROR_ITEM_NOT_FOUND:
95 break;
96 default:
97 printf("Command READ_RAW failed: 0x%x / %u\n", res, origin);
98 }
99
100 return res;
101 }
102
write_secure_object(struct test_ctx * ctx,char * id,char * data,size_t data_len)103 TEEC_Result write_secure_object(struct test_ctx *ctx, char *id,
104 char *data, size_t data_len)
105 {
106 TEEC_Operation op;
107 uint32_t origin;
108 TEEC_Result res;
109 size_t id_len = strlen(id);
110
111 memset(&op, 0, sizeof(op));
112 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
113 TEEC_MEMREF_TEMP_INPUT,
114 TEEC_NONE, TEEC_NONE);
115
116 op.params[0].tmpref.buffer = id;
117 op.params[0].tmpref.size = id_len;
118
119 op.params[1].tmpref.buffer = data;
120 op.params[1].tmpref.size = data_len;
121
122 res = TEEC_InvokeCommand(&ctx->sess,
123 TA_SECURE_STORAGE_CMD_WRITE_RAW,
124 &op, &origin);
125 if (res != TEEC_SUCCESS)
126 printf("Command WRITE_RAW failed: 0x%x / %u\n", res, origin);
127
128 switch (res) {
129 case TEEC_SUCCESS:
130 break;
131 default:
132 printf("Command WRITE_RAW failed: 0x%x / %u\n", res, origin);
133 }
134
135 return res;
136 }
137
delete_secure_object(struct test_ctx * ctx,char * id)138 TEEC_Result delete_secure_object(struct test_ctx *ctx, char *id)
139 {
140 TEEC_Operation op;
141 uint32_t origin;
142 TEEC_Result res;
143 size_t id_len = strlen(id);
144
145 memset(&op, 0, sizeof(op));
146 op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
147 TEEC_NONE, TEEC_NONE, TEEC_NONE);
148
149 op.params[0].tmpref.buffer = id;
150 op.params[0].tmpref.size = id_len;
151
152 res = TEEC_InvokeCommand(&ctx->sess,
153 TA_SECURE_STORAGE_CMD_DELETE,
154 &op, &origin);
155
156 switch (res) {
157 case TEEC_SUCCESS:
158 case TEEC_ERROR_ITEM_NOT_FOUND:
159 break;
160 default:
161 printf("Command DELETE failed: 0x%x / %u\n", res, origin);
162 }
163
164 return res;
165 }
166
167 #define TEST_OBJECT_SIZE 7000
168
main(void)169 int main(void)
170 {
171 struct test_ctx ctx;
172 char obj1_id[] = "object#1"; /* string identification for the object */
173 char obj2_id[] = "object#2"; /* string identification for the object */
174 char obj1_data[TEST_OBJECT_SIZE];
175 char read_data[TEST_OBJECT_SIZE];
176 TEEC_Result res;
177
178 printf("Prepare session with the TA\n");
179 prepare_tee_session(&ctx);
180
181 /*
182 * Create object, read it, delete it.
183 */
184 printf("\nTest on object \"%s\"\n", obj1_id);
185
186 printf("- Create and load object in the TA secure storage\n");
187
188 memset(obj1_data, 0xA1, sizeof(obj1_data));
189
190 res = write_secure_object(&ctx, obj1_id,
191 obj1_data, sizeof(obj1_data));
192 if (res != TEEC_SUCCESS)
193 errx(1, "Failed to create an object in the secure storage");
194
195 printf("- Read back the object\n");
196
197 res = read_secure_object(&ctx, obj1_id,
198 read_data, sizeof(read_data));
199 if (res != TEEC_SUCCESS)
200 errx(1, "Failed to read an object from the secure storage");
201 if (memcmp(obj1_data, read_data, sizeof(obj1_data)))
202 errx(1, "Unexpected content found in secure storage");
203
204 printf("- Delete the object\n");
205
206 res = delete_secure_object(&ctx, obj1_id);
207 if (res != TEEC_SUCCESS)
208 errx(1, "Failed to delete the object: 0x%x", res);
209
210 /*
211 * Non volatile storage: create object2 if not found, delete it if found
212 */
213 printf("\nTest on object \"%s\"\n", obj2_id);
214
215 res = read_secure_object(&ctx, obj2_id,
216 read_data, sizeof(read_data));
217 if (res != TEEC_SUCCESS && res != TEEC_ERROR_ITEM_NOT_FOUND)
218 errx(1, "Unexpected status when reading an object : 0x%x", res);
219
220 if (res == TEEC_ERROR_ITEM_NOT_FOUND) {
221 char data[] = "This is data stored in the secure storage.\n";
222
223 printf("- Object not found in TA secure storage, create it.\n");
224
225 res = write_secure_object(&ctx, obj2_id,
226 data, sizeof(data));
227 if (res != TEEC_SUCCESS)
228 errx(1, "Failed to create/load an object");
229
230 } else if (res == TEEC_SUCCESS) {
231 printf("- Object found in TA secure storage, delete it.\n");
232
233 res = delete_secure_object(&ctx, obj2_id);
234 if (res != TEEC_SUCCESS)
235 errx(1, "Failed to delete an object");
236 }
237
238 printf("\nWe're done, close and release TEE resources\n");
239 terminate_tee_session(&ctx);
240 return 0;
241 }
242