xref: /optee_os/lib/libutee/tee_api_property.c (revision 5a913ee74d3c71af2a2860ce8a4e7aeab2916f9b)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2017, Linaro Limited
5  */
6 #include <printk.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <tee_api_defines.h>
11 #include <tee_api.h>
12 #include <tee_api_types.h>
13 #include <tee_arith_internal.h>
14 #include <tee_internal_api_extensions.h>
15 #include <tee_isocket.h>
16 #include <user_ta_header.h>
17 #include <utee_syscalls.h>
18 #include <util.h>
19 
20 #include "string_ext.h"
21 #include "base64.h"
22 
23 #define PROP_STR_MAX    80
24 
25 #define PROP_ENUMERATOR_NOT_STARTED 0xffffffff
26 
27 struct prop_enumerator {
28 	uint32_t idx;			/* current index */
29 	TEE_PropSetHandle prop_set;	/* part of TEE_PROPSET_xxx */
30 };
31 
32 const struct user_ta_property tee_props[] = {
33 	{
34 		"gpd.tee.arith.maxBigIntSize",
35 		USER_TA_PROP_TYPE_U32,
36 		&(const uint32_t){CFG_TA_BIGNUM_MAX_BITS}
37 	},
38 	{
39 		"gpd.tee.sockets.version",
40 		USER_TA_PROP_TYPE_U32,
41 		&(const uint32_t){TEE_ISOCKET_VERSION}
42 	},
43 	{
44 		"gpd.tee.sockets.tcp.version",
45 		USER_TA_PROP_TYPE_U32,
46 		&(const uint32_t){TEE_ISOCKET_VERSION}
47 	},
48 };
49 
50 static TEE_Result propset_get(TEE_PropSetHandle h,
51 			      const struct user_ta_property **eps,
52 			      size_t *eps_len)
53 {
54 	if (h == TEE_PROPSET_CURRENT_TA) {
55 		*eps = ta_props;
56 		*eps_len = ta_num_props;
57 	} else if (h == TEE_PROPSET_CURRENT_CLIENT) {
58 		*eps = NULL;
59 		*eps_len = 0;
60 	} else if (h == TEE_PROPSET_TEE_IMPLEMENTATION) {
61 		*eps = tee_props;
62 		*eps_len = ARRAY_SIZE(tee_props);
63 	} else {
64 		return TEE_ERROR_ITEM_NOT_FOUND;
65 	}
66 
67 	return TEE_SUCCESS;
68 }
69 
70 static TEE_Result propget_get_ext_prop(const struct user_ta_property *ep,
71 				       enum user_ta_prop_type *type,
72 				       void *buf, uint32_t *len)
73 {
74 	size_t l;
75 
76 	*type = ep->type;
77 	switch (*type) {
78 	case USER_TA_PROP_TYPE_BOOL:
79 		l = sizeof(bool);
80 		break;
81 	case USER_TA_PROP_TYPE_U32:
82 		l = sizeof(uint32_t);
83 		break;
84 	case USER_TA_PROP_TYPE_UUID:
85 		l = sizeof(TEE_UUID);
86 		break;
87 	case USER_TA_PROP_TYPE_IDENTITY:
88 		l = sizeof(TEE_Identity);
89 		break;
90 	case USER_TA_PROP_TYPE_STRING:
91 		/* take the leading 0 into account */
92 		l = strlen(ep->value) + 1;
93 		break;
94 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
95 		/*
96 		 * in case of TA property, a binary block is provided as a
97 		 * string, which is base64 encoded. We must first decode it,
98 		 * without taking into account the zero termination of the
99 		 * string
100 		 */
101 		l = *len;
102 		if (!base64_dec(ep->value, strlen(ep->value), buf, &l) &&
103 		    (l <= *len))
104 			return TEE_ERROR_GENERIC;
105 		if (*len < l) {
106 			*len = l;
107 			return TEE_ERROR_SHORT_BUFFER;
108 		}
109 
110 		*len = l;
111 		return TEE_SUCCESS;
112 	default:
113 		return TEE_ERROR_GENERIC;
114 	}
115 
116 	if (*len < l) {
117 		*len = l;
118 		return TEE_ERROR_SHORT_BUFFER;
119 	}
120 
121 	*len = l;
122 	memcpy(buf, ep->value, l);
123 	return TEE_SUCCESS;
124 }
125 
126 static TEE_Result propget_get_property(TEE_PropSetHandle h, const char *name,
127 				       enum user_ta_prop_type *type,
128 				       void *buf, uint32_t *len)
129 {
130 	TEE_Result res;
131 	const struct user_ta_property *eps;
132 	size_t eps_len;
133 	uint32_t prop_type;
134 	uint32_t index;
135 
136 	if (h == TEE_PROPSET_CURRENT_TA || h == TEE_PROPSET_CURRENT_CLIENT ||
137 	    h == TEE_PROPSET_TEE_IMPLEMENTATION) {
138 		size_t n;
139 
140 		res = propset_get(h, &eps, &eps_len);
141 		if (res != TEE_SUCCESS)
142 			return res;
143 
144 		for (n = 0; n < eps_len; n++) {
145 			if (!strcmp(name, eps[n].name))
146 				return propget_get_ext_prop(eps + n, type,
147 							    buf, len);
148 		}
149 
150 		/* get the index from the name */
151 		res = utee_get_property_name_to_index((unsigned long)h, name,
152 						strlen(name) + 1, &index);
153 		if (res != TEE_SUCCESS)
154 			return res;
155 		res = utee_get_property((unsigned long)h, index, NULL, NULL,
156 					buf, len, &prop_type);
157 	} else {
158 		struct prop_enumerator *pe = (struct prop_enumerator *)h;
159 		uint32_t idx = pe->idx;
160 
161 		if (idx == PROP_ENUMERATOR_NOT_STARTED)
162 			return TEE_ERROR_ITEM_NOT_FOUND;
163 
164 		res = propset_get(pe->prop_set, &eps, &eps_len);
165 		if (res != TEE_SUCCESS)
166 			return res;
167 
168 		if (idx < eps_len)
169 			return propget_get_ext_prop(eps + idx, type, buf, len);
170 		idx -= eps_len;
171 
172 		res = utee_get_property((unsigned long)pe->prop_set, idx,
173 					NULL, NULL, buf, len, &prop_type);
174 		if (res == TEE_ERROR_ITEM_NOT_FOUND)
175 			res = TEE_ERROR_BAD_PARAMETERS;
176 	}
177 
178 	*type = prop_type;
179 	return res;
180 }
181 
182 TEE_Result TEE_GetPropertyAsString(TEE_PropSetHandle propsetOrEnumerator,
183 				   const char *name, char *value,
184 				   uint32_t *value_len)
185 {
186 	TEE_Result res;
187 	size_t l;
188 	enum user_ta_prop_type type;
189 	void *tmp_buf = 0;
190 	uint32_t tmp_len;
191 	uint32_t uint32_val;
192 	bool bool_val;
193 	TEE_Identity *p_identity_val;
194 
195 	if (!value || !value_len) {
196 		res = TEE_ERROR_BAD_PARAMETERS;
197 		goto out;
198 	}
199 
200 	tmp_len = *value_len;
201 	if (tmp_len < sizeof(TEE_Identity))
202 		tmp_len = sizeof(TEE_Identity);
203 	tmp_buf = TEE_Malloc(tmp_len, TEE_USER_MEM_HINT_NO_FILL_ZERO);
204 	if (!tmp_buf) {
205 		res = TEE_ERROR_OUT_OF_MEMORY;
206 		goto out;
207 	}
208 
209 	res = propget_get_property(propsetOrEnumerator, name, &type,
210 				   tmp_buf, &tmp_len);
211 	if (res != TEE_SUCCESS) {
212 		if (res == TEE_ERROR_SHORT_BUFFER) {
213 			if (type == USER_TA_PROP_TYPE_BINARY_BLOCK) {
214 				/*
215 				 * in this case, we must enlarge the buffer
216 				 * with the size of the of the base64 encoded
217 				 * see base64_enc() function
218 				 */
219 				tmp_len = base64_enc_len(tmp_len);
220 			}
221 			*value_len = tmp_len;
222 		}
223 		goto out;
224 	}
225 
226 	switch (type) {
227 	case USER_TA_PROP_TYPE_BOOL:
228 		bool_val = *((bool *)tmp_buf);
229 		l = strlcpy(value, (bool_val ? "true" : "false"), *value_len);
230 		break;
231 
232 	case USER_TA_PROP_TYPE_U32:
233 		uint32_val = *((uint32_t *)tmp_buf);
234 		l = snprintf(value, *value_len, "%u", uint32_val);
235 		break;
236 
237 	case USER_TA_PROP_TYPE_UUID:
238 		l = snprintk(value, *value_len, "%pUl", tmp_buf);
239 		break;
240 
241 	case USER_TA_PROP_TYPE_IDENTITY:
242 		p_identity_val = ((TEE_Identity *)tmp_buf);
243 		l = snprintk(value, *value_len, "%u:%pUl",
244 			     p_identity_val->login,
245 			     (void *)(&(p_identity_val->uuid)));
246 		break;
247 
248 	case USER_TA_PROP_TYPE_STRING:
249 		l = strlcpy(value, tmp_buf, *value_len);
250 		break;
251 
252 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
253 		l = *value_len;	/* l includes the zero-termination */
254 		if (!base64_enc(tmp_buf, tmp_len, value, &l) &&
255 		    (l <= *value_len)) {
256 			res = TEE_ERROR_GENERIC;
257 			goto out;
258 		}
259 		l--;	/* remove the zero-termination that is added later */
260 		break;
261 
262 	default:
263 		res = TEE_ERROR_BAD_FORMAT;
264 		goto out;
265 	}
266 
267 	l++;	/* include zero termination */
268 
269 	if (l > *value_len)
270 		res = TEE_ERROR_SHORT_BUFFER;
271 	*value_len = l;
272 
273 out:
274 	if (tmp_buf)
275 		TEE_Free(tmp_buf);
276 	if (res != TEE_SUCCESS &&
277 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
278 	    res != TEE_ERROR_SHORT_BUFFER)
279 		TEE_Panic(0);
280 
281 	return res;
282 }
283 
284 TEE_Result TEE_GetPropertyAsBool(TEE_PropSetHandle propsetOrEnumerator,
285 				 const char *name, bool *value)
286 {
287 	TEE_Result res;
288 	enum user_ta_prop_type type;
289 	uint32_t bool_len = sizeof(bool);
290 	if (value == NULL) {
291 		res = TEE_ERROR_BAD_PARAMETERS;
292 		goto out;
293 	}
294 
295 	type = USER_TA_PROP_TYPE_BOOL;
296 	res = propget_get_property(propsetOrEnumerator, name, &type,
297 				   value, &bool_len);
298 	if (type != USER_TA_PROP_TYPE_BOOL)
299 		res = TEE_ERROR_BAD_FORMAT;
300 	if (res != TEE_SUCCESS)
301 		goto out;
302 
303 out:
304 	if (res != TEE_SUCCESS &&
305 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
306 	    res != TEE_ERROR_BAD_FORMAT)
307 		TEE_Panic(0);
308 
309 	return res;
310 }
311 
312 TEE_Result TEE_GetPropertyAsU32(TEE_PropSetHandle propsetOrEnumerator,
313 				const char *name, uint32_t *value)
314 {
315 	TEE_Result res;
316 	enum user_ta_prop_type type;
317 	uint32_t uint32_len = sizeof(uint32_t);
318 
319 	if (!value) {
320 		res = TEE_ERROR_BAD_PARAMETERS;
321 		goto out;
322 	}
323 
324 	type = USER_TA_PROP_TYPE_U32;
325 	res = propget_get_property(propsetOrEnumerator, name, &type,
326 				   value, &uint32_len);
327 	if (type != USER_TA_PROP_TYPE_U32)
328 		res = TEE_ERROR_BAD_FORMAT;
329 
330 out:
331 	if (res != TEE_SUCCESS &&
332 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
333 	    res != TEE_ERROR_BAD_FORMAT)
334 		TEE_Panic(0);
335 
336 	return res;
337 }
338 
339 TEE_Result TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator,
340 					const char *name, void *value,
341 					uint32_t *value_len)
342 {
343 	TEE_Result res;
344 	enum user_ta_prop_type type;
345 
346 	if (!value || !value_len) {
347 		res = TEE_ERROR_BAD_PARAMETERS;
348 		goto out;
349 	}
350 
351 	type = USER_TA_PROP_TYPE_BINARY_BLOCK;
352 	res = propget_get_property(propsetOrEnumerator, name, &type,
353 				   value, value_len);
354 	if (type != USER_TA_PROP_TYPE_BINARY_BLOCK)
355 		res = TEE_ERROR_BAD_FORMAT;
356 
357 out:
358 	if (res != TEE_SUCCESS &&
359 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
360 	    res != TEE_ERROR_BAD_FORMAT &&
361 	    res != TEE_ERROR_SHORT_BUFFER)
362 		TEE_Panic(0);
363 
364 	return res;
365 }
366 
367 TEE_Result TEE_GetPropertyAsUUID(TEE_PropSetHandle propsetOrEnumerator,
368 				 const char *name, TEE_UUID *value)
369 {
370 	TEE_Result res;
371 	enum user_ta_prop_type type;
372 	uint32_t uuid_len = sizeof(TEE_UUID);
373 
374 	if (!value) {
375 		res = TEE_ERROR_BAD_PARAMETERS;
376 		goto out;
377 	}
378 
379 	type = USER_TA_PROP_TYPE_UUID;
380 	res = propget_get_property(propsetOrEnumerator, name, &type,
381 				   value, &uuid_len);
382 	if (type != USER_TA_PROP_TYPE_UUID)
383 		res = TEE_ERROR_BAD_FORMAT;
384 
385 out:
386 	if (res != TEE_SUCCESS &&
387 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
388 	    res != TEE_ERROR_BAD_FORMAT)
389 		TEE_Panic(0);
390 
391 	return res;
392 }
393 
394 TEE_Result TEE_GetPropertyAsIdentity(TEE_PropSetHandle propsetOrEnumerator,
395 				     const char *name, TEE_Identity *value)
396 {
397 	TEE_Result res;
398 	enum user_ta_prop_type type;
399 	uint32_t identity_len = sizeof(TEE_Identity);
400 
401 	if (!value) {
402 		res = TEE_ERROR_BAD_PARAMETERS;
403 		goto out;
404 	}
405 
406 	type = USER_TA_PROP_TYPE_IDENTITY;
407 	res = propget_get_property(propsetOrEnumerator, name, &type,
408 				   value, &identity_len);
409 	if (type != USER_TA_PROP_TYPE_IDENTITY)
410 		res = TEE_ERROR_BAD_FORMAT;
411 
412 out:
413 	if (res != TEE_SUCCESS &&
414 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
415 	    res != TEE_ERROR_BAD_FORMAT)
416 		TEE_Panic(0);
417 
418 	return res;
419 }
420 
421 TEE_Result TEE_AllocatePropertyEnumerator(TEE_PropSetHandle *enumerator)
422 {
423 	TEE_Result res;
424 	struct prop_enumerator *pe;
425 
426 	if (!enumerator) {
427 		res = TEE_ERROR_BAD_PARAMETERS;
428 		goto err;
429 	}
430 
431 	pe = TEE_Malloc(sizeof(struct prop_enumerator),
432 			TEE_USER_MEM_HINT_NO_FILL_ZERO);
433 	if (pe == NULL) {
434 		res = TEE_ERROR_OUT_OF_MEMORY;
435 		goto err;
436 	}
437 
438 	*enumerator = (TEE_PropSetHandle) pe;
439 	TEE_ResetPropertyEnumerator(*enumerator);
440 
441 	goto out;
442 
443 err:
444 	if (res == TEE_ERROR_OUT_OF_MEMORY)
445 		return res;
446 	TEE_Panic(0);
447 out:
448 	return TEE_SUCCESS;
449 }
450 
451 void TEE_ResetPropertyEnumerator(TEE_PropSetHandle enumerator)
452 {
453 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
454 
455 	pe->idx = PROP_ENUMERATOR_NOT_STARTED;
456 }
457 
458 void TEE_FreePropertyEnumerator(TEE_PropSetHandle enumerator)
459 {
460 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
461 
462 	TEE_Free(pe);
463 }
464 
465 void TEE_StartPropertyEnumerator(TEE_PropSetHandle enumerator,
466 				 TEE_PropSetHandle propSet)
467 {
468 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
469 
470 	if (!pe)
471 		return;
472 
473 	pe->idx = 0;
474 	pe->prop_set = propSet;
475 }
476 
477 TEE_Result TEE_GetPropertyName(TEE_PropSetHandle enumerator,
478 			       void *name, uint32_t *name_len)
479 {
480 	TEE_Result res;
481 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
482 	const struct user_ta_property *eps;
483 	size_t eps_len;
484 	const char *str;
485 	size_t bufferlen;
486 
487 	if (!pe || !name || !name_len) {
488 		res = TEE_ERROR_BAD_PARAMETERS;
489 		goto err;
490 	}
491 
492 	bufferlen = *name_len;
493 	res = propset_get(pe->prop_set, &eps, &eps_len);
494 	if (res != TEE_SUCCESS)
495 		goto err;
496 
497 	if (pe->idx < eps_len) {
498 		str = eps[pe->idx].name;
499 		bufferlen = strlcpy(name, str, *name_len) + 1;
500 		if (bufferlen > *name_len)
501 			res = TEE_ERROR_SHORT_BUFFER;
502 		*name_len = bufferlen;
503 	} else {
504 		res = utee_get_property((unsigned long)pe->prop_set,
505 					pe->idx - eps_len,
506 					name, name_len, NULL, NULL, NULL);
507 		if (res != TEE_SUCCESS)
508 			goto err;
509 	}
510 
511 err:
512 	if (res != TEE_SUCCESS &&
513 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
514 	    res != TEE_ERROR_SHORT_BUFFER)
515 		TEE_Panic(0);
516 	return res;
517 }
518 
519 TEE_Result TEE_GetNextProperty(TEE_PropSetHandle enumerator)
520 {
521 	TEE_Result res;
522 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
523 	uint32_t next_idx;
524 	const struct user_ta_property *eps;
525 	size_t eps_len;
526 
527 	if (!pe) {
528 		res = TEE_ERROR_BAD_PARAMETERS;
529 		goto out;
530 	}
531 
532 	if (pe->idx == PROP_ENUMERATOR_NOT_STARTED) {
533 		res = TEE_ERROR_ITEM_NOT_FOUND;
534 		goto out;
535 	}
536 
537 	res = propset_get(pe->prop_set, &eps, &eps_len);
538 	if (res != TEE_SUCCESS)
539 		goto out;
540 
541 	next_idx = pe->idx + 1;
542 	pe->idx = next_idx;
543 	if (next_idx < eps_len)
544 		res = TEE_SUCCESS;
545 	else
546 		res = utee_get_property((unsigned long)pe->prop_set,
547 					next_idx - eps_len,
548 					NULL, NULL, NULL, NULL, NULL);
549 
550 out:
551 	if (res != TEE_SUCCESS &&
552 	    res != TEE_ERROR_ITEM_NOT_FOUND)
553 		TEE_Panic(0);
554 	return res;
555 }
556