xref: /optee_os/ta/pkcs11/src/attributes.c (revision a1d5c81f8834a9d2c6f4372cce2e59e70e709121)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2017-2020, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <compiler.h>
8 #include <pkcs11_ta.h>
9 #include <stddef.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <string_ext.h>
13 #include <tee_internal_api.h>
14 #include <tee_internal_api_extensions.h>
15 #include <trace.h>
16 #include <util.h>
17 
18 #include "attributes.h"
19 #include "pkcs11_helpers.h"
20 #include "serializer.h"
21 
22 enum pkcs11_rc init_attributes_head(struct obj_attrs **head)
23 {
24 	*head = TEE_Malloc(sizeof(**head), TEE_MALLOC_FILL_ZERO);
25 	if (!*head)
26 		return PKCS11_CKR_DEVICE_MEMORY;
27 
28 	return PKCS11_CKR_OK;
29 }
30 
31 enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute,
32 			     void *data, size_t size)
33 {
34 	size_t buf_len = sizeof(struct obj_attrs) + (*head)->attrs_size;
35 	char **bstart = (void *)head;
36 	enum pkcs11_rc rc = PKCS11_CKR_OK;
37 	uint32_t data32 = 0;
38 
39 	data32 = attribute;
40 	rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
41 	if (rc)
42 		return rc;
43 
44 	data32 = size;
45 	rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
46 	if (rc)
47 		return rc;
48 
49 	rc = serialize(bstart, &buf_len, data, size);
50 	if (rc)
51 		return rc;
52 
53 	/* Alloced buffer is always well aligned */
54 	head = (void *)bstart;
55 	(*head)->attrs_size += 2 * sizeof(uint32_t) + size;
56 	(*head)->attrs_count++;
57 
58 	return rc;
59 }
60 
61 void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute,
62 			void **attr, uint32_t *attr_size, size_t *count)
63 {
64 	char *cur = (char *)head + sizeof(struct obj_attrs);
65 	char *end = cur + head->attrs_size;
66 	size_t next_off = 0;
67 	size_t max_found = *count;
68 	size_t found = 0;
69 	void **attr_ptr = attr;
70 	uint32_t *attr_size_ptr = attr_size;
71 
72 	for (; cur < end; cur += next_off) {
73 		/* Structure aligned copy of the pkcs11_ref in the object */
74 		struct pkcs11_attribute_head pkcs11_ref = { };
75 
76 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
77 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
78 
79 		if (pkcs11_ref.id != attribute)
80 			continue;
81 
82 		found++;
83 
84 		if (!max_found)
85 			continue;	/* only count matching attributes */
86 
87 		if (attr) {
88 			if (pkcs11_ref.size)
89 				*attr_ptr++ = cur + sizeof(pkcs11_ref);
90 			else
91 				*attr_ptr++ = NULL;
92 		}
93 
94 		if (attr_size)
95 			*attr_size_ptr++ = pkcs11_ref.size;
96 
97 		if (found == max_found)
98 			break;
99 	}
100 
101 	/* Sanity */
102 	if (cur > end) {
103 		DMSG("Exceeding serial object length");
104 		TEE_Panic(0);
105 	}
106 
107 	*count = found;
108 }
109 
110 enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute,
111 				 void **attr_ptr, uint32_t *attr_size)
112 {
113 	size_t count = 1;
114 
115 	get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count);
116 
117 	if (!count)
118 		return PKCS11_RV_NOT_FOUND;
119 
120 	if (count != 1)
121 		return PKCS11_CKR_GENERAL_ERROR;
122 
123 	return PKCS11_CKR_OK;
124 }
125 
126 enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute,
127 			     void *attr, uint32_t *attr_size)
128 {
129 	enum pkcs11_rc rc = PKCS11_CKR_OK;
130 	void *attr_ptr = NULL;
131 	uint32_t size = 0;
132 
133 	rc = get_attribute_ptr(head, attribute, &attr_ptr, &size);
134 	if (rc)
135 		return rc;
136 
137 	if (attr_size && *attr_size != size) {
138 		*attr_size = size;
139 		/* This reuses buffer-to-small for any bad size matching */
140 		return PKCS11_CKR_BUFFER_TOO_SMALL;
141 	}
142 
143 	if (attr)
144 		TEE_MemMove(attr, attr_ptr, size);
145 
146 	if (attr_size)
147 		*attr_size = size;
148 
149 	return PKCS11_CKR_OK;
150 }
151 
152 bool get_bool(struct obj_attrs *head, uint32_t attribute)
153 {
154 	enum pkcs11_rc rc = PKCS11_CKR_OK;
155 	uint8_t bbool = 0;
156 	uint32_t size = sizeof(bbool);
157 
158 	rc = get_attribute(head, attribute, &bbool, &size);
159 
160 	if (rc == PKCS11_RV_NOT_FOUND)
161 		return false;
162 
163 	assert(rc == PKCS11_CKR_OK);
164 	return bbool;
165 }
166 
167 #if CFG_TEE_TA_LOG_LEVEL > 0
168 /*
169  * Debug: dump CK attribute array to output trace
170  */
171 #define ATTR_TRACE_FMT	"%s attr %s / %s\t(0x%04"PRIx32" %"PRIu32"-byte"
172 #define ATTR_FMT_0BYTE	ATTR_TRACE_FMT ")"
173 #define ATTR_FMT_1BYTE	ATTR_TRACE_FMT ": %02x)"
174 #define ATTR_FMT_2BYTE	ATTR_TRACE_FMT ": %02x %02x)"
175 #define ATTR_FMT_3BYTE	ATTR_TRACE_FMT ": %02x %02x %02x)"
176 #define ATTR_FMT_4BYTE	ATTR_TRACE_FMT ": %02x %02x %02x %02x)"
177 #define ATTR_FMT_ARRAY	ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)"
178 
179 static void __trace_attributes(char *prefix, void *src, void *end)
180 {
181 	size_t next_off = 0;
182 	char *prefix2 = NULL;
183 	size_t prefix_len = strlen(prefix);
184 	char *cur = src;
185 
186 	/* append 4 spaces to the prefix plus terminal '\0' */
187 	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
188 	if (!prefix2)
189 		return;
190 
191 	TEE_MemMove(prefix2, prefix, prefix_len + 1);
192 	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
193 	*(prefix2 + prefix_len + 4) = '\0';
194 
195 	for (; cur < (char *)end; cur += next_off) {
196 		struct pkcs11_attribute_head pkcs11_ref = { };
197 		uint8_t data[4] = { 0 };
198 
199 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
200 		TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
201 			    MIN(pkcs11_ref.size, sizeof(data)));
202 
203 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
204 
205 		switch (pkcs11_ref.size) {
206 		case 0:
207 			IMSG_RAW(ATTR_FMT_0BYTE,
208 				 prefix, id2str_attr(pkcs11_ref.id), "*",
209 				 pkcs11_ref.id, pkcs11_ref.size);
210 			break;
211 		case 1:
212 			IMSG_RAW(ATTR_FMT_1BYTE,
213 				 prefix, id2str_attr(pkcs11_ref.id),
214 				 id2str_attr_value(pkcs11_ref.id,
215 						   pkcs11_ref.size,
216 						   cur + sizeof(pkcs11_ref)),
217 				 pkcs11_ref.id, pkcs11_ref.size, data[0]);
218 			break;
219 		case 2:
220 			IMSG_RAW(ATTR_FMT_2BYTE,
221 				 prefix, id2str_attr(pkcs11_ref.id),
222 				 id2str_attr_value(pkcs11_ref.id,
223 						   pkcs11_ref.size,
224 						   cur + sizeof(pkcs11_ref)),
225 				 pkcs11_ref.id, pkcs11_ref.size, data[0],
226 				 data[1]);
227 			break;
228 		case 3:
229 			IMSG_RAW(ATTR_FMT_3BYTE,
230 				 prefix, id2str_attr(pkcs11_ref.id),
231 				 id2str_attr_value(pkcs11_ref.id,
232 						   pkcs11_ref.size,
233 						   cur + sizeof(pkcs11_ref)),
234 				 pkcs11_ref.id, pkcs11_ref.size,
235 				 data[0], data[1], data[2]);
236 			break;
237 		case 4:
238 			IMSG_RAW(ATTR_FMT_4BYTE,
239 				 prefix, id2str_attr(pkcs11_ref.id),
240 				 id2str_attr_value(pkcs11_ref.id,
241 						   pkcs11_ref.size,
242 						   cur + sizeof(pkcs11_ref)),
243 				 pkcs11_ref.id, pkcs11_ref.size,
244 				 data[0], data[1], data[2], data[3]);
245 			break;
246 		default:
247 			IMSG_RAW(ATTR_FMT_ARRAY,
248 				 prefix, id2str_attr(pkcs11_ref.id),
249 				 id2str_attr_value(pkcs11_ref.id,
250 						   pkcs11_ref.size,
251 						   cur + sizeof(pkcs11_ref)),
252 				 pkcs11_ref.id, pkcs11_ref.size,
253 				 data[0], data[1], data[2], data[3]);
254 			break;
255 		}
256 
257 		switch (pkcs11_ref.id) {
258 		case PKCS11_CKA_WRAP_TEMPLATE:
259 		case PKCS11_CKA_UNWRAP_TEMPLATE:
260 		case PKCS11_CKA_DERIVE_TEMPLATE:
261 			if (pkcs11_ref.size)
262 				trace_attributes(prefix2,
263 						 cur + sizeof(pkcs11_ref));
264 			break;
265 		default:
266 			break;
267 		}
268 	}
269 
270 	/* Sanity */
271 	if (cur != end)
272 		EMSG("Warning: unexpected alignment in object attributes");
273 
274 	TEE_Free(prefix2);
275 }
276 
277 void trace_attributes(const char *prefix, void *ref)
278 {
279 	struct obj_attrs head = { };
280 	char *pre = NULL;
281 
282 	TEE_MemMove(&head, ref, sizeof(head));
283 
284 	if (!head.attrs_count)
285 		return;
286 
287 	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
288 	if (!pre) {
289 		EMSG("%s: out of memory", prefix);
290 		return;
291 	}
292 
293 	if (prefix)
294 		TEE_MemMove(pre, prefix, strlen(prefix));
295 
296 	IMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
297 	IMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
298 		 pre, head.attrs_count, head.attrs_size);
299 
300 	pre[prefix ? strlen(prefix) : 0] = '|';
301 	__trace_attributes(pre, (char *)ref + sizeof(head),
302 			   (char *)ref + sizeof(head) + head.attrs_size);
303 
304 	IMSG_RAW("%s`-----------------------", prefix ? prefix : "");
305 
306 	TEE_Free(pre);
307 }
308 #endif /*CFG_TEE_TA_LOG_LEVEL*/
309