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