xref: /optee_os/ta/pkcs11/src/attributes.c (revision 0b9125844ba4380767f2efa180ac30b014961c4d)
163f89caaSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
263f89caaSJens Wiklander /*
363f89caaSJens Wiklander  * Copyright (c) 2017-2020, Linaro Limited
463f89caaSJens Wiklander  */
563f89caaSJens Wiklander 
663f89caaSJens Wiklander #include <assert.h>
763f89caaSJens Wiklander #include <compiler.h>
863f89caaSJens Wiklander #include <pkcs11_ta.h>
963f89caaSJens Wiklander #include <stddef.h>
1063f89caaSJens Wiklander #include <stdlib.h>
1163f89caaSJens Wiklander #include <string.h>
1263f89caaSJens Wiklander #include <string_ext.h>
1363f89caaSJens Wiklander #include <tee_internal_api.h>
1463f89caaSJens Wiklander #include <tee_internal_api_extensions.h>
1563f89caaSJens Wiklander #include <trace.h>
1663f89caaSJens Wiklander #include <util.h>
1763f89caaSJens Wiklander 
1863f89caaSJens Wiklander #include "attributes.h"
1963f89caaSJens Wiklander #include "pkcs11_helpers.h"
2063f89caaSJens Wiklander #include "serializer.h"
2163f89caaSJens Wiklander 
2263f89caaSJens Wiklander enum pkcs11_rc init_attributes_head(struct obj_attrs **head)
2363f89caaSJens Wiklander {
2463f89caaSJens Wiklander 	*head = TEE_Malloc(sizeof(**head), TEE_MALLOC_FILL_ZERO);
2563f89caaSJens Wiklander 	if (!*head)
2663f89caaSJens Wiklander 		return PKCS11_CKR_DEVICE_MEMORY;
2763f89caaSJens Wiklander 
2863f89caaSJens Wiklander 	return PKCS11_CKR_OK;
2963f89caaSJens Wiklander }
3063f89caaSJens Wiklander 
3163f89caaSJens Wiklander enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute,
3263f89caaSJens Wiklander 			     void *data, size_t size)
3363f89caaSJens Wiklander {
3463f89caaSJens Wiklander 	size_t buf_len = sizeof(struct obj_attrs) + (*head)->attrs_size;
3563f89caaSJens Wiklander 	char **bstart = (void *)head;
3663f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
3763f89caaSJens Wiklander 	uint32_t data32 = 0;
3863f89caaSJens Wiklander 
3963f89caaSJens Wiklander 	data32 = attribute;
4063f89caaSJens Wiklander 	rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
4163f89caaSJens Wiklander 	if (rc)
4263f89caaSJens Wiklander 		return rc;
4363f89caaSJens Wiklander 
4463f89caaSJens Wiklander 	data32 = size;
4563f89caaSJens Wiklander 	rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
4663f89caaSJens Wiklander 	if (rc)
4763f89caaSJens Wiklander 		return rc;
4863f89caaSJens Wiklander 
4963f89caaSJens Wiklander 	rc = serialize(bstart, &buf_len, data, size);
5063f89caaSJens Wiklander 	if (rc)
5163f89caaSJens Wiklander 		return rc;
5263f89caaSJens Wiklander 
5363f89caaSJens Wiklander 	/* Alloced buffer is always well aligned */
5463f89caaSJens Wiklander 	head = (void *)bstart;
5563f89caaSJens Wiklander 	(*head)->attrs_size += 2 * sizeof(uint32_t) + size;
5663f89caaSJens Wiklander 	(*head)->attrs_count++;
5763f89caaSJens Wiklander 
5863f89caaSJens Wiklander 	return rc;
5963f89caaSJens Wiklander }
6063f89caaSJens Wiklander 
6163f89caaSJens Wiklander void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute,
6263f89caaSJens Wiklander 			void **attr, uint32_t *attr_size, size_t *count)
6363f89caaSJens Wiklander {
6463f89caaSJens Wiklander 	char *cur = (char *)head + sizeof(struct obj_attrs);
6563f89caaSJens Wiklander 	char *end = cur + head->attrs_size;
6663f89caaSJens Wiklander 	size_t next_off = 0;
6763f89caaSJens Wiklander 	size_t max_found = *count;
6863f89caaSJens Wiklander 	size_t found = 0;
6963f89caaSJens Wiklander 	void **attr_ptr = attr;
7063f89caaSJens Wiklander 	uint32_t *attr_size_ptr = attr_size;
7163f89caaSJens Wiklander 
7263f89caaSJens Wiklander 	for (; cur < end; cur += next_off) {
7363f89caaSJens Wiklander 		/* Structure aligned copy of the pkcs11_ref in the object */
7463f89caaSJens Wiklander 		struct pkcs11_attribute_head pkcs11_ref = { };
7563f89caaSJens Wiklander 
7663f89caaSJens Wiklander 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
7763f89caaSJens Wiklander 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
7863f89caaSJens Wiklander 
7963f89caaSJens Wiklander 		if (pkcs11_ref.id != attribute)
8063f89caaSJens Wiklander 			continue;
8163f89caaSJens Wiklander 
8263f89caaSJens Wiklander 		found++;
8363f89caaSJens Wiklander 
8463f89caaSJens Wiklander 		if (!max_found)
8563f89caaSJens Wiklander 			continue;	/* only count matching attributes */
8663f89caaSJens Wiklander 
87*0b912584SEtienne Carriere 		if (attr) {
88*0b912584SEtienne Carriere 			if (pkcs11_ref.size)
8963f89caaSJens Wiklander 				*attr_ptr++ = cur + sizeof(pkcs11_ref);
90*0b912584SEtienne Carriere 			else
91*0b912584SEtienne Carriere 				*attr_ptr++ = NULL;
92*0b912584SEtienne Carriere 		}
9363f89caaSJens Wiklander 
9463f89caaSJens Wiklander 		if (attr_size)
9563f89caaSJens Wiklander 			*attr_size_ptr++ = pkcs11_ref.size;
9663f89caaSJens Wiklander 
9763f89caaSJens Wiklander 		if (found == max_found)
9863f89caaSJens Wiklander 			break;
9963f89caaSJens Wiklander 	}
10063f89caaSJens Wiklander 
10163f89caaSJens Wiklander 	/* Sanity */
10263f89caaSJens Wiklander 	if (cur > end) {
10363f89caaSJens Wiklander 		DMSG("Exceeding serial object length");
10463f89caaSJens Wiklander 		TEE_Panic(0);
10563f89caaSJens Wiklander 	}
10663f89caaSJens Wiklander 
10763f89caaSJens Wiklander 	*count = found;
10863f89caaSJens Wiklander }
10963f89caaSJens Wiklander 
11063f89caaSJens Wiklander enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute,
11163f89caaSJens Wiklander 				 void **attr_ptr, uint32_t *attr_size)
11263f89caaSJens Wiklander {
11363f89caaSJens Wiklander 	size_t count = 1;
11463f89caaSJens Wiklander 
11563f89caaSJens Wiklander 	get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count);
11663f89caaSJens Wiklander 
11763f89caaSJens Wiklander 	if (!count)
11863f89caaSJens Wiklander 		return PKCS11_RV_NOT_FOUND;
11963f89caaSJens Wiklander 
12063f89caaSJens Wiklander 	if (count != 1)
12163f89caaSJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
12263f89caaSJens Wiklander 
12363f89caaSJens Wiklander 	return PKCS11_CKR_OK;
12463f89caaSJens Wiklander }
12563f89caaSJens Wiklander 
12663f89caaSJens Wiklander enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute,
12763f89caaSJens Wiklander 			     void *attr, uint32_t *attr_size)
12863f89caaSJens Wiklander {
12963f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
13063f89caaSJens Wiklander 	void *attr_ptr = NULL;
13163f89caaSJens Wiklander 	uint32_t size = 0;
13263f89caaSJens Wiklander 
13363f89caaSJens Wiklander 	rc = get_attribute_ptr(head, attribute, &attr_ptr, &size);
13463f89caaSJens Wiklander 	if (rc)
13563f89caaSJens Wiklander 		return rc;
13663f89caaSJens Wiklander 
13763f89caaSJens Wiklander 	if (attr_size && *attr_size != size) {
13863f89caaSJens Wiklander 		*attr_size = size;
13963f89caaSJens Wiklander 		/* This reuses buffer-to-small for any bad size matching */
14063f89caaSJens Wiklander 		return PKCS11_CKR_BUFFER_TOO_SMALL;
14163f89caaSJens Wiklander 	}
14263f89caaSJens Wiklander 
14363f89caaSJens Wiklander 	if (attr)
14463f89caaSJens Wiklander 		TEE_MemMove(attr, attr_ptr, size);
14563f89caaSJens Wiklander 
14663f89caaSJens Wiklander 	if (attr_size)
14763f89caaSJens Wiklander 		*attr_size = size;
14863f89caaSJens Wiklander 
14963f89caaSJens Wiklander 	return PKCS11_CKR_OK;
15063f89caaSJens Wiklander }
15163f89caaSJens Wiklander 
15263f89caaSJens Wiklander bool get_bool(struct obj_attrs *head, uint32_t attribute)
15363f89caaSJens Wiklander {
15463f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
15563f89caaSJens Wiklander 	uint8_t bbool = 0;
15663f89caaSJens Wiklander 	uint32_t size = sizeof(bbool);
15763f89caaSJens Wiklander 
15863f89caaSJens Wiklander 	rc = get_attribute(head, attribute, &bbool, &size);
15963f89caaSJens Wiklander 
16063f89caaSJens Wiklander 	if (rc == PKCS11_RV_NOT_FOUND)
16163f89caaSJens Wiklander 		return false;
16263f89caaSJens Wiklander 
16363f89caaSJens Wiklander 	assert(rc == PKCS11_CKR_OK);
16463f89caaSJens Wiklander 	return bbool;
16563f89caaSJens Wiklander }
16663f89caaSJens Wiklander 
16763f89caaSJens Wiklander #if CFG_TEE_TA_LOG_LEVEL > 0
16863f89caaSJens Wiklander /*
16963f89caaSJens Wiklander  * Debug: dump CK attribute array to output trace
17063f89caaSJens Wiklander  */
17163f89caaSJens Wiklander #define ATTR_TRACE_FMT	"%s attr %s / %s\t(0x%04"PRIx32" %"PRIu32"-byte"
17263f89caaSJens Wiklander #define ATTR_FMT_0BYTE	ATTR_TRACE_FMT ")"
17363f89caaSJens Wiklander #define ATTR_FMT_1BYTE	ATTR_TRACE_FMT ": %02x)"
17463f89caaSJens Wiklander #define ATTR_FMT_2BYTE	ATTR_TRACE_FMT ": %02x %02x)"
17563f89caaSJens Wiklander #define ATTR_FMT_3BYTE	ATTR_TRACE_FMT ": %02x %02x %02x)"
17663f89caaSJens Wiklander #define ATTR_FMT_4BYTE	ATTR_TRACE_FMT ": %02x %02x %02x %02x)"
17763f89caaSJens Wiklander #define ATTR_FMT_ARRAY	ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)"
17863f89caaSJens Wiklander 
17963f89caaSJens Wiklander static void __trace_attributes(char *prefix, void *src, void *end)
18063f89caaSJens Wiklander {
18163f89caaSJens Wiklander 	size_t next_off = 0;
18263f89caaSJens Wiklander 	char *prefix2 = NULL;
18363f89caaSJens Wiklander 	size_t prefix_len = strlen(prefix);
18463f89caaSJens Wiklander 	char *cur = src;
18563f89caaSJens Wiklander 
18663f89caaSJens Wiklander 	/* append 4 spaces to the prefix plus terminal '\0' */
18763f89caaSJens Wiklander 	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
18863f89caaSJens Wiklander 	if (!prefix2)
18963f89caaSJens Wiklander 		return;
19063f89caaSJens Wiklander 
19163f89caaSJens Wiklander 	TEE_MemMove(prefix2, prefix, prefix_len + 1);
19263f89caaSJens Wiklander 	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
19363f89caaSJens Wiklander 	*(prefix2 + prefix_len + 4) = '\0';
19463f89caaSJens Wiklander 
19563f89caaSJens Wiklander 	for (; cur < (char *)end; cur += next_off) {
19663f89caaSJens Wiklander 		struct pkcs11_attribute_head pkcs11_ref = { };
19763f89caaSJens Wiklander 		uint8_t data[4] = { 0 };
19863f89caaSJens Wiklander 
19963f89caaSJens Wiklander 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
20063f89caaSJens Wiklander 		TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
20163f89caaSJens Wiklander 			    MIN(pkcs11_ref.size, sizeof(data)));
20263f89caaSJens Wiklander 
20363f89caaSJens Wiklander 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
20463f89caaSJens Wiklander 
20563f89caaSJens Wiklander 		switch (pkcs11_ref.size) {
20663f89caaSJens Wiklander 		case 0:
20763f89caaSJens Wiklander 			IMSG_RAW(ATTR_FMT_0BYTE,
20863f89caaSJens Wiklander 				 prefix, id2str_attr(pkcs11_ref.id), "*",
20963f89caaSJens Wiklander 				 pkcs11_ref.id, pkcs11_ref.size);
21063f89caaSJens Wiklander 			break;
21163f89caaSJens Wiklander 		case 1:
21263f89caaSJens Wiklander 			IMSG_RAW(ATTR_FMT_1BYTE,
21363f89caaSJens Wiklander 				 prefix, id2str_attr(pkcs11_ref.id),
21463f89caaSJens Wiklander 				 id2str_attr_value(pkcs11_ref.id,
21563f89caaSJens Wiklander 						   pkcs11_ref.size,
21663f89caaSJens Wiklander 						   cur + sizeof(pkcs11_ref)),
21763f89caaSJens Wiklander 				 pkcs11_ref.id, pkcs11_ref.size, data[0]);
21863f89caaSJens Wiklander 			break;
21963f89caaSJens Wiklander 		case 2:
22063f89caaSJens Wiklander 			IMSG_RAW(ATTR_FMT_2BYTE,
22163f89caaSJens Wiklander 				 prefix, id2str_attr(pkcs11_ref.id),
22263f89caaSJens Wiklander 				 id2str_attr_value(pkcs11_ref.id,
22363f89caaSJens Wiklander 						   pkcs11_ref.size,
22463f89caaSJens Wiklander 						   cur + sizeof(pkcs11_ref)),
22563f89caaSJens Wiklander 				 pkcs11_ref.id, pkcs11_ref.size, data[0],
22663f89caaSJens Wiklander 				 data[1]);
22763f89caaSJens Wiklander 			break;
22863f89caaSJens Wiklander 		case 3:
22963f89caaSJens Wiklander 			IMSG_RAW(ATTR_FMT_3BYTE,
23063f89caaSJens Wiklander 				 prefix, id2str_attr(pkcs11_ref.id),
23163f89caaSJens Wiklander 				 id2str_attr_value(pkcs11_ref.id,
23263f89caaSJens Wiklander 						   pkcs11_ref.size,
23363f89caaSJens Wiklander 						   cur + sizeof(pkcs11_ref)),
23463f89caaSJens Wiklander 				 pkcs11_ref.id, pkcs11_ref.size,
23563f89caaSJens Wiklander 				 data[0], data[1], data[2]);
23663f89caaSJens Wiklander 			break;
23763f89caaSJens Wiklander 		case 4:
23863f89caaSJens Wiklander 			IMSG_RAW(ATTR_FMT_4BYTE,
23963f89caaSJens Wiklander 				 prefix, id2str_attr(pkcs11_ref.id),
24063f89caaSJens Wiklander 				 id2str_attr_value(pkcs11_ref.id,
24163f89caaSJens Wiklander 						   pkcs11_ref.size,
24263f89caaSJens Wiklander 						   cur + sizeof(pkcs11_ref)),
24363f89caaSJens Wiklander 				 pkcs11_ref.id, pkcs11_ref.size,
24463f89caaSJens Wiklander 				 data[0], data[1], data[2], data[3]);
24563f89caaSJens Wiklander 			break;
24663f89caaSJens Wiklander 		default:
24763f89caaSJens Wiklander 			IMSG_RAW(ATTR_FMT_ARRAY,
24863f89caaSJens Wiklander 				 prefix, id2str_attr(pkcs11_ref.id),
24963f89caaSJens Wiklander 				 id2str_attr_value(pkcs11_ref.id,
25063f89caaSJens Wiklander 						   pkcs11_ref.size,
25163f89caaSJens Wiklander 						   cur + sizeof(pkcs11_ref)),
25263f89caaSJens Wiklander 				 pkcs11_ref.id, pkcs11_ref.size,
25363f89caaSJens Wiklander 				 data[0], data[1], data[2], data[3]);
25463f89caaSJens Wiklander 			break;
25563f89caaSJens Wiklander 		}
25663f89caaSJens Wiklander 
25763f89caaSJens Wiklander 		switch (pkcs11_ref.id) {
25863f89caaSJens Wiklander 		case PKCS11_CKA_WRAP_TEMPLATE:
25963f89caaSJens Wiklander 		case PKCS11_CKA_UNWRAP_TEMPLATE:
26063f89caaSJens Wiklander 		case PKCS11_CKA_DERIVE_TEMPLATE:
261ef5f7584SEtienne Carriere 			if (pkcs11_ref.size)
262ef5f7584SEtienne Carriere 				trace_attributes(prefix2,
263ef5f7584SEtienne Carriere 						 cur + sizeof(pkcs11_ref));
26463f89caaSJens Wiklander 			break;
26563f89caaSJens Wiklander 		default:
26663f89caaSJens Wiklander 			break;
26763f89caaSJens Wiklander 		}
26863f89caaSJens Wiklander 	}
26963f89caaSJens Wiklander 
27063f89caaSJens Wiklander 	/* Sanity */
27163f89caaSJens Wiklander 	if (cur != end)
27263f89caaSJens Wiklander 		EMSG("Warning: unexpected alignment in object attributes");
27363f89caaSJens Wiklander 
27463f89caaSJens Wiklander 	TEE_Free(prefix2);
27563f89caaSJens Wiklander }
27663f89caaSJens Wiklander 
27763f89caaSJens Wiklander void trace_attributes(const char *prefix, void *ref)
27863f89caaSJens Wiklander {
279ef5f7584SEtienne Carriere 	struct obj_attrs head = { };
28063f89caaSJens Wiklander 	char *pre = NULL;
28163f89caaSJens Wiklander 
28263f89caaSJens Wiklander 	TEE_MemMove(&head, ref, sizeof(head));
28363f89caaSJens Wiklander 
284ef5f7584SEtienne Carriere 	if (!head.attrs_count)
285ef5f7584SEtienne Carriere 		return;
286ef5f7584SEtienne Carriere 
28763f89caaSJens Wiklander 	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
28863f89caaSJens Wiklander 	if (!pre) {
28963f89caaSJens Wiklander 		EMSG("%s: out of memory", prefix);
29063f89caaSJens Wiklander 		return;
29163f89caaSJens Wiklander 	}
29263f89caaSJens Wiklander 
29363f89caaSJens Wiklander 	if (prefix)
29463f89caaSJens Wiklander 		TEE_MemMove(pre, prefix, strlen(prefix));
29563f89caaSJens Wiklander 
29663f89caaSJens Wiklander 	IMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
29763f89caaSJens Wiklander 	IMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
29863f89caaSJens Wiklander 		 pre, head.attrs_count, head.attrs_size);
29963f89caaSJens Wiklander 
30063f89caaSJens Wiklander 	pre[prefix ? strlen(prefix) : 0] = '|';
30163f89caaSJens Wiklander 	__trace_attributes(pre, (char *)ref + sizeof(head),
30263f89caaSJens Wiklander 			   (char *)ref + sizeof(head) + head.attrs_size);
30363f89caaSJens Wiklander 
30463f89caaSJens Wiklander 	IMSG_RAW("%s`-----------------------", prefix ? prefix : "");
30563f89caaSJens Wiklander 
30663f89caaSJens Wiklander 	TEE_Free(pre);
30763f89caaSJens Wiklander }
30863f89caaSJens Wiklander #endif /*CFG_TEE_TA_LOG_LEVEL*/
309