xref: /optee_os/lib/libutee/tee_api_property.c (revision b01047730e77127c23a36591643eeb8bb0487d68)
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
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 #include <tee_api.h>
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <tee_api_defines.h>
33 #include <tee_api_types.h>
34 #include <user_ta_header.h>
35 #include <tee_internal_api_extensions.h>
36 
37 #include <utee_syscalls.h>
38 
39 #include "string_ext.h"
40 #include "base64.h"
41 
42 #define PROP_STR_MAX    80
43 
44 #define PROP_ENUMERATOR_NOT_STARTED 0xffffffff
45 
46 struct prop_enumerator {
47 	uint32_t idx;
48 	TEE_PropSetHandle prop_set;
49 };
50 
51 struct prop_value {
52 	enum user_ta_prop_type type;
53 	union {
54 		bool bool_val;
55 		uint32_t int_val;
56 		TEE_UUID uuid_val;
57 		TEE_Identity identity_val;
58 		char str_val[PROP_STR_MAX];
59 	} u;
60 };
61 
62 typedef TEE_Result(*ta_propget_func_t) (struct prop_value *pv);
63 
64 struct prop_set {
65 	const char *str;
66 	ta_propget_func_t get;
67 };
68 
69 static TEE_Result propget_gpd_ta_app_id(struct prop_value *pv)
70 {
71 	pv->type = USER_TA_PROP_TYPE_UUID;
72 	return utee_get_property(UTEE_PROP_TA_APP_ID, &pv->u.uuid_val,
73 				 sizeof(pv->u.uuid_val));
74 }
75 
76 static TEE_Result propget_gpd_client_identity(struct prop_value *pv)
77 {
78 	pv->type = USER_TA_PROP_TYPE_IDENTITY;
79 	return utee_get_property(UTEE_PROP_CLIENT_ID, &pv->u.identity_val,
80 				 sizeof(pv->u.identity_val));
81 }
82 
83 static TEE_Result propget_gpd_tee_api_version(struct prop_value *pv)
84 {
85 	pv->type = USER_TA_PROP_TYPE_STRING;
86 	return utee_get_property(UTEE_PROP_TEE_API_VERSION, &pv->u.str_val,
87 				 sizeof(pv->u.str_val));
88 }
89 
90 static TEE_Result propget_gpd_tee_description(struct prop_value *pv)
91 {
92 	pv->type = USER_TA_PROP_TYPE_STRING;
93 	return utee_get_property(UTEE_PROP_TEE_DESCR, &pv->u.str_val,
94 				 sizeof(pv->u.str_val));
95 }
96 
97 static TEE_Result propget_gpd_tee_device_id(struct prop_value *pv)
98 {
99 	pv->type = USER_TA_PROP_TYPE_UUID;
100 	return utee_get_property(UTEE_PROP_TEE_DEV_ID, &pv->u.uuid_val,
101 				 sizeof(pv->u.uuid_val));
102 }
103 
104 static TEE_Result propget_gpd_tee_sys_time_protection_level(struct prop_value
105 							    *pv)
106 {
107 	pv->type = USER_TA_PROP_TYPE_U32;
108 	return utee_get_property(UTEE_PROP_TEE_SYS_TIME_PROT_LEVEL,
109 				 &pv->u.int_val, sizeof(pv->u.int_val));
110 }
111 
112 static TEE_Result propget_gpd_tee_ta_time_protection_level(struct prop_value
113 							   *pv)
114 {
115 	pv->type = USER_TA_PROP_TYPE_U32;
116 	return utee_get_property(UTEE_PROP_TEE_TA_TIME_PROT_LEVEL,
117 				 &pv->u.int_val, sizeof(pv->u.int_val));
118 }
119 
120 static TEE_Result propget_gpd_tee_arith_max_big_int_size(struct prop_value *pv)
121 {
122 	pv->type = USER_TA_PROP_TYPE_U32;
123 	return utee_get_property(UTEE_PROP_TEE_ARITH_MAX_BIG_INT_SIZE,
124 				 &pv->u.int_val, sizeof(pv->u.int_val));
125 }
126 
127 static const struct prop_set propset_current_ta[] = {
128 	{"gpd.ta.appID", propget_gpd_ta_app_id},
129 };
130 
131 static const size_t propset_current_ta_len =
132 	sizeof(propset_current_ta) / sizeof(propset_current_ta[0]);
133 
134 static const struct prop_set propset_current_client[] = {
135 	{"gpd.client.identity", propget_gpd_client_identity},
136 };
137 
138 static const size_t propset_current_client_len =
139 	sizeof(propset_current_client) / sizeof(propset_current_client[0]);
140 
141 static const struct prop_set propset_implementation[] = {
142 	{"gpd.tee.apiversion", propget_gpd_tee_api_version},
143 	{"gpd.tee.description", propget_gpd_tee_description},
144 	{"gpd.tee.deviceID", propget_gpd_tee_device_id},
145 	{"gpd.tee.systemTime.protectionLevel",
146 	 propget_gpd_tee_sys_time_protection_level},
147 	{"gpd.tee.TAPersistentTime.protectionLevel",
148 	 propget_gpd_tee_ta_time_protection_level},
149 	{"gpd.tee.arith.maxBigIntSize", propget_gpd_tee_arith_max_big_int_size},
150 };
151 
152 static const size_t propset_implementation_len =
153 	sizeof(propset_implementation) / sizeof(propset_implementation[0]);
154 
155 static TEE_Result propset_get(TEE_PropSetHandle h, const struct prop_set **ps,
156 			      size_t *ps_len,
157 			      const struct user_ta_property **eps,
158 			      size_t *eps_len)
159 {
160 	if (h == TEE_PROPSET_CURRENT_TA) {
161 		*ps = propset_current_ta;
162 		*ps_len = propset_current_ta_len;
163 		*eps = ta_props;
164 		*eps_len = ta_num_props;
165 	} else if (h == TEE_PROPSET_CURRENT_CLIENT) {
166 		*ps = propset_current_client;
167 		*ps_len = propset_current_client_len;
168 		*eps = NULL;
169 		*eps_len = 0;
170 	} else if (h == TEE_PROPSET_TEE_IMPLEMENTATION) {
171 		*ps = propset_implementation;
172 		*ps_len = propset_implementation_len;
173 		*eps = NULL;
174 		*eps_len = 0;
175 	} else {
176 		return TEE_ERROR_ITEM_NOT_FOUND;
177 	}
178 
179 	return TEE_SUCCESS;
180 }
181 
182 static TEE_Result propget_get_ext_prop(const struct user_ta_property *ep,
183 				       struct prop_value *pv)
184 {
185 	size_t l;
186 
187 	pv->type = ep->type;
188 	switch (ep->type) {
189 	case USER_TA_PROP_TYPE_BOOL:
190 		l = sizeof(bool);
191 		break;
192 	case USER_TA_PROP_TYPE_U32:
193 		l = sizeof(uint32_t);
194 		break;
195 	case USER_TA_PROP_TYPE_UUID:
196 		l = sizeof(TEE_UUID);
197 		break;
198 	case USER_TA_PROP_TYPE_IDENTITY:
199 		l = sizeof(TEE_Identity);
200 		break;
201 	case USER_TA_PROP_TYPE_STRING:
202 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
203 		/* Handle too large strings by truncating them */
204 		strlcpy(pv->u.str_val, ep->value, sizeof(pv->u.str_val));
205 		return TEE_SUCCESS;
206 	default:
207 		return TEE_ERROR_GENERIC;
208 	}
209 	memcpy(&pv->u, ep->value, l);
210 	return TEE_SUCCESS;
211 }
212 
213 static TEE_Result propget_get_property(TEE_PropSetHandle h, char *name,
214 				       struct prop_value *pv)
215 {
216 	TEE_Result res;
217 	const struct prop_set *ps;
218 	size_t ps_len;
219 	const struct user_ta_property *eps;
220 	size_t eps_len;
221 
222 	if (h == TEE_PROPSET_CURRENT_TA || h == TEE_PROPSET_CURRENT_CLIENT ||
223 	    h == TEE_PROPSET_TEE_IMPLEMENTATION) {
224 		size_t n;
225 
226 		res = propset_get(h, &ps, &ps_len, &eps, &eps_len);
227 		if (res != TEE_SUCCESS)
228 			return res;
229 
230 		for (n = 0; n < ps_len; n++) {
231 			if (strcmp(name, ps[n].str) == 0)
232 				return ps[n].get(pv);
233 		}
234 		for (n = 0; n < eps_len; n++) {
235 			if (strcmp(name, eps[n].name) == 0)
236 				return propget_get_ext_prop(eps + n, pv);
237 		}
238 		return TEE_ERROR_ITEM_NOT_FOUND;
239 	} else {
240 		struct prop_enumerator *pe = (struct prop_enumerator *)h;
241 		uint32_t idx = pe->idx;
242 
243 		if (idx == PROP_ENUMERATOR_NOT_STARTED)
244 			return TEE_ERROR_ITEM_NOT_FOUND;
245 
246 		res = propset_get(pe->prop_set, &ps, &ps_len, &eps, &eps_len);
247 		if (res != TEE_SUCCESS)
248 			return res;
249 
250 		if (idx < ps_len)
251 			return ps[idx].get(pv);
252 
253 		idx -= ps_len;
254 		if (idx < eps_len)
255 			return propget_get_ext_prop(eps + idx, pv);
256 
257 		return TEE_ERROR_BAD_PARAMETERS;
258 	}
259 }
260 
261 TEE_Result TEE_GetPropertyAsString(TEE_PropSetHandle propsetOrEnumerator,
262 				   char *name, char *valueBuffer,
263 				   size_t *valueBufferLen)
264 {
265 	TEE_Result res;
266 	struct prop_value pv;
267 	size_t l;
268 	size_t bufferlen;
269 
270 	if (valueBuffer == NULL || valueBufferLen == NULL)
271 		return TEE_ERROR_BAD_PARAMETERS;
272 
273 	bufferlen = *valueBufferLen;
274 
275 	res = propget_get_property(propsetOrEnumerator, name, &pv);
276 	if (res != TEE_SUCCESS)
277 		return res;
278 
279 	switch (pv.type) {
280 	case USER_TA_PROP_TYPE_BOOL:
281 		l = strlcpy(valueBuffer, pv.u.bool_val ? "true" : "false",
282 			    bufferlen);
283 		break;
284 
285 	case USER_TA_PROP_TYPE_U32:
286 		l = snprintf(valueBuffer, bufferlen, "%u",
287 			     (unsigned int)pv.u.int_val);
288 		break;
289 
290 	case USER_TA_PROP_TYPE_UUID:
291 		l = snprintf(valueBuffer, bufferlen,
292 			     "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
293 			     (unsigned int)pv.u.uuid_val.timeLow,
294 			     pv.u.uuid_val.timeMid,
295 			     pv.u.uuid_val.timeHiAndVersion,
296 			     pv.u.uuid_val.clockSeqAndNode[0],
297 			     pv.u.uuid_val.clockSeqAndNode[1],
298 			     pv.u.uuid_val.clockSeqAndNode[2],
299 			     pv.u.uuid_val.clockSeqAndNode[3],
300 			     pv.u.uuid_val.clockSeqAndNode[4],
301 			     pv.u.uuid_val.clockSeqAndNode[5],
302 			     pv.u.uuid_val.clockSeqAndNode[6],
303 			     pv.u.uuid_val.clockSeqAndNode[7]);
304 		break;
305 
306 	case USER_TA_PROP_TYPE_IDENTITY:
307 		l = snprintf(valueBuffer, bufferlen,
308 			     "%u:%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
309 			     (unsigned int)pv.u.identity_val.login,
310 			     (unsigned int)pv.u.identity_val.uuid.timeLow,
311 			     pv.u.identity_val.uuid.timeMid,
312 			     pv.u.identity_val.uuid.timeHiAndVersion,
313 			     pv.u.identity_val.uuid.clockSeqAndNode[0],
314 			     pv.u.identity_val.uuid.clockSeqAndNode[1],
315 			     pv.u.identity_val.uuid.clockSeqAndNode[2],
316 			     pv.u.identity_val.uuid.clockSeqAndNode[3],
317 			     pv.u.identity_val.uuid.clockSeqAndNode[4],
318 			     pv.u.identity_val.uuid.clockSeqAndNode[5],
319 			     pv.u.identity_val.uuid.clockSeqAndNode[6],
320 			     pv.u.identity_val.uuid.clockSeqAndNode[7]);
321 		break;
322 
323 	case USER_TA_PROP_TYPE_STRING:
324 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
325 		l = strlcpy(valueBuffer, pv.u.str_val, bufferlen);
326 		break;
327 
328 	default:
329 		return TEE_ERROR_BAD_FORMAT;
330 	}
331 
332 	/* The size "must account for the zero terminator" */
333 	*valueBufferLen = l + 1;
334 
335 	if (l >= bufferlen)
336 		return TEE_ERROR_SHORT_BUFFER;
337 
338 	return TEE_SUCCESS;
339 }
340 
341 TEE_Result TEE_GetPropertyAsBool(TEE_PropSetHandle propsetOrEnumerator,
342 				 char *name, bool *value)
343 {
344 	TEE_Result res;
345 	struct prop_value pv;
346 
347 	if (value == NULL)
348 		return TEE_ERROR_BAD_PARAMETERS;
349 
350 	res = propget_get_property(propsetOrEnumerator, name, &pv);
351 	if (res != TEE_SUCCESS)
352 		return res;
353 
354 	if (pv.type != USER_TA_PROP_TYPE_BOOL)
355 		return TEE_ERROR_BAD_FORMAT;
356 
357 	*value = pv.u.bool_val;
358 	return TEE_SUCCESS;
359 }
360 
361 TEE_Result TEE_GetPropertyAsU32(TEE_PropSetHandle propsetOrEnumerator,
362 				char *name, uint32_t *value)
363 {
364 	TEE_Result res;
365 	struct prop_value pv;
366 
367 	if (value == NULL)
368 		return TEE_ERROR_BAD_PARAMETERS;
369 
370 	res = propget_get_property(propsetOrEnumerator, name, &pv);
371 	if (res != TEE_SUCCESS)
372 		return res;
373 
374 	if (pv.type != USER_TA_PROP_TYPE_U32)
375 		return TEE_ERROR_BAD_FORMAT;
376 
377 	*value = pv.u.int_val;
378 	return TEE_SUCCESS;
379 }
380 
381 TEE_Result TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator,
382 					char *name, void *valueBuffer,
383 					size_t *valueBufferLen)
384 {
385 	TEE_Result res;
386 	struct prop_value pv;
387 	void *val;
388 	int val_len;
389 
390 	if (valueBuffer == NULL || valueBufferLen == NULL)
391 		return TEE_ERROR_BAD_PARAMETERS;
392 
393 	res = propget_get_property(propsetOrEnumerator, name, &pv);
394 	if (res != TEE_SUCCESS)
395 		return res;
396 
397 	if (pv.type != USER_TA_PROP_TYPE_BINARY_BLOCK)
398 		return TEE_ERROR_BAD_FORMAT;
399 
400 	val = pv.u.str_val;
401 	val_len = strlen(val);
402 	if (!base64_dec(val, val_len, valueBuffer, valueBufferLen))
403 		return TEE_ERROR_SHORT_BUFFER;
404 	return TEE_SUCCESS;
405 }
406 
407 TEE_Result TEE_GetPropertyAsUUID(TEE_PropSetHandle propsetOrEnumerator,
408 				 char *name, TEE_UUID *value)
409 {
410 	TEE_Result res;
411 	struct prop_value pv;
412 
413 	if (value == NULL)
414 		return TEE_ERROR_BAD_PARAMETERS;
415 
416 	res = propget_get_property(propsetOrEnumerator, name, &pv);
417 	if (res != TEE_SUCCESS)
418 		return res;
419 
420 	if (pv.type != USER_TA_PROP_TYPE_UUID)
421 		return TEE_ERROR_BAD_FORMAT;
422 
423 	*value = pv.u.uuid_val;	/* struct copy */
424 	return TEE_SUCCESS;
425 }
426 
427 TEE_Result TEE_GetPropertyAsIdentity(TEE_PropSetHandle propsetOrEnumerator,
428 				     char *name, TEE_Identity *value)
429 {
430 	TEE_Result res;
431 	struct prop_value pv;
432 
433 	if (value == NULL)
434 		return TEE_ERROR_BAD_PARAMETERS;
435 
436 	res = propget_get_property(propsetOrEnumerator, name, &pv);
437 	if (res != TEE_SUCCESS)
438 		return res;
439 
440 	if (pv.type != USER_TA_PROP_TYPE_IDENTITY)
441 		return TEE_ERROR_BAD_FORMAT;
442 
443 	*value = pv.u.identity_val;	/* struct copy */
444 	return TEE_SUCCESS;
445 }
446 
447 TEE_Result TEE_AllocatePropertyEnumerator(TEE_PropSetHandle *enumerator)
448 {
449 	struct prop_enumerator *pe;
450 
451 	if (enumerator == NULL)
452 		return TEE_ERROR_BAD_PARAMETERS;
453 
454 	pe = TEE_Malloc(sizeof(struct prop_enumerator),
455 			TEE_USER_MEM_HINT_NO_FILL_ZERO);
456 	if (pe == NULL)
457 		return TEE_ERROR_OUT_OF_MEMORY;
458 
459 	*enumerator = (TEE_PropSetHandle) pe;
460 	TEE_ResetPropertyEnumerator(*enumerator);
461 	return TEE_SUCCESS;
462 }
463 
464 void TEE_ResetPropertyEnumerator(TEE_PropSetHandle enumerator)
465 {
466 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
467 
468 	pe->idx = PROP_ENUMERATOR_NOT_STARTED;
469 }
470 
471 void TEE_FreePropertyEnumerator(TEE_PropSetHandle enumerator)
472 {
473 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
474 
475 	TEE_Free(pe);
476 }
477 
478 void TEE_StartPropertyEnumerator(TEE_PropSetHandle enumerator,
479 				 TEE_PropSetHandle propSet)
480 {
481 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
482 
483 	if (pe == NULL)
484 		return;
485 
486 	pe->idx = 0;
487 	pe->prop_set = propSet;
488 }
489 
490 TEE_Result TEE_GetPropertyName(TEE_PropSetHandle enumerator,
491 			       void *nameBuffer, size_t *nameBufferLen)
492 {
493 	TEE_Result res;
494 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
495 	const struct prop_set *ps;
496 	size_t ps_len;
497 	const struct user_ta_property *eps;
498 	size_t eps_len;
499 	size_t l;
500 	const char *str;
501 	size_t bufferlen;
502 
503 	if (pe == NULL || nameBuffer == NULL || nameBufferLen == NULL)
504 		return TEE_ERROR_BAD_PARAMETERS;
505 
506 	bufferlen = *nameBufferLen;
507 	res = propset_get(pe->prop_set, &ps, &ps_len, &eps, &eps_len);
508 	if (res != TEE_SUCCESS)
509 		return res;
510 
511 	if (pe->idx < ps_len)
512 		str = ps[pe->idx].str;
513 	else if ((pe->idx - ps_len) < eps_len)
514 		str = ta_props[pe->idx - ps_len].name;
515 	else
516 		return TEE_ERROR_ITEM_NOT_FOUND;
517 
518 	l = strlcpy(nameBuffer, str, bufferlen);
519 
520 	/* The size "must account for the zero terminator" */
521 	*nameBufferLen = l + 1;
522 
523 	if (l >= bufferlen)
524 		return TEE_ERROR_SHORT_BUFFER;
525 
526 	return TEE_SUCCESS;
527 }
528 
529 TEE_Result TEE_GetNextProperty(TEE_PropSetHandle enumerator)
530 {
531 	TEE_Result res;
532 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
533 	uint32_t next_idx;
534 	const struct prop_set *ps;
535 	size_t ps_len;
536 	const struct user_ta_property *eps;
537 	size_t eps_len;
538 
539 	if (pe == NULL)
540 		return TEE_ERROR_BAD_PARAMETERS;
541 
542 	if (pe->idx == PROP_ENUMERATOR_NOT_STARTED)
543 		return TEE_ERROR_ITEM_NOT_FOUND;
544 
545 	res = propset_get(pe->prop_set, &ps, &ps_len, &eps, &eps_len);
546 	if (res != TEE_SUCCESS)
547 		return res;
548 
549 	next_idx = pe->idx + 1;
550 	pe->idx = next_idx;
551 	if (next_idx >= (ps_len + eps_len))
552 		return TEE_ERROR_ITEM_NOT_FOUND;
553 
554 	return TEE_SUCCESS;
555 }
556