xref: /optee_os/lib/libutee/tee_api_property.c (revision ba675d69487f1725d21cafc4f0d646ce1deb44bb)
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 				   uint32_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 		res = TEE_ERROR_BAD_PARAMETERS;
273 		goto err;
274 	}
275 
276 	bufferlen = *valueBufferLen;
277 
278 	res = propget_get_property(propsetOrEnumerator, name, &pv);
279 	if (res != TEE_SUCCESS)
280 		goto err;
281 
282 	switch (pv.type) {
283 	case USER_TA_PROP_TYPE_BOOL:
284 		l = strlcpy(valueBuffer, pv.u.bool_val ? "true" : "false",
285 			    bufferlen);
286 		break;
287 
288 	case USER_TA_PROP_TYPE_U32:
289 		l = snprintf(valueBuffer, bufferlen, "%u",
290 			     (unsigned int)pv.u.int_val);
291 		break;
292 
293 	case USER_TA_PROP_TYPE_UUID:
294 		l = snprintf(valueBuffer, bufferlen,
295 			     "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
296 			     (unsigned int)pv.u.uuid_val.timeLow,
297 			     pv.u.uuid_val.timeMid,
298 			     pv.u.uuid_val.timeHiAndVersion,
299 			     pv.u.uuid_val.clockSeqAndNode[0],
300 			     pv.u.uuid_val.clockSeqAndNode[1],
301 			     pv.u.uuid_val.clockSeqAndNode[2],
302 			     pv.u.uuid_val.clockSeqAndNode[3],
303 			     pv.u.uuid_val.clockSeqAndNode[4],
304 			     pv.u.uuid_val.clockSeqAndNode[5],
305 			     pv.u.uuid_val.clockSeqAndNode[6],
306 			     pv.u.uuid_val.clockSeqAndNode[7]);
307 		break;
308 
309 	case USER_TA_PROP_TYPE_IDENTITY:
310 		l = snprintf(valueBuffer, bufferlen,
311 			     "%u:%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
312 			     (unsigned int)pv.u.identity_val.login,
313 			     (unsigned int)pv.u.identity_val.uuid.timeLow,
314 			     pv.u.identity_val.uuid.timeMid,
315 			     pv.u.identity_val.uuid.timeHiAndVersion,
316 			     pv.u.identity_val.uuid.clockSeqAndNode[0],
317 			     pv.u.identity_val.uuid.clockSeqAndNode[1],
318 			     pv.u.identity_val.uuid.clockSeqAndNode[2],
319 			     pv.u.identity_val.uuid.clockSeqAndNode[3],
320 			     pv.u.identity_val.uuid.clockSeqAndNode[4],
321 			     pv.u.identity_val.uuid.clockSeqAndNode[5],
322 			     pv.u.identity_val.uuid.clockSeqAndNode[6],
323 			     pv.u.identity_val.uuid.clockSeqAndNode[7]);
324 		break;
325 
326 	case USER_TA_PROP_TYPE_STRING:
327 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
328 		l = strlcpy(valueBuffer, pv.u.str_val, bufferlen);
329 		break;
330 
331 	default:
332 		res = TEE_ERROR_BAD_FORMAT;
333 		goto err;
334 	}
335 
336 	/* The size "must account for the zero terminator" */
337 	*valueBufferLen = l + 1;
338 
339 	if (l >= bufferlen) {
340 		res = TEE_ERROR_SHORT_BUFFER;
341 		goto err;
342 	}
343 
344 	goto out;
345 
346 err:
347 	if (res == TEE_ERROR_ITEM_NOT_FOUND ||
348 	    res == TEE_ERROR_SHORT_BUFFER)
349 		return res;
350 	TEE_Panic(0);
351 out:
352 	return TEE_SUCCESS;
353 }
354 
355 TEE_Result TEE_GetPropertyAsBool(TEE_PropSetHandle propsetOrEnumerator,
356 				 char *name, bool *value)
357 {
358 	TEE_Result res;
359 	struct prop_value pv;
360 
361 	if (value == NULL) {
362 		res = TEE_ERROR_BAD_PARAMETERS;
363 		goto err;
364 	}
365 
366 	res = propget_get_property(propsetOrEnumerator, name, &pv);
367 	if (res != TEE_SUCCESS)
368 		goto err;
369 
370 	if (pv.type != USER_TA_PROP_TYPE_BOOL) {
371 		res = TEE_ERROR_BAD_FORMAT;
372 		goto err;
373 	}
374 
375 	*value = pv.u.bool_val;
376 
377 	goto out;
378 
379 err:
380 	if (res == TEE_ERROR_ITEM_NOT_FOUND ||
381 	    res == TEE_ERROR_BAD_FORMAT)
382 		return res;
383 	TEE_Panic(0);
384 out:
385 	return TEE_SUCCESS;
386 }
387 
388 TEE_Result TEE_GetPropertyAsU32(TEE_PropSetHandle propsetOrEnumerator,
389 				char *name, uint32_t *value)
390 {
391 	TEE_Result res;
392 	struct prop_value pv;
393 
394 	if (value == NULL) {
395 		res = TEE_ERROR_BAD_PARAMETERS;
396 		goto err;
397 	}
398 
399 	res = propget_get_property(propsetOrEnumerator, name, &pv);
400 	if (res != TEE_SUCCESS)
401 		goto err;
402 
403 	if (pv.type != USER_TA_PROP_TYPE_U32) {
404 		res = TEE_ERROR_BAD_FORMAT;
405 		goto err;
406 	}
407 
408 	*value = pv.u.int_val;
409 
410 	goto out;
411 
412 err:
413 	if (res == TEE_ERROR_ITEM_NOT_FOUND ||
414 	    res == TEE_ERROR_BAD_FORMAT)
415 		return res;
416 	TEE_Panic(0);
417 out:
418 	return TEE_SUCCESS;
419 }
420 
421 TEE_Result TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator,
422 					char *name, void *valueBuffer,
423 					uint32_t *valueBufferLen)
424 {
425 	TEE_Result res;
426 	struct prop_value pv;
427 	void *val;
428 	int val_len;
429 	size_t size;
430 
431 	if (valueBuffer == NULL || valueBufferLen == NULL) {
432 		res = TEE_ERROR_BAD_PARAMETERS;
433 		goto err;
434 	}
435 
436 	res = propget_get_property(propsetOrEnumerator, name, &pv);
437 	if (res != TEE_SUCCESS)
438 		goto err;
439 
440 	if (pv.type != USER_TA_PROP_TYPE_BINARY_BLOCK) {
441 		res = TEE_ERROR_BAD_FORMAT;
442 		goto err;
443 	}
444 
445 	val = pv.u.str_val;
446 	val_len = strlen(val);
447 	size = *valueBufferLen;
448 	if (!base64_dec(val, val_len, valueBuffer, &size)) {
449 		res = TEE_ERROR_SHORT_BUFFER;
450 		goto err;
451 	}
452 
453 	*valueBufferLen = size;
454 
455 	goto out;
456 
457 err:
458 	if (res == TEE_ERROR_ITEM_NOT_FOUND ||
459 	    res == TEE_ERROR_BAD_FORMAT ||
460 	    res == TEE_ERROR_SHORT_BUFFER)
461 		return res;
462 	TEE_Panic(0);
463 out:
464 	return TEE_SUCCESS;
465 }
466 
467 TEE_Result TEE_GetPropertyAsUUID(TEE_PropSetHandle propsetOrEnumerator,
468 				 char *name, TEE_UUID *value)
469 {
470 	TEE_Result res;
471 	struct prop_value pv;
472 
473 	if (value == NULL) {
474 		res = TEE_ERROR_BAD_PARAMETERS;
475 		goto err;
476 	}
477 
478 	res = propget_get_property(propsetOrEnumerator, name, &pv);
479 	if (res != TEE_SUCCESS)
480 		goto err;
481 
482 	if (pv.type != USER_TA_PROP_TYPE_UUID) {
483 		res = TEE_ERROR_BAD_FORMAT;
484 		goto err;
485 	}
486 
487 	*value = pv.u.uuid_val;	/* struct copy */
488 
489 	goto out;
490 
491 err:
492 	if (res == TEE_ERROR_ITEM_NOT_FOUND ||
493 	    res == TEE_ERROR_BAD_FORMAT)
494 		return res;
495 	TEE_Panic(0);
496 out:
497 	return TEE_SUCCESS;
498 }
499 
500 TEE_Result TEE_GetPropertyAsIdentity(TEE_PropSetHandle propsetOrEnumerator,
501 				     char *name, TEE_Identity *value)
502 {
503 	TEE_Result res;
504 	struct prop_value pv;
505 
506 	if (value == NULL) {
507 		res = TEE_ERROR_BAD_PARAMETERS;
508 		goto err;
509 	}
510 
511 	res = propget_get_property(propsetOrEnumerator, name, &pv);
512 	if (res != TEE_SUCCESS)
513 		goto err;
514 
515 	if (pv.type != USER_TA_PROP_TYPE_IDENTITY) {
516 		res = TEE_ERROR_BAD_FORMAT;
517 		goto err;
518 	}
519 
520 	*value = pv.u.identity_val;	/* struct copy */
521 
522 	goto out;
523 
524 err:
525 	if (res == TEE_ERROR_ITEM_NOT_FOUND ||
526 	    res == TEE_ERROR_BAD_FORMAT)
527 		return res;
528 	TEE_Panic(0);
529 out:
530 	return TEE_SUCCESS;
531 }
532 
533 TEE_Result TEE_AllocatePropertyEnumerator(TEE_PropSetHandle *enumerator)
534 {
535 	TEE_Result res;
536 	struct prop_enumerator *pe;
537 
538 	if (enumerator == NULL) {
539 		res = TEE_ERROR_BAD_PARAMETERS;
540 		goto err;
541 	}
542 
543 	pe = TEE_Malloc(sizeof(struct prop_enumerator),
544 			TEE_USER_MEM_HINT_NO_FILL_ZERO);
545 	if (pe == NULL) {
546 		res = TEE_ERROR_OUT_OF_MEMORY;
547 		goto err;
548 	}
549 
550 	*enumerator = (TEE_PropSetHandle) pe;
551 	TEE_ResetPropertyEnumerator(*enumerator);
552 
553 	goto out;
554 
555 err:
556 	if (res == TEE_ERROR_OUT_OF_MEMORY)
557 		return res;
558 	TEE_Panic(0);
559 out:
560 	return TEE_SUCCESS;
561 }
562 
563 void TEE_ResetPropertyEnumerator(TEE_PropSetHandle enumerator)
564 {
565 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
566 
567 	pe->idx = PROP_ENUMERATOR_NOT_STARTED;
568 }
569 
570 void TEE_FreePropertyEnumerator(TEE_PropSetHandle enumerator)
571 {
572 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
573 
574 	TEE_Free(pe);
575 }
576 
577 void TEE_StartPropertyEnumerator(TEE_PropSetHandle enumerator,
578 				 TEE_PropSetHandle propSet)
579 {
580 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
581 
582 	if (pe == NULL)
583 		return;
584 
585 	pe->idx = 0;
586 	pe->prop_set = propSet;
587 }
588 
589 TEE_Result TEE_GetPropertyName(TEE_PropSetHandle enumerator,
590 			       void *nameBuffer, uint32_t *nameBufferLen)
591 {
592 	TEE_Result res;
593 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
594 	const struct prop_set *ps;
595 	size_t ps_len;
596 	const struct user_ta_property *eps;
597 	size_t eps_len;
598 	size_t l;
599 	const char *str;
600 	size_t bufferlen;
601 
602 	if (pe == NULL || nameBuffer == NULL || nameBufferLen == NULL) {
603 		res = TEE_ERROR_BAD_PARAMETERS;
604 		goto err;
605 	}
606 
607 	bufferlen = *nameBufferLen;
608 	res = propset_get(pe->prop_set, &ps, &ps_len, &eps, &eps_len);
609 	if (res != TEE_SUCCESS)
610 		goto err;
611 
612 	if (pe->idx < ps_len)
613 		str = ps[pe->idx].str;
614 	else if ((pe->idx - ps_len) < eps_len)
615 		str = ta_props[pe->idx - ps_len].name;
616 	else {
617 		res = TEE_ERROR_ITEM_NOT_FOUND;
618 		goto err;
619 	}
620 
621 	l = strlcpy(nameBuffer, str, bufferlen);
622 
623 	/* The size "must account for the zero terminator" */
624 	*nameBufferLen = l + 1;
625 
626 	if (l >= bufferlen) {
627 		res = TEE_ERROR_SHORT_BUFFER;
628 		goto err;
629 	}
630 
631 	goto out;
632 
633 err:
634 	if (res == TEE_ERROR_ITEM_NOT_FOUND ||
635 	    res == TEE_ERROR_SHORT_BUFFER)
636 		return res;
637 	TEE_Panic(0);
638 out:
639 	return TEE_SUCCESS;
640 }
641 
642 TEE_Result TEE_GetNextProperty(TEE_PropSetHandle enumerator)
643 {
644 	TEE_Result res;
645 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
646 	uint32_t next_idx;
647 	const struct prop_set *ps;
648 	size_t ps_len;
649 	const struct user_ta_property *eps;
650 	size_t eps_len;
651 
652 	if (pe == NULL) {
653 		res = TEE_ERROR_BAD_PARAMETERS;
654 		goto err;
655 	}
656 
657 	if (pe->idx == PROP_ENUMERATOR_NOT_STARTED) {
658 		res = TEE_ERROR_ITEM_NOT_FOUND;
659 		goto err;
660 	}
661 
662 	res = propset_get(pe->prop_set, &ps, &ps_len, &eps, &eps_len);
663 	if (res != TEE_SUCCESS)
664 		goto err;
665 
666 	next_idx = pe->idx + 1;
667 	pe->idx = next_idx;
668 	if (next_idx >= (ps_len + eps_len)) {
669 		res = TEE_ERROR_ITEM_NOT_FOUND;
670 		goto err;
671 	}
672 
673 	goto out;
674 
675 err:
676 	if (res == TEE_ERROR_ITEM_NOT_FOUND)
677 		return res;
678 	TEE_Panic(0);
679 out:
680 	return TEE_SUCCESS;
681 }
682