xref: /optee_os/ta/pkcs11/src/attributes.c (revision f86aa9e1925ef129e92324b3d5e1d4c7f0a03e87)
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 			*attr_ptr++ = cur + sizeof(pkcs11_ref);
89 
90 		if (attr_size)
91 			*attr_size_ptr++ = pkcs11_ref.size;
92 
93 		if (found == max_found)
94 			break;
95 	}
96 
97 	/* Sanity */
98 	if (cur > end) {
99 		DMSG("Exceeding serial object length");
100 		TEE_Panic(0);
101 	}
102 
103 	*count = found;
104 }
105 
106 enum pkcs11_rc get_attribute_ptr(struct obj_attrs *head, uint32_t attribute,
107 				 void **attr_ptr, uint32_t *attr_size)
108 {
109 	size_t count = 1;
110 
111 	get_attribute_ptrs(head, attribute, attr_ptr, attr_size, &count);
112 
113 	if (!count)
114 		return PKCS11_RV_NOT_FOUND;
115 
116 	if (count != 1)
117 		return PKCS11_CKR_GENERAL_ERROR;
118 
119 	return PKCS11_CKR_OK;
120 }
121 
122 enum pkcs11_rc get_attribute(struct obj_attrs *head, uint32_t attribute,
123 			     void *attr, uint32_t *attr_size)
124 {
125 	enum pkcs11_rc rc = PKCS11_CKR_OK;
126 	void *attr_ptr = NULL;
127 	uint32_t size = 0;
128 
129 	rc = get_attribute_ptr(head, attribute, &attr_ptr, &size);
130 	if (rc)
131 		return rc;
132 
133 	if (attr_size && *attr_size != size) {
134 		*attr_size = size;
135 		/* This reuses buffer-to-small for any bad size matching */
136 		return PKCS11_CKR_BUFFER_TOO_SMALL;
137 	}
138 
139 	if (attr)
140 		TEE_MemMove(attr, attr_ptr, size);
141 
142 	if (attr_size)
143 		*attr_size = size;
144 
145 	return PKCS11_CKR_OK;
146 }
147 
148 bool get_bool(struct obj_attrs *head, uint32_t attribute)
149 {
150 	enum pkcs11_rc rc = PKCS11_CKR_OK;
151 	uint8_t bbool = 0;
152 	uint32_t size = sizeof(bbool);
153 
154 	rc = get_attribute(head, attribute, &bbool, &size);
155 
156 	if (rc == PKCS11_RV_NOT_FOUND)
157 		return false;
158 
159 	assert(rc == PKCS11_CKR_OK);
160 	return bbool;
161 }
162 
163 #if CFG_TEE_TA_LOG_LEVEL > 0
164 /*
165  * Debug: dump CK attribute array to output trace
166  */
167 #define ATTR_TRACE_FMT	"%s attr %s / %s\t(0x%04"PRIx32" %"PRIu32"-byte"
168 #define ATTR_FMT_0BYTE	ATTR_TRACE_FMT ")"
169 #define ATTR_FMT_1BYTE	ATTR_TRACE_FMT ": %02x)"
170 #define ATTR_FMT_2BYTE	ATTR_TRACE_FMT ": %02x %02x)"
171 #define ATTR_FMT_3BYTE	ATTR_TRACE_FMT ": %02x %02x %02x)"
172 #define ATTR_FMT_4BYTE	ATTR_TRACE_FMT ": %02x %02x %02x %02x)"
173 #define ATTR_FMT_ARRAY	ATTR_TRACE_FMT ": %02x %02x %02x %02x ...)"
174 
175 static void __trace_attributes(char *prefix, void *src, void *end)
176 {
177 	size_t next_off = 0;
178 	char *prefix2 = NULL;
179 	size_t prefix_len = strlen(prefix);
180 	char *cur = src;
181 
182 	/* append 4 spaces to the prefix plus terminal '\0' */
183 	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
184 	if (!prefix2)
185 		return;
186 
187 	TEE_MemMove(prefix2, prefix, prefix_len + 1);
188 	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
189 	*(prefix2 + prefix_len + 4) = '\0';
190 
191 	for (; cur < (char *)end; cur += next_off) {
192 		struct pkcs11_attribute_head pkcs11_ref = { };
193 		uint8_t data[4] = { 0 };
194 
195 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
196 		TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
197 			    MIN(pkcs11_ref.size, sizeof(data)));
198 
199 		next_off = sizeof(pkcs11_ref) + pkcs11_ref.size;
200 
201 		switch (pkcs11_ref.size) {
202 		case 0:
203 			IMSG_RAW(ATTR_FMT_0BYTE,
204 				 prefix, id2str_attr(pkcs11_ref.id), "*",
205 				 pkcs11_ref.id, pkcs11_ref.size);
206 			break;
207 		case 1:
208 			IMSG_RAW(ATTR_FMT_1BYTE,
209 				 prefix, id2str_attr(pkcs11_ref.id),
210 				 id2str_attr_value(pkcs11_ref.id,
211 						   pkcs11_ref.size,
212 						   cur + sizeof(pkcs11_ref)),
213 				 pkcs11_ref.id, pkcs11_ref.size, data[0]);
214 			break;
215 		case 2:
216 			IMSG_RAW(ATTR_FMT_2BYTE,
217 				 prefix, id2str_attr(pkcs11_ref.id),
218 				 id2str_attr_value(pkcs11_ref.id,
219 						   pkcs11_ref.size,
220 						   cur + sizeof(pkcs11_ref)),
221 				 pkcs11_ref.id, pkcs11_ref.size, data[0],
222 				 data[1]);
223 			break;
224 		case 3:
225 			IMSG_RAW(ATTR_FMT_3BYTE,
226 				 prefix, id2str_attr(pkcs11_ref.id),
227 				 id2str_attr_value(pkcs11_ref.id,
228 						   pkcs11_ref.size,
229 						   cur + sizeof(pkcs11_ref)),
230 				 pkcs11_ref.id, pkcs11_ref.size,
231 				 data[0], data[1], data[2]);
232 			break;
233 		case 4:
234 			IMSG_RAW(ATTR_FMT_4BYTE,
235 				 prefix, id2str_attr(pkcs11_ref.id),
236 				 id2str_attr_value(pkcs11_ref.id,
237 						   pkcs11_ref.size,
238 						   cur + sizeof(pkcs11_ref)),
239 				 pkcs11_ref.id, pkcs11_ref.size,
240 				 data[0], data[1], data[2], data[3]);
241 			break;
242 		default:
243 			IMSG_RAW(ATTR_FMT_ARRAY,
244 				 prefix, id2str_attr(pkcs11_ref.id),
245 				 id2str_attr_value(pkcs11_ref.id,
246 						   pkcs11_ref.size,
247 						   cur + sizeof(pkcs11_ref)),
248 				 pkcs11_ref.id, pkcs11_ref.size,
249 				 data[0], data[1], data[2], data[3]);
250 			break;
251 		}
252 
253 		switch (pkcs11_ref.id) {
254 		case PKCS11_CKA_WRAP_TEMPLATE:
255 		case PKCS11_CKA_UNWRAP_TEMPLATE:
256 		case PKCS11_CKA_DERIVE_TEMPLATE:
257 			trace_attributes(prefix2, cur + sizeof(pkcs11_ref));
258 			break;
259 		default:
260 			break;
261 		}
262 	}
263 
264 	/* Sanity */
265 	if (cur != end)
266 		EMSG("Warning: unexpected alignment in object attributes");
267 
268 	TEE_Free(prefix2);
269 }
270 
271 void trace_attributes(const char *prefix, void *ref)
272 {
273 	struct obj_attrs head;
274 	char *pre = NULL;
275 
276 	TEE_MemMove(&head, ref, sizeof(head));
277 
278 	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
279 	if (!pre) {
280 		EMSG("%s: out of memory", prefix);
281 		return;
282 	}
283 
284 	if (prefix)
285 		TEE_MemMove(pre, prefix, strlen(prefix));
286 
287 	IMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
288 	IMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
289 		 pre, head.attrs_count, head.attrs_size);
290 
291 	pre[prefix ? strlen(prefix) : 0] = '|';
292 	__trace_attributes(pre, (char *)ref + sizeof(head),
293 			   (char *)ref + sizeof(head) + head.attrs_size);
294 
295 	IMSG_RAW("%s`-----------------------", prefix ? prefix : "");
296 
297 	TEE_Free(pre);
298 }
299 #endif /*CFG_TEE_TA_LOG_LEVEL*/
300