xref: /optee_os/ta/pkcs11/src/sanitize_object.c (revision 63f89caa9022ecf51d1b82dc78af35ba9e38466d)
1*63f89caaSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
2*63f89caaSJens Wiklander /*
3*63f89caaSJens Wiklander  * Copyright (c) 2017-2020, Linaro Limited
4*63f89caaSJens Wiklander  */
5*63f89caaSJens Wiklander 
6*63f89caaSJens Wiklander #include <bitstring.h>
7*63f89caaSJens Wiklander #include <pkcs11_ta.h>
8*63f89caaSJens Wiklander #include <stdlib.h>
9*63f89caaSJens Wiklander #include <string.h>
10*63f89caaSJens Wiklander #include <util.h>
11*63f89caaSJens Wiklander #include <tee_internal_api.h>
12*63f89caaSJens Wiklander #include <tee_internal_api_extensions.h>
13*63f89caaSJens Wiklander #include <trace.h>
14*63f89caaSJens Wiklander 
15*63f89caaSJens Wiklander #include "attributes.h"
16*63f89caaSJens Wiklander #include "pkcs11_helpers.h"
17*63f89caaSJens Wiklander #include "sanitize_object.h"
18*63f89caaSJens Wiklander #include "serializer.h"
19*63f89caaSJens Wiklander #include "token_capabilities.h"
20*63f89caaSJens Wiklander 
21*63f89caaSJens Wiklander /*
22*63f89caaSJens Wiklander  * Functions to generate a serialized object.
23*63f89caaSJens Wiklander  * References are pointers to struct serializer.
24*63f89caaSJens Wiklander  */
25*63f89caaSJens Wiklander 
26*63f89caaSJens Wiklander bool sanitize_consistent_class_and_type(struct obj_attrs *attrs)
27*63f89caaSJens Wiklander {
28*63f89caaSJens Wiklander 	switch (get_class(attrs)) {
29*63f89caaSJens Wiklander 	case PKCS11_CKO_DATA:
30*63f89caaSJens Wiklander 		return true;
31*63f89caaSJens Wiklander 	case PKCS11_CKO_SECRET_KEY:
32*63f89caaSJens Wiklander 		return key_type_is_symm_key(get_key_type(attrs));
33*63f89caaSJens Wiklander 	case PKCS11_CKO_MECHANISM:
34*63f89caaSJens Wiklander 		return mechanism_is_valid(get_mechanism_type(attrs));
35*63f89caaSJens Wiklander 	case PKCS11_CKO_PUBLIC_KEY:
36*63f89caaSJens Wiklander 	case PKCS11_CKO_PRIVATE_KEY:
37*63f89caaSJens Wiklander 		return key_type_is_asymm_key(get_key_type(attrs));
38*63f89caaSJens Wiklander 	case PKCS11_CKO_OTP_KEY:
39*63f89caaSJens Wiklander 	case PKCS11_CKO_CERTIFICATE:
40*63f89caaSJens Wiklander 	case PKCS11_CKO_DOMAIN_PARAMETERS:
41*63f89caaSJens Wiklander 	case PKCS11_CKO_HW_FEATURE:
42*63f89caaSJens Wiklander 	default:
43*63f89caaSJens Wiklander 		return false;
44*63f89caaSJens Wiklander 	}
45*63f89caaSJens Wiklander 
46*63f89caaSJens Wiklander 	return false;
47*63f89caaSJens Wiklander }
48*63f89caaSJens Wiklander 
49*63f89caaSJens Wiklander static enum pkcs11_rc read_attr_advance(void *buf, size_t blen, size_t *pos,
50*63f89caaSJens Wiklander 					struct pkcs11_attribute_head *attr,
51*63f89caaSJens Wiklander 					void **data)
52*63f89caaSJens Wiklander {
53*63f89caaSJens Wiklander 	uint8_t *b = buf;
54*63f89caaSJens Wiklander 	size_t data_pos = 0;
55*63f89caaSJens Wiklander 	size_t next_pos = 0;
56*63f89caaSJens Wiklander 
57*63f89caaSJens Wiklander 	if (ADD_OVERFLOW(*pos, sizeof(*attr), &data_pos) || data_pos > blen)
58*63f89caaSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
59*63f89caaSJens Wiklander 	TEE_MemMove(attr, b + *pos, sizeof(*attr));
60*63f89caaSJens Wiklander 
61*63f89caaSJens Wiklander 	if (ADD_OVERFLOW(data_pos, attr->size, &next_pos) || next_pos > blen)
62*63f89caaSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
63*63f89caaSJens Wiklander 
64*63f89caaSJens Wiklander 	*data = b + data_pos;
65*63f89caaSJens Wiklander 	*pos = next_pos;
66*63f89caaSJens Wiklander 
67*63f89caaSJens Wiklander 	return PKCS11_CKR_OK;
68*63f89caaSJens Wiklander }
69*63f89caaSJens Wiklander 
70*63f89caaSJens Wiklander /* Sanitize class/type in a client attribute list */
71*63f89caaSJens Wiklander static enum pkcs11_rc sanitize_class_and_type(struct obj_attrs **dst, void *src,
72*63f89caaSJens Wiklander 					      size_t src_size)
73*63f89caaSJens Wiklander {
74*63f89caaSJens Wiklander 	uint32_t class_found = PKCS11_CKO_UNDEFINED_ID;
75*63f89caaSJens Wiklander 	size_t pos = sizeof(struct pkcs11_object_head);
76*63f89caaSJens Wiklander 	struct pkcs11_attribute_head cli_ref = { };
77*63f89caaSJens Wiklander 	uint32_t type_found = PKCS11_UNDEFINED_ID;
78*63f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
79*63f89caaSJens Wiklander 	void *data = NULL;
80*63f89caaSJens Wiklander 
81*63f89caaSJens Wiklander 	while (pos != src_size) {
82*63f89caaSJens Wiklander 		rc = read_attr_advance(src, src_size, &pos, &cli_ref, &data);
83*63f89caaSJens Wiklander 		if (rc)
84*63f89caaSJens Wiklander 			goto err;
85*63f89caaSJens Wiklander 
86*63f89caaSJens Wiklander 		if (cli_ref.id == PKCS11_CKA_CLASS) {
87*63f89caaSJens Wiklander 			uint32_t class = 0;
88*63f89caaSJens Wiklander 
89*63f89caaSJens Wiklander 			if (cli_ref.size != sizeof(class)) {
90*63f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
91*63f89caaSJens Wiklander 				goto err;
92*63f89caaSJens Wiklander 			}
93*63f89caaSJens Wiklander 
94*63f89caaSJens Wiklander 			TEE_MemMove(&class, data, sizeof(class));
95*63f89caaSJens Wiklander 
96*63f89caaSJens Wiklander 			if (class_found != PKCS11_CKO_UNDEFINED_ID &&
97*63f89caaSJens Wiklander 			    class_found != class) {
98*63f89caaSJens Wiklander 				EMSG("Conflicting class value");
99*63f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
100*63f89caaSJens Wiklander 				goto err;
101*63f89caaSJens Wiklander 			}
102*63f89caaSJens Wiklander 
103*63f89caaSJens Wiklander 			class_found = class;
104*63f89caaSJens Wiklander 			continue;
105*63f89caaSJens Wiklander 		}
106*63f89caaSJens Wiklander 
107*63f89caaSJens Wiklander 		/* The attribute is a type-in-class */
108*63f89caaSJens Wiklander 		if (pkcs11_attr_is_type(cli_ref.id)) {
109*63f89caaSJens Wiklander 			uint32_t type = 0;
110*63f89caaSJens Wiklander 
111*63f89caaSJens Wiklander 			if (cli_ref.size != sizeof(type)) {
112*63f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
113*63f89caaSJens Wiklander 				goto err;
114*63f89caaSJens Wiklander 			}
115*63f89caaSJens Wiklander 
116*63f89caaSJens Wiklander 			TEE_MemMove(&type, data, sizeof(type));
117*63f89caaSJens Wiklander 
118*63f89caaSJens Wiklander 			if (type_found != PKCS11_CKK_UNDEFINED_ID &&
119*63f89caaSJens Wiklander 			    type_found != type) {
120*63f89caaSJens Wiklander 				EMSG("Conflicting type-in-class value");
121*63f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
122*63f89caaSJens Wiklander 				goto err;
123*63f89caaSJens Wiklander 			}
124*63f89caaSJens Wiklander 
125*63f89caaSJens Wiklander 			type_found = type;
126*63f89caaSJens Wiklander 		}
127*63f89caaSJens Wiklander 	}
128*63f89caaSJens Wiklander 
129*63f89caaSJens Wiklander 	if (class_found != PKCS11_CKO_UNDEFINED_ID) {
130*63f89caaSJens Wiklander 		rc = add_attribute(dst, PKCS11_CKA_CLASS,
131*63f89caaSJens Wiklander 				   &class_found, sizeof(class_found));
132*63f89caaSJens Wiklander 		if (rc)
133*63f89caaSJens Wiklander 			return rc;
134*63f89caaSJens Wiklander 	}
135*63f89caaSJens Wiklander 
136*63f89caaSJens Wiklander 	if (type_found != PKCS11_UNDEFINED_ID) {
137*63f89caaSJens Wiklander 		rc = add_attribute(dst, PKCS11_CKA_KEY_TYPE,
138*63f89caaSJens Wiklander 				   &type_found, sizeof(type_found));
139*63f89caaSJens Wiklander 		if (rc)
140*63f89caaSJens Wiklander 			return rc;
141*63f89caaSJens Wiklander 	}
142*63f89caaSJens Wiklander 
143*63f89caaSJens Wiklander 	return PKCS11_CKR_OK;
144*63f89caaSJens Wiklander 
145*63f89caaSJens Wiklander err:
146*63f89caaSJens Wiklander 	trace_attributes_from_api_head("bad-template", src, src_size);
147*63f89caaSJens Wiklander 
148*63f89caaSJens Wiklander 	return rc;
149*63f89caaSJens Wiklander }
150*63f89caaSJens Wiklander 
151*63f89caaSJens Wiklander static enum pkcs11_rc sanitize_boolprops(struct obj_attrs **dst, void *src,
152*63f89caaSJens Wiklander 					 size_t src_size)
153*63f89caaSJens Wiklander {
154*63f89caaSJens Wiklander 	bitstr_t bit_decl(seen_attrs, PKCS11_BOOLPROPS_MAX_COUNT) = { 0 };
155*63f89caaSJens Wiklander 	bitstr_t bit_decl(boolprops, PKCS11_BOOLPROPS_MAX_COUNT) = { 0 };
156*63f89caaSJens Wiklander 	size_t pos = sizeof(struct pkcs11_object_head);
157*63f89caaSJens Wiklander 	struct pkcs11_attribute_head cli_ref = { };
158*63f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
159*63f89caaSJens Wiklander 	bool value = false;
160*63f89caaSJens Wiklander 	void *data = NULL;
161*63f89caaSJens Wiklander 	int idx = 0;
162*63f89caaSJens Wiklander 
163*63f89caaSJens Wiklander 	/*
164*63f89caaSJens Wiklander 	 * We're keeping track of seen boolean attributes in the bitstring
165*63f89caaSJens Wiklander 	 * seen_attrs. The bitstring boolprops holds the recorded value
166*63f89caaSJens Wiklander 	 * once seen_attrs has been updated.
167*63f89caaSJens Wiklander 	 */
168*63f89caaSJens Wiklander 
169*63f89caaSJens Wiklander 	while (pos != src_size) {
170*63f89caaSJens Wiklander 		rc = read_attr_advance(src, src_size, &pos, &cli_ref, &data);
171*63f89caaSJens Wiklander 		if (rc)
172*63f89caaSJens Wiklander 			return rc;
173*63f89caaSJens Wiklander 
174*63f89caaSJens Wiklander 		idx = pkcs11_attr2boolprop_shift(cli_ref.id);
175*63f89caaSJens Wiklander 		if (idx < 0)
176*63f89caaSJens Wiklander 			continue; /* skipping non-boolean attributes */
177*63f89caaSJens Wiklander 
178*63f89caaSJens Wiklander 		if (idx >= PKCS11_BOOLPROPS_MAX_COUNT ||
179*63f89caaSJens Wiklander 		    cli_ref.size != sizeof(uint8_t))
180*63f89caaSJens Wiklander 			return PKCS11_CKR_FUNCTION_FAILED;
181*63f89caaSJens Wiklander 
182*63f89caaSJens Wiklander 		value = *(uint8_t *)data;
183*63f89caaSJens Wiklander 
184*63f89caaSJens Wiklander 		/*
185*63f89caaSJens Wiklander 		 * If this attribute has already been seen, check that it
186*63f89caaSJens Wiklander 		 * still holds the same value as last time.
187*63f89caaSJens Wiklander 		 */
188*63f89caaSJens Wiklander 		if (bit_test(seen_attrs, idx) &&
189*63f89caaSJens Wiklander 		    value != (bool)bit_test(boolprops, idx))
190*63f89caaSJens Wiklander 			return PKCS11_CKR_TEMPLATE_INCONSISTENT;
191*63f89caaSJens Wiklander 
192*63f89caaSJens Wiklander 		if (value)
193*63f89caaSJens Wiklander 			bit_set(boolprops, idx);
194*63f89caaSJens Wiklander 
195*63f89caaSJens Wiklander 		if (!bit_test(seen_attrs, idx)) {
196*63f89caaSJens Wiklander 			uint8_t pkcs11_bool = value;
197*63f89caaSJens Wiklander 
198*63f89caaSJens Wiklander 			rc = add_attribute(dst, cli_ref.id, &pkcs11_bool,
199*63f89caaSJens Wiklander 					   sizeof(pkcs11_bool));
200*63f89caaSJens Wiklander 			if (rc)
201*63f89caaSJens Wiklander 				return rc;
202*63f89caaSJens Wiklander 		}
203*63f89caaSJens Wiklander 		bit_set(seen_attrs, idx);
204*63f89caaSJens Wiklander 	}
205*63f89caaSJens Wiklander 
206*63f89caaSJens Wiklander 	return PKCS11_CKR_OK;
207*63f89caaSJens Wiklander }
208*63f89caaSJens Wiklander 
209*63f89caaSJens Wiklander static uint32_t sanitize_indirect_attr(struct obj_attrs **dst,
210*63f89caaSJens Wiklander 				       struct pkcs11_attribute_head *cli_ref,
211*63f89caaSJens Wiklander 				       char *data)
212*63f89caaSJens Wiklander {
213*63f89caaSJens Wiklander 	struct obj_attrs *obj2 = NULL;
214*63f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
215*63f89caaSJens Wiklander 	enum pkcs11_class_id class = get_class(*dst);
216*63f89caaSJens Wiklander 
217*63f89caaSJens Wiklander 	if (class == PKCS11_CKO_UNDEFINED_ID)
218*63f89caaSJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
219*63f89caaSJens Wiklander 
220*63f89caaSJens Wiklander 	/*
221*63f89caaSJens Wiklander 	 * Serialized attributes: current applicable only to the key
222*63f89caaSJens Wiklander 	 * templates which are tables of attributes.
223*63f89caaSJens Wiklander 	 */
224*63f89caaSJens Wiklander 	switch (cli_ref->id) {
225*63f89caaSJens Wiklander 	case PKCS11_CKA_WRAP_TEMPLATE:
226*63f89caaSJens Wiklander 	case PKCS11_CKA_UNWRAP_TEMPLATE:
227*63f89caaSJens Wiklander 	case PKCS11_CKA_DERIVE_TEMPLATE:
228*63f89caaSJens Wiklander 		break;
229*63f89caaSJens Wiklander 	default:
230*63f89caaSJens Wiklander 		return PKCS11_RV_NOT_FOUND;
231*63f89caaSJens Wiklander 	}
232*63f89caaSJens Wiklander 	/* Such attributes are expected only for keys (and vendor defined) */
233*63f89caaSJens Wiklander 	if (pkcs11_attr_class_is_key(class))
234*63f89caaSJens Wiklander 		return PKCS11_CKR_TEMPLATE_INCONSISTENT;
235*63f89caaSJens Wiklander 
236*63f89caaSJens Wiklander 	rc = init_attributes_head(&obj2);
237*63f89caaSJens Wiklander 	if (rc)
238*63f89caaSJens Wiklander 		return rc;
239*63f89caaSJens Wiklander 
240*63f89caaSJens Wiklander 	/* Build a new serial object while sanitizing the attributes list */
241*63f89caaSJens Wiklander 	rc = sanitize_client_object(&obj2, data, cli_ref->size);
242*63f89caaSJens Wiklander 	if (rc)
243*63f89caaSJens Wiklander 		goto out;
244*63f89caaSJens Wiklander 
245*63f89caaSJens Wiklander 	rc = add_attribute(dst, cli_ref->id, obj2,
246*63f89caaSJens Wiklander 			   sizeof(*obj2) + obj2->attrs_size);
247*63f89caaSJens Wiklander out:
248*63f89caaSJens Wiklander 	TEE_Free(obj2);
249*63f89caaSJens Wiklander 	return rc;
250*63f89caaSJens Wiklander }
251*63f89caaSJens Wiklander 
252*63f89caaSJens Wiklander enum pkcs11_rc sanitize_client_object(struct obj_attrs **dst, void *src,
253*63f89caaSJens Wiklander 				      size_t size)
254*63f89caaSJens Wiklander {
255*63f89caaSJens Wiklander 	struct pkcs11_attribute_head cli_ref = { };
256*63f89caaSJens Wiklander 	struct pkcs11_object_head head = { };
257*63f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
258*63f89caaSJens Wiklander 	size_t pos = sizeof(head);
259*63f89caaSJens Wiklander 	size_t sz_from_hdr = 0;
260*63f89caaSJens Wiklander 	void *data = NULL;
261*63f89caaSJens Wiklander 
262*63f89caaSJens Wiklander 	if (size < sizeof(head))
263*63f89caaSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
264*63f89caaSJens Wiklander 
265*63f89caaSJens Wiklander 	TEE_MemMove(&head, src, sizeof(head));
266*63f89caaSJens Wiklander 
267*63f89caaSJens Wiklander 	if (ADD_OVERFLOW(sizeof(head), head.attrs_size, &sz_from_hdr) ||
268*63f89caaSJens Wiklander 	    size < sz_from_hdr)
269*63f89caaSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
270*63f89caaSJens Wiklander 
271*63f89caaSJens Wiklander 	rc = init_attributes_head(dst);
272*63f89caaSJens Wiklander 	if (rc)
273*63f89caaSJens Wiklander 		return rc;
274*63f89caaSJens Wiklander 
275*63f89caaSJens Wiklander 	rc = sanitize_class_and_type(dst, src, sz_from_hdr);
276*63f89caaSJens Wiklander 	if (rc)
277*63f89caaSJens Wiklander 		return rc;
278*63f89caaSJens Wiklander 
279*63f89caaSJens Wiklander 	rc = sanitize_boolprops(dst, src, sz_from_hdr);
280*63f89caaSJens Wiklander 	if (rc)
281*63f89caaSJens Wiklander 		return rc;
282*63f89caaSJens Wiklander 
283*63f89caaSJens Wiklander 	while (pos != sz_from_hdr) {
284*63f89caaSJens Wiklander 		rc = read_attr_advance(src, sz_from_hdr, &pos, &cli_ref, &data);
285*63f89caaSJens Wiklander 		if (rc)
286*63f89caaSJens Wiklander 			return rc;
287*63f89caaSJens Wiklander 
288*63f89caaSJens Wiklander 		if (cli_ref.id == PKCS11_CKA_CLASS ||
289*63f89caaSJens Wiklander 		    pkcs11_attr_is_type(cli_ref.id) ||
290*63f89caaSJens Wiklander 		    pkcs11_attr_is_boolean(cli_ref.id))
291*63f89caaSJens Wiklander 			continue;
292*63f89caaSJens Wiklander 
293*63f89caaSJens Wiklander 		rc = sanitize_indirect_attr(dst, &cli_ref, data);
294*63f89caaSJens Wiklander 		if (rc == PKCS11_CKR_OK)
295*63f89caaSJens Wiklander 			continue;
296*63f89caaSJens Wiklander 		if (rc != PKCS11_RV_NOT_FOUND)
297*63f89caaSJens Wiklander 			return rc;
298*63f89caaSJens Wiklander 
299*63f89caaSJens Wiklander 		if (!valid_pkcs11_attribute_id(cli_ref.id, cli_ref.size)) {
300*63f89caaSJens Wiklander 			EMSG("Invalid attribute id %#"PRIx32, cli_ref.id);
301*63f89caaSJens Wiklander 			return PKCS11_CKR_TEMPLATE_INCONSISTENT;
302*63f89caaSJens Wiklander 		}
303*63f89caaSJens Wiklander 
304*63f89caaSJens Wiklander 		rc = add_attribute(dst, cli_ref.id, data, cli_ref.size);
305*63f89caaSJens Wiklander 		if (rc)
306*63f89caaSJens Wiklander 			return rc;
307*63f89caaSJens Wiklander 	}
308*63f89caaSJens Wiklander 
309*63f89caaSJens Wiklander 	return rc;
310*63f89caaSJens Wiklander }
311*63f89caaSJens Wiklander 
312*63f89caaSJens Wiklander /*
313*63f89caaSJens Wiklander  * Debug: dump object attribute array to output trace
314*63f89caaSJens Wiklander  */
315*63f89caaSJens Wiklander 
316*63f89caaSJens Wiklander static void __trace_attributes(char *prefix, void *src, void *end)
317*63f89caaSJens Wiklander {
318*63f89caaSJens Wiklander 	size_t next = 0;
319*63f89caaSJens Wiklander 	char *prefix2 = NULL;
320*63f89caaSJens Wiklander 	size_t prefix_len = strlen(prefix);
321*63f89caaSJens Wiklander 	char *cur = src;
322*63f89caaSJens Wiklander 
323*63f89caaSJens Wiklander 	/* append 4 spaces to the prefix plus terminal '\0' */
324*63f89caaSJens Wiklander 	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
325*63f89caaSJens Wiklander 	if (!prefix2)
326*63f89caaSJens Wiklander 		return;
327*63f89caaSJens Wiklander 
328*63f89caaSJens Wiklander 	TEE_MemMove(prefix2, prefix, prefix_len + 1);
329*63f89caaSJens Wiklander 	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
330*63f89caaSJens Wiklander 	*(prefix2 + prefix_len + 4) = '\0';
331*63f89caaSJens Wiklander 
332*63f89caaSJens Wiklander 	for (; cur < (char *)end; cur += next) {
333*63f89caaSJens Wiklander 		struct pkcs11_attribute_head pkcs11_ref;
334*63f89caaSJens Wiklander 		uint8_t data[4] = { 0 };
335*63f89caaSJens Wiklander 		uint32_t data_u32 = 0;
336*63f89caaSJens Wiklander 
337*63f89caaSJens Wiklander 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
338*63f89caaSJens Wiklander 		TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
339*63f89caaSJens Wiklander 			    MIN(pkcs11_ref.size, sizeof(data)));
340*63f89caaSJens Wiklander 		TEE_MemMove(&data_u32, cur + sizeof(pkcs11_ref),
341*63f89caaSJens Wiklander 			    sizeof(data_u32));
342*63f89caaSJens Wiklander 
343*63f89caaSJens Wiklander 		next = sizeof(pkcs11_ref) + pkcs11_ref.size;
344*63f89caaSJens Wiklander 
345*63f89caaSJens Wiklander 		DMSG_RAW("%s Attr %s / %s (%#04"PRIx32" %"PRIu32"-byte)",
346*63f89caaSJens Wiklander 			 prefix, id2str_attr(pkcs11_ref.id),
347*63f89caaSJens Wiklander 			 id2str_attr_value(pkcs11_ref.id, pkcs11_ref.size,
348*63f89caaSJens Wiklander 					   cur + sizeof(pkcs11_ref)),
349*63f89caaSJens Wiklander 			 pkcs11_ref.id, pkcs11_ref.size);
350*63f89caaSJens Wiklander 
351*63f89caaSJens Wiklander 		switch (pkcs11_ref.size) {
352*63f89caaSJens Wiklander 		case 0:
353*63f89caaSJens Wiklander 			break;
354*63f89caaSJens Wiklander 		case 1:
355*63f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x", prefix, data[0]);
356*63f89caaSJens Wiklander 			break;
357*63f89caaSJens Wiklander 		case 2:
358*63f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x",
359*63f89caaSJens Wiklander 				 prefix, data[0], data[1]);
360*63f89caaSJens Wiklander 			break;
361*63f89caaSJens Wiklander 		case 3:
362*63f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x %02x",
363*63f89caaSJens Wiklander 				 prefix, data[0], data[1], data[2]);
364*63f89caaSJens Wiklander 			break;
365*63f89caaSJens Wiklander 		case 4:
366*63f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x",
367*63f89caaSJens Wiklander 				 prefix, data[0], data[1], data[2], data[3]);
368*63f89caaSJens Wiklander 			break;
369*63f89caaSJens Wiklander 		default:
370*63f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x ...",
371*63f89caaSJens Wiklander 				 prefix, data[0], data[1], data[2], data[3]);
372*63f89caaSJens Wiklander 			break;
373*63f89caaSJens Wiklander 		}
374*63f89caaSJens Wiklander 
375*63f89caaSJens Wiklander 		switch (pkcs11_ref.id) {
376*63f89caaSJens Wiklander 		case PKCS11_CKA_WRAP_TEMPLATE:
377*63f89caaSJens Wiklander 		case PKCS11_CKA_UNWRAP_TEMPLATE:
378*63f89caaSJens Wiklander 		case PKCS11_CKA_DERIVE_TEMPLATE:
379*63f89caaSJens Wiklander 			trace_attributes_from_api_head(prefix2,
380*63f89caaSJens Wiklander 						       cur + sizeof(pkcs11_ref),
381*63f89caaSJens Wiklander 						       (char *)end - cur);
382*63f89caaSJens Wiklander 			break;
383*63f89caaSJens Wiklander 		default:
384*63f89caaSJens Wiklander 			break;
385*63f89caaSJens Wiklander 		}
386*63f89caaSJens Wiklander 	}
387*63f89caaSJens Wiklander 
388*63f89caaSJens Wiklander 	/* Sanity */
389*63f89caaSJens Wiklander 	if (cur != (char *)end)
390*63f89caaSJens Wiklander 		EMSG("Warning: unexpected alignment issue");
391*63f89caaSJens Wiklander 
392*63f89caaSJens Wiklander 	TEE_Free(prefix2);
393*63f89caaSJens Wiklander }
394*63f89caaSJens Wiklander 
395*63f89caaSJens Wiklander void trace_attributes_from_api_head(const char *prefix, void *ref, size_t size)
396*63f89caaSJens Wiklander {
397*63f89caaSJens Wiklander 	struct pkcs11_object_head head = { };
398*63f89caaSJens Wiklander 	char *pre = NULL;
399*63f89caaSJens Wiklander 	size_t offset = 0;
400*63f89caaSJens Wiklander 
401*63f89caaSJens Wiklander 	TEE_MemMove(&head, ref, sizeof(head));
402*63f89caaSJens Wiklander 
403*63f89caaSJens Wiklander 	if (size > sizeof(head) + head.attrs_size) {
404*63f89caaSJens Wiklander 		EMSG("template overflows client buffer (%zu/%zu)",
405*63f89caaSJens Wiklander 		     size, sizeof(head) + head.attrs_size);
406*63f89caaSJens Wiklander 		return;
407*63f89caaSJens Wiklander 	}
408*63f89caaSJens Wiklander 
409*63f89caaSJens Wiklander 	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
410*63f89caaSJens Wiklander 	if (!pre) {
411*63f89caaSJens Wiklander 		EMSG("%s: out of memory", prefix);
412*63f89caaSJens Wiklander 		return;
413*63f89caaSJens Wiklander 	}
414*63f89caaSJens Wiklander 	if (prefix)
415*63f89caaSJens Wiklander 		TEE_MemMove(pre, prefix, strlen(prefix));
416*63f89caaSJens Wiklander 
417*63f89caaSJens Wiklander 	DMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
418*63f89caaSJens Wiklander 	DMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
419*63f89caaSJens Wiklander 		 pre, head.attrs_count, head.attrs_size);
420*63f89caaSJens Wiklander 
421*63f89caaSJens Wiklander 	offset = sizeof(head);
422*63f89caaSJens Wiklander 	pre[prefix ? strlen(prefix) : 0] = '|';
423*63f89caaSJens Wiklander 	__trace_attributes(pre, (char *)ref + offset,
424*63f89caaSJens Wiklander 			   (char *)ref + offset + head.attrs_size);
425*63f89caaSJens Wiklander 
426*63f89caaSJens Wiklander 	DMSG_RAW("%s`-----------------------", prefix ? prefix : "");
427*63f89caaSJens Wiklander 
428*63f89caaSJens Wiklander 	TEE_Free(pre);
429*63f89caaSJens Wiklander }
430