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