xref: /optee_os/lib/libutee/tee_api_property.c (revision 97b8ba50e03a08e7e97179164bb62b3ac8caa2f7)
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,
153 						       &index);
154 		if (res != TEE_SUCCESS)
155 			return res;
156 		res = _utee_get_property((unsigned long)h, index, NULL, NULL,
157 					 buf, len, &prop_type);
158 	} else {
159 		struct prop_enumerator *pe = (struct prop_enumerator *)h;
160 		uint32_t idx = pe->idx;
161 
162 		if (idx == PROP_ENUMERATOR_NOT_STARTED)
163 			return TEE_ERROR_ITEM_NOT_FOUND;
164 
165 		res = propset_get(pe->prop_set, &eps, &eps_len);
166 		if (res != TEE_SUCCESS)
167 			return res;
168 
169 		if (idx < eps_len)
170 			return propget_get_ext_prop(eps + idx, type, buf, len);
171 		idx -= eps_len;
172 
173 		res = _utee_get_property((unsigned long)pe->prop_set, idx,
174 					 NULL, NULL, buf, len, &prop_type);
175 		if (res == TEE_ERROR_ITEM_NOT_FOUND)
176 			res = TEE_ERROR_BAD_PARAMETERS;
177 	}
178 
179 	*type = prop_type;
180 	return res;
181 }
182 
183 TEE_Result TEE_GetPropertyAsString(TEE_PropSetHandle propsetOrEnumerator,
184 				   const char *name, char *value,
185 				   uint32_t *value_len)
186 {
187 	TEE_Result res;
188 	size_t l;
189 	enum user_ta_prop_type type;
190 	void *tmp_buf = 0;
191 	uint32_t tmp_len;
192 	uint32_t uint32_val;
193 	bool bool_val;
194 	TEE_Identity *p_identity_val;
195 
196 	if (!value || !value_len) {
197 		res = TEE_ERROR_BAD_PARAMETERS;
198 		goto out;
199 	}
200 
201 	tmp_len = *value_len;
202 	if (tmp_len < sizeof(TEE_Identity))
203 		tmp_len = sizeof(TEE_Identity);
204 	tmp_buf = TEE_Malloc(tmp_len, TEE_USER_MEM_HINT_NO_FILL_ZERO);
205 	if (!tmp_buf) {
206 		res = TEE_ERROR_OUT_OF_MEMORY;
207 		goto out;
208 	}
209 
210 	res = propget_get_property(propsetOrEnumerator, name, &type,
211 				   tmp_buf, &tmp_len);
212 	if (res != TEE_SUCCESS) {
213 		if (res == TEE_ERROR_SHORT_BUFFER) {
214 			if (type == USER_TA_PROP_TYPE_BINARY_BLOCK) {
215 				/*
216 				 * in this case, we must enlarge the buffer
217 				 * with the size of the of the base64 encoded
218 				 * see base64_enc() function
219 				 */
220 				tmp_len = _base64_enc_len(tmp_len);
221 			}
222 			*value_len = tmp_len;
223 		}
224 		goto out;
225 	}
226 
227 	switch (type) {
228 	case USER_TA_PROP_TYPE_BOOL:
229 		bool_val = *((bool *)tmp_buf);
230 		l = strlcpy(value, (bool_val ? "true" : "false"), *value_len);
231 		break;
232 
233 	case USER_TA_PROP_TYPE_U32:
234 		uint32_val = *((uint32_t *)tmp_buf);
235 		l = snprintf(value, *value_len, "%u", uint32_val);
236 		break;
237 
238 	case USER_TA_PROP_TYPE_UUID:
239 		l = snprintk(value, *value_len, "%pUl", tmp_buf);
240 		break;
241 
242 	case USER_TA_PROP_TYPE_IDENTITY:
243 		p_identity_val = ((TEE_Identity *)tmp_buf);
244 		l = snprintk(value, *value_len, "%u:%pUl",
245 			     p_identity_val->login,
246 			     (void *)(&(p_identity_val->uuid)));
247 		break;
248 
249 	case USER_TA_PROP_TYPE_STRING:
250 		l = strlcpy(value, tmp_buf, *value_len);
251 		break;
252 
253 	case USER_TA_PROP_TYPE_BINARY_BLOCK:
254 		l = *value_len;	/* l includes the zero-termination */
255 		if (!_base64_enc(tmp_buf, tmp_len, value, &l) &&
256 		    l <= *value_len) {
257 			res = TEE_ERROR_GENERIC;
258 			goto out;
259 		}
260 		l--;	/* remove the zero-termination that is added later */
261 		break;
262 
263 	default:
264 		res = TEE_ERROR_BAD_FORMAT;
265 		goto out;
266 	}
267 
268 	l++;	/* include zero termination */
269 
270 	if (l > *value_len)
271 		res = TEE_ERROR_SHORT_BUFFER;
272 	*value_len = l;
273 
274 out:
275 	if (tmp_buf)
276 		TEE_Free(tmp_buf);
277 	if (res != TEE_SUCCESS &&
278 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
279 	    res != TEE_ERROR_SHORT_BUFFER)
280 		TEE_Panic(0);
281 
282 	return res;
283 }
284 
285 TEE_Result TEE_GetPropertyAsBool(TEE_PropSetHandle propsetOrEnumerator,
286 				 const char *name, bool *value)
287 {
288 	TEE_Result res;
289 	enum user_ta_prop_type type;
290 	uint32_t bool_len = sizeof(bool);
291 	if (value == NULL) {
292 		res = TEE_ERROR_BAD_PARAMETERS;
293 		goto out;
294 	}
295 
296 	type = USER_TA_PROP_TYPE_BOOL;
297 	res = propget_get_property(propsetOrEnumerator, name, &type,
298 				   value, &bool_len);
299 	if (type != USER_TA_PROP_TYPE_BOOL)
300 		res = TEE_ERROR_BAD_FORMAT;
301 	if (res != TEE_SUCCESS)
302 		goto out;
303 
304 out:
305 	if (res != TEE_SUCCESS &&
306 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
307 	    res != TEE_ERROR_BAD_FORMAT)
308 		TEE_Panic(0);
309 
310 	return res;
311 }
312 
313 TEE_Result TEE_GetPropertyAsU32(TEE_PropSetHandle propsetOrEnumerator,
314 				const char *name, uint32_t *value)
315 {
316 	TEE_Result res;
317 	enum user_ta_prop_type type;
318 	uint32_t uint32_len = sizeof(uint32_t);
319 
320 	if (!value) {
321 		res = TEE_ERROR_BAD_PARAMETERS;
322 		goto out;
323 	}
324 
325 	type = USER_TA_PROP_TYPE_U32;
326 	res = propget_get_property(propsetOrEnumerator, name, &type,
327 				   value, &uint32_len);
328 	if (type != USER_TA_PROP_TYPE_U32)
329 		res = TEE_ERROR_BAD_FORMAT;
330 
331 out:
332 	if (res != TEE_SUCCESS &&
333 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
334 	    res != TEE_ERROR_BAD_FORMAT)
335 		TEE_Panic(0);
336 
337 	return res;
338 }
339 
340 TEE_Result TEE_GetPropertyAsBinaryBlock(TEE_PropSetHandle propsetOrEnumerator,
341 					const char *name, void *value,
342 					uint32_t *value_len)
343 {
344 	TEE_Result res;
345 	enum user_ta_prop_type type;
346 
347 	if (!value_len) {
348 		res = TEE_ERROR_BAD_PARAMETERS;
349 		goto out;
350 	}
351 
352 	type = USER_TA_PROP_TYPE_BINARY_BLOCK;
353 	res = propget_get_property(propsetOrEnumerator, name, &type,
354 				   value, value_len);
355 	if (type != USER_TA_PROP_TYPE_BINARY_BLOCK)
356 		res = TEE_ERROR_BAD_FORMAT;
357 
358 out:
359 	if (res != TEE_SUCCESS &&
360 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
361 	    res != TEE_ERROR_BAD_FORMAT &&
362 	    res != TEE_ERROR_SHORT_BUFFER)
363 		TEE_Panic(0);
364 
365 	return res;
366 }
367 
368 TEE_Result TEE_GetPropertyAsUUID(TEE_PropSetHandle propsetOrEnumerator,
369 				 const char *name, TEE_UUID *value)
370 {
371 	TEE_Result res;
372 	enum user_ta_prop_type type;
373 	uint32_t uuid_len = sizeof(TEE_UUID);
374 
375 	if (!value) {
376 		res = TEE_ERROR_BAD_PARAMETERS;
377 		goto out;
378 	}
379 
380 	type = USER_TA_PROP_TYPE_UUID;
381 	res = propget_get_property(propsetOrEnumerator, name, &type,
382 				   value, &uuid_len);
383 	if (type != USER_TA_PROP_TYPE_UUID)
384 		res = TEE_ERROR_BAD_FORMAT;
385 
386 out:
387 	if (res != TEE_SUCCESS &&
388 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
389 	    res != TEE_ERROR_BAD_FORMAT)
390 		TEE_Panic(0);
391 
392 	return res;
393 }
394 
395 TEE_Result TEE_GetPropertyAsIdentity(TEE_PropSetHandle propsetOrEnumerator,
396 				     const char *name, TEE_Identity *value)
397 {
398 	TEE_Result res;
399 	enum user_ta_prop_type type;
400 	uint32_t identity_len = sizeof(TEE_Identity);
401 
402 	if (!value) {
403 		res = TEE_ERROR_BAD_PARAMETERS;
404 		goto out;
405 	}
406 
407 	type = USER_TA_PROP_TYPE_IDENTITY;
408 	res = propget_get_property(propsetOrEnumerator, name, &type,
409 				   value, &identity_len);
410 	if (type != USER_TA_PROP_TYPE_IDENTITY)
411 		res = TEE_ERROR_BAD_FORMAT;
412 
413 out:
414 	if (res != TEE_SUCCESS &&
415 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
416 	    res != TEE_ERROR_BAD_FORMAT)
417 		TEE_Panic(0);
418 
419 	return res;
420 }
421 
422 TEE_Result TEE_AllocatePropertyEnumerator(TEE_PropSetHandle *enumerator)
423 {
424 	TEE_Result res;
425 	struct prop_enumerator *pe;
426 
427 	if (!enumerator) {
428 		res = TEE_ERROR_BAD_PARAMETERS;
429 		goto err;
430 	}
431 
432 	pe = TEE_Malloc(sizeof(struct prop_enumerator),
433 			TEE_USER_MEM_HINT_NO_FILL_ZERO);
434 	if (pe == NULL) {
435 		res = TEE_ERROR_OUT_OF_MEMORY;
436 		goto err;
437 	}
438 
439 	*enumerator = (TEE_PropSetHandle) pe;
440 	TEE_ResetPropertyEnumerator(*enumerator);
441 
442 	goto out;
443 
444 err:
445 	if (res == TEE_ERROR_OUT_OF_MEMORY)
446 		return res;
447 	TEE_Panic(0);
448 out:
449 	return TEE_SUCCESS;
450 }
451 
452 void TEE_ResetPropertyEnumerator(TEE_PropSetHandle enumerator)
453 {
454 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
455 
456 	pe->idx = PROP_ENUMERATOR_NOT_STARTED;
457 }
458 
459 void TEE_FreePropertyEnumerator(TEE_PropSetHandle enumerator)
460 {
461 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
462 
463 	TEE_Free(pe);
464 }
465 
466 void TEE_StartPropertyEnumerator(TEE_PropSetHandle enumerator,
467 				 TEE_PropSetHandle propSet)
468 {
469 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
470 
471 	if (!pe)
472 		return;
473 
474 	pe->idx = 0;
475 	pe->prop_set = propSet;
476 }
477 
478 TEE_Result TEE_GetPropertyName(TEE_PropSetHandle enumerator,
479 			       void *name, uint32_t *name_len)
480 {
481 	TEE_Result res;
482 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
483 	const struct user_ta_property *eps;
484 	size_t eps_len;
485 	const char *str;
486 	size_t bufferlen;
487 
488 	if (!pe || !name || !name_len) {
489 		res = TEE_ERROR_BAD_PARAMETERS;
490 		goto err;
491 	}
492 
493 	bufferlen = *name_len;
494 	res = propset_get(pe->prop_set, &eps, &eps_len);
495 	if (res != TEE_SUCCESS)
496 		goto err;
497 
498 	if (pe->idx < eps_len) {
499 		str = eps[pe->idx].name;
500 		bufferlen = strlcpy(name, str, *name_len) + 1;
501 		if (bufferlen > *name_len)
502 			res = TEE_ERROR_SHORT_BUFFER;
503 		*name_len = bufferlen;
504 	} else {
505 		res = _utee_get_property((unsigned long)pe->prop_set,
506 					 pe->idx - eps_len, name, name_len,
507 					 NULL, NULL, NULL);
508 		if (res != TEE_SUCCESS)
509 			goto err;
510 	}
511 
512 err:
513 	if (res != TEE_SUCCESS &&
514 	    res != TEE_ERROR_ITEM_NOT_FOUND &&
515 	    res != TEE_ERROR_SHORT_BUFFER)
516 		TEE_Panic(0);
517 	return res;
518 }
519 
520 TEE_Result TEE_GetNextProperty(TEE_PropSetHandle enumerator)
521 {
522 	TEE_Result res;
523 	struct prop_enumerator *pe = (struct prop_enumerator *)enumerator;
524 	uint32_t next_idx;
525 	const struct user_ta_property *eps;
526 	size_t eps_len;
527 
528 	if (!pe) {
529 		res = TEE_ERROR_BAD_PARAMETERS;
530 		goto out;
531 	}
532 
533 	if (pe->idx == PROP_ENUMERATOR_NOT_STARTED) {
534 		res = TEE_ERROR_ITEM_NOT_FOUND;
535 		goto out;
536 	}
537 
538 	res = propset_get(pe->prop_set, &eps, &eps_len);
539 	if (res != TEE_SUCCESS)
540 		goto out;
541 
542 	next_idx = pe->idx + 1;
543 	pe->idx = next_idx;
544 	if (next_idx < eps_len)
545 		res = TEE_SUCCESS;
546 	else
547 		res = _utee_get_property((unsigned long)pe->prop_set,
548 					 next_idx - eps_len, NULL, NULL, NULL,
549 					 NULL, NULL);
550 
551 out:
552 	if (res != TEE_SUCCESS &&
553 	    res != TEE_ERROR_ITEM_NOT_FOUND)
554 		TEE_Panic(0);
555 	return res;
556 }
557