xref: /optee_os/ta/pkcs11/src/attributes.c (revision 4bc2a199d122c30f05bcc61e43da128ffabd46fb)
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 <trace.h>
15 #include <util.h>
16 
17 #include "attributes.h"
18 #include "pkcs11_helpers.h"
19 #include "serializer.h"
20 
init_attributes_head(struct obj_attrs ** head)21 enum pkcs11_rc init_attributes_head(struct obj_attrs **head)
22 {
23 	*head = TEE_Malloc(sizeof(**head), TEE_MALLOC_FILL_ZERO);
24 	if (!*head)
25 		return PKCS11_CKR_DEVICE_MEMORY;
26 
27 	return PKCS11_CKR_OK;
28 }
29 
add_attribute(struct obj_attrs ** head,uint32_t attribute,void * data,size_t size)30 enum pkcs11_rc add_attribute(struct obj_attrs **head, uint32_t attribute,
31 			     void *data, size_t size)
32 {
33 	size_t buf_len = sizeof(struct obj_attrs) + (*head)->attrs_size;
34 	char **bstart = (void *)head;
35 	enum pkcs11_rc rc = PKCS11_CKR_OK;
36 	uint32_t data32 = 0;
37 
38 	data32 = attribute;
39 	rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
40 	if (rc)
41 		return rc;
42 
43 	data32 = size;
44 	rc = serialize(bstart, &buf_len, &data32, sizeof(uint32_t));
45 	if (rc)
46 		return rc;
47 
48 	rc = serialize(bstart, &buf_len, data, size);
49 	if (rc)
50 		return rc;
51 
52 	/* Alloced buffer is always well aligned */
53 	head = (void *)bstart;
54 	(*head)->attrs_size += 2 * sizeof(uint32_t) + size;
55 	(*head)->attrs_count++;
56 
57 	return rc;
58 }
59 
_remove_attribute(struct obj_attrs ** head,uint32_t attribute,bool empty)60 static enum pkcs11_rc _remove_attribute(struct obj_attrs **head,
61 					uint32_t attribute, bool empty)
62 {
63 	struct obj_attrs *h = *head;
64 	char *cur = NULL;
65 	char *end = NULL;
66 	size_t next_off = 0;
67 
68 	/* Let's find the target attribute */
69 	cur = (char *)h + sizeof(struct obj_attrs);
70 	end = cur + h->attrs_size;
71 	for (; cur < end; cur += next_off) {
72 		struct pkcs11_attribute_head pkcs11_ref = { };
73 
74 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
75 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
76 
77 		if (pkcs11_ref.id != attribute)
78 			continue;
79 
80 		if (empty && pkcs11_ref.size)
81 			return PKCS11_CKR_FUNCTION_FAILED;
82 
83 		TEE_MemMove(cur, cur + next_off, end - (cur + next_off));
84 
85 		h->attrs_count--;
86 		h->attrs_size -= next_off;
87 		end -= next_off;
88 		next_off = 0;
89 
90 		return PKCS11_CKR_OK;
91 	}
92 
93 	DMSG("Attribute %s (%#x) not found", id2str_attr(attribute), attribute);
94 	return PKCS11_RV_NOT_FOUND;
95 }
96 
remove_empty_attribute(struct obj_attrs ** head,uint32_t attribute)97 enum pkcs11_rc remove_empty_attribute(struct obj_attrs **head,
98 				      uint32_t attribute)
99 {
100 	return _remove_attribute(head, attribute, true /* empty */);
101 }
102 
get_attribute_ptrs(struct obj_attrs * head,uint32_t attribute,void ** attr,uint32_t * attr_size,size_t * count)103 void get_attribute_ptrs(struct obj_attrs *head, uint32_t attribute,
104 			void **attr, uint32_t *attr_size, size_t *count)
105 {
106 	char *cur = (char *)head + sizeof(struct obj_attrs);
107 	char *end = cur + head->attrs_size;
108 	size_t next_off = 0;
109 	size_t max_found = *count;
110 	size_t found = 0;
111 	void **attr_ptr = attr;
112 	uint32_t *attr_size_ptr = attr_size;
113 
114 	for (; cur < end; cur += next_off) {
115 		/* Structure aligned copy of the pkcs11_ref in the object */
116 		struct pkcs11_attribute_head pkcs11_ref = { };
117 
118 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
119 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
120 
121 		if (pkcs11_ref.id != attribute)
122 			continue;
123 
124 		found++;
125 
126 		if (!max_found)
127 			continue;	/* only count matching attributes */
128 
129 		if (attr) {
130 			if (pkcs11_ref.size)
131 				*attr_ptr++ = cur + sizeof(pkcs11_ref);
132 			else
133 				*attr_ptr++ = NULL;
134 		}
135 
136 		if (attr_size)
137 			*attr_size_ptr++ = pkcs11_ref.size;
138 
139 		if (found == max_found)
140 			break;
141 	}
142 
143 	/* Sanity */
144 	if (cur > end) {
145 		DMSG("Exceeding serial object length");
146 		TEE_Panic(0);
147 	}
148 
149 	*count = found;
150 }
151 
get_attribute_ptr(struct obj_attrs * head,uint32_t attribute,void ** attr_ptr,uint32_t * attr_size)152 enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute,
153 				 void **attr_ptr, uint32_t *attr_size)
154 {
155 	size_t count = 1;
156 
157 	get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count);
158 
159 	if (!count)
160 		return PKCS11_RV_NOT_FOUND;
161 
162 	if (count != 1)
163 		return PKCS11_CKR_GENERAL_ERROR;
164 
165 	return PKCS11_CKR_OK;
166 }
167 
get_attribute(struct obj_attrs * head,uint32_t attribute,void * attr,uint32_t * attr_size)168 enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute,
169 			     void *attr, uint32_t *attr_size)
170 {
171 	enum pkcs11_rc rc = PKCS11_CKR_OK;
172 	void *attr_ptr = NULL;
173 	uint32_t size = 0;
174 
175 	rc = get_attribute_ptr(head, attribute, &attr_ptr, &size);
176 	if (rc)
177 		return rc;
178 
179 	if (attr_size && *attr_size < size) {
180 		*attr_size = size;
181 		/* This reuses buffer-to-small for any bad size matching */
182 		return PKCS11_CKR_BUFFER_TOO_SMALL;
183 	}
184 
185 	if (attr)
186 		TEE_MemMove(attr, attr_ptr, size);
187 
188 	if (attr_size)
189 		*attr_size = size;
190 
191 	return PKCS11_CKR_OK;
192 }
193 
set_attribute(struct obj_attrs ** head,uint32_t attribute,void * data,size_t size)194 enum pkcs11_rc set_attribute(struct obj_attrs **head, uint32_t attribute,
195 			     void *data, size_t size)
196 {
197 	enum pkcs11_rc rc = PKCS11_CKR_OK;
198 
199 	rc = _remove_attribute(head, attribute, false);
200 	if (rc != PKCS11_CKR_OK && rc != PKCS11_RV_NOT_FOUND)
201 		return rc;
202 
203 	return add_attribute(head, attribute, data, size);
204 }
205 
modify_attributes_list(struct obj_attrs ** dst,struct obj_attrs * head)206 enum pkcs11_rc modify_attributes_list(struct obj_attrs **dst,
207 				      struct obj_attrs *head)
208 {
209 	char *cur = (char *)head + sizeof(struct obj_attrs);
210 	char *end = cur + head->attrs_size;
211 	size_t len = 0;
212 	enum pkcs11_rc rc = PKCS11_CKR_OK;
213 
214 	for (; cur < end; cur += len) {
215 		struct pkcs11_attribute_head *cli_ref = (void *)cur;
216 		/* Structure aligned copy of the pkcs11_ref in the object */
217 		struct pkcs11_attribute_head cli_head = { };
218 
219 		TEE_MemMove(&cli_head, cur, sizeof(cli_head));
220 		len = sizeof(cli_head) + cli_head.size;
221 
222 		rc = set_attribute(dst, cli_head.id,
223 				   cli_head.size ? cli_ref->data : NULL,
224 				   cli_head.size);
225 		if (rc)
226 			return rc;
227 	}
228 
229 	return PKCS11_CKR_OK;
230 }
231 
get_bool(struct obj_attrs * head,uint32_t attribute)232 bool get_bool(struct obj_attrs *head, uint32_t attribute)
233 {
234 	enum pkcs11_rc rc = PKCS11_CKR_OK;
235 	uint8_t bbool = 0;
236 	uint32_t size = sizeof(bbool);
237 
238 	rc = get_attribute(head, attribute, &bbool, &size);
239 
240 	if (rc == PKCS11_RV_NOT_FOUND)
241 		return false;
242 
243 	assert(rc == PKCS11_CKR_OK);
244 	return bbool;
245 }
246 
attributes_match_reference(struct obj_attrs * candidate,struct obj_attrs * ref)247 bool attributes_match_reference(struct obj_attrs *candidate,
248 				struct obj_attrs *ref)
249 {
250 	size_t count = ref->attrs_count;
251 	unsigned char *ref_attr = ref->attrs;
252 	uint32_t rc = PKCS11_CKR_GENERAL_ERROR;
253 
254 	if (!ref->attrs_count) {
255 		DMSG("Empty reference match all");
256 		return true;
257 	}
258 
259 	for (count = 0; count < ref->attrs_count; count++) {
260 		struct pkcs11_attribute_head pkcs11_ref = { };
261 		void *value = NULL;
262 		uint32_t size = 0;
263 
264 		TEE_MemMove(&pkcs11_ref, ref_attr, sizeof(pkcs11_ref));
265 
266 		/* Hidden attributes cannot be matched */
267 		if (attribute_is_hidden(&pkcs11_ref))
268 			return false;
269 
270 		rc = get_attribute_ptr(candidate, pkcs11_ref.id, &value, &size);
271 
272 		if (rc || !value || size != pkcs11_ref.size ||
273 		    TEE_MemCompare(ref_attr + sizeof(pkcs11_ref), value, size))
274 			return false;
275 
276 		ref_attr += sizeof(pkcs11_ref) + pkcs11_ref.size;
277 	}
278 
279 	return true;
280 }
281 
attributes_match_add_reference(struct obj_attrs ** head,struct obj_attrs * ref)282 enum pkcs11_rc attributes_match_add_reference(struct obj_attrs **head,
283 					      struct obj_attrs *ref)
284 {
285 	size_t count = ref->attrs_count;
286 	unsigned char *ref_attr = ref->attrs;
287 	enum pkcs11_rc rc = PKCS11_CKR_OK;
288 
289 	if (!ref->attrs_count)
290 		return PKCS11_CKR_OK;
291 
292 	for (count = 0; count < ref->attrs_count; count++) {
293 		struct pkcs11_attribute_head pkcs11_ref = { };
294 		void *value = NULL;
295 		uint32_t size = 0;
296 
297 		TEE_MemMove(&pkcs11_ref, ref_attr, sizeof(pkcs11_ref));
298 
299 		rc = get_attribute_ptr(*head, pkcs11_ref.id, &value, &size);
300 		if (rc == PKCS11_RV_NOT_FOUND) {
301 			rc = add_attribute(head, pkcs11_ref.id,
302 					   ref_attr + sizeof(pkcs11_ref),
303 					   pkcs11_ref.size);
304 			if (rc)
305 				return rc;
306 		} else {
307 			if (rc || !value || size != pkcs11_ref.size ||
308 			    TEE_MemCompare(ref_attr + sizeof(pkcs11_ref), value,
309 					   size))
310 				return PKCS11_CKR_TEMPLATE_INCONSISTENT;
311 		}
312 
313 		ref_attr += sizeof(pkcs11_ref) + pkcs11_ref.size;
314 	}
315 
316 	return PKCS11_CKR_OK;
317 }
318 
319 #if CFG_TEE_TA_LOG_LEVEL > 0
320 /*
321  * Debug: dump CK attribute array to output trace
322  */
323 #define ATTR_TRACE_FMT	"%s attr %s / %s\t(0x%04"PRIx32" %"PRIu32"-byte"
324 #define ATTR_FMT_0BYTE	ATTR_TRACE_FMT ")"
325 #define ATTR_FMT_1BYTE	ATTR_TRACE_FMT ": %02x)"
326 #define ATTR_FMT_2BYTE	ATTR_TRACE_FMT ": %02x %02x)"
327 #define ATTR_FMT_3BYTE	ATTR_TRACE_FMT ": %02x %02x %02x)"
328 #define ATTR_FMT_4BYTE	ATTR_TRACE_FMT ": %02x %02x %02x %02x)"
329 #define ATTR_FMT_ARRAY	ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)"
330 
__trace_attributes(char * prefix,void * src,void * end)331 static void __trace_attributes(char *prefix, void *src, void *end)
332 {
333 	size_t next_off = 0;
334 	char *prefix2 = NULL;
335 	size_t prefix_len = strlen(prefix);
336 	char *cur = src;
337 
338 	/* append 4 spaces to the prefix plus terminal '\0' */
339 	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
340 	if (!prefix2)
341 		return;
342 
343 	TEE_MemMove(prefix2, prefix, prefix_len + 1);
344 	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
345 	*(prefix2 + prefix_len + 4) = '\0';
346 
347 	for (; cur < (char *)end; cur += next_off) {
348 		struct pkcs11_attribute_head pkcs11_ref = { };
349 		uint8_t data[4] = { 0 };
350 
351 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
352 		TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
353 			    MIN(pkcs11_ref.size, sizeof(data)));
354 
355 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
356 
357 		switch (pkcs11_ref.size) {
358 		case 0:
359 			IMSG_RAW(ATTR_FMT_0BYTE,
360 				 prefix, id2str_attr(pkcs11_ref.id), "*",
361 				 pkcs11_ref.id, pkcs11_ref.size);
362 			break;
363 		case 1:
364 			IMSG_RAW(ATTR_FMT_1BYTE,
365 				 prefix, id2str_attr(pkcs11_ref.id),
366 				 id2str_attr_value(pkcs11_ref.id,
367 						   pkcs11_ref.size,
368 						   cur + sizeof(pkcs11_ref)),
369 				 pkcs11_ref.id, pkcs11_ref.size, data[0]);
370 			break;
371 		case 2:
372 			IMSG_RAW(ATTR_FMT_2BYTE,
373 				 prefix, id2str_attr(pkcs11_ref.id),
374 				 id2str_attr_value(pkcs11_ref.id,
375 						   pkcs11_ref.size,
376 						   cur + sizeof(pkcs11_ref)),
377 				 pkcs11_ref.id, pkcs11_ref.size, data[0],
378 				 data[1]);
379 			break;
380 		case 3:
381 			IMSG_RAW(ATTR_FMT_3BYTE,
382 				 prefix, id2str_attr(pkcs11_ref.id),
383 				 id2str_attr_value(pkcs11_ref.id,
384 						   pkcs11_ref.size,
385 						   cur + sizeof(pkcs11_ref)),
386 				 pkcs11_ref.id, pkcs11_ref.size,
387 				 data[0], data[1], data[2]);
388 			break;
389 		case 4:
390 			IMSG_RAW(ATTR_FMT_4BYTE,
391 				 prefix, id2str_attr(pkcs11_ref.id),
392 				 id2str_attr_value(pkcs11_ref.id,
393 						   pkcs11_ref.size,
394 						   cur + sizeof(pkcs11_ref)),
395 				 pkcs11_ref.id, pkcs11_ref.size,
396 				 data[0], data[1], data[2], data[3]);
397 			break;
398 		default:
399 			IMSG_RAW(ATTR_FMT_ARRAY,
400 				 prefix, id2str_attr(pkcs11_ref.id),
401 				 id2str_attr_value(pkcs11_ref.id,
402 						   pkcs11_ref.size,
403 						   cur + sizeof(pkcs11_ref)),
404 				 pkcs11_ref.id, pkcs11_ref.size,
405 				 data[0], data[1], data[2], data[3]);
406 			break;
407 		}
408 
409 		switch (pkcs11_ref.id) {
410 		case PKCS11_CKA_WRAP_TEMPLATE:
411 		case PKCS11_CKA_UNWRAP_TEMPLATE:
412 		case PKCS11_CKA_DERIVE_TEMPLATE:
413 			if (pkcs11_ref.size)
414 				trace_attributes(prefix2,
415 						 cur + sizeof(pkcs11_ref));
416 			break;
417 		default:
418 			break;
419 		}
420 	}
421 
422 	/* Sanity */
423 	if (cur != end)
424 		EMSG("Warning: unexpected alignment in object attributes");
425 
426 	TEE_Free(prefix2);
427 }
428 
trace_attributes(const char * prefix,void * ref)429 void trace_attributes(const char *prefix, void *ref)
430 {
431 	struct obj_attrs head = { };
432 	char *pre = NULL;
433 
434 	TEE_MemMove(&head, ref, sizeof(head));
435 
436 	if (!head.attrs_count)
437 		return;
438 
439 	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
440 	if (!pre) {
441 		EMSG("%s: out of memory", prefix);
442 		return;
443 	}
444 
445 	if (prefix)
446 		TEE_MemMove(pre, prefix, strlen(prefix));
447 
448 	IMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
449 	IMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
450 		 pre, head.attrs_count, head.attrs_size);
451 
452 	pre[prefix ? strlen(prefix) : 0] = '|';
453 	__trace_attributes(pre, (char *)ref + sizeof(head),
454 			   (char *)ref + sizeof(head) + head.attrs_size);
455 
456 	IMSG_RAW("%s`-----------------------", prefix ? prefix : "");
457 
458 	TEE_Free(pre);
459 }
460 #endif /*CFG_TEE_TA_LOG_LEVEL*/
461