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