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