xref: /optee_os/ta/pkcs11/src/sanitize_object.c (revision dcad34094cfb2e608a274baa3f6fd6e7ac3ed44a)
163f89caaSJens Wiklander // SPDX-License-Identifier: BSD-2-Clause
263f89caaSJens Wiklander /*
363f89caaSJens Wiklander  * Copyright (c) 2017-2020, Linaro Limited
463f89caaSJens Wiklander  */
563f89caaSJens Wiklander 
663f89caaSJens Wiklander #include <bitstring.h>
763f89caaSJens Wiklander #include <pkcs11_ta.h>
863f89caaSJens Wiklander #include <stdlib.h>
963f89caaSJens Wiklander #include <string.h>
1063f89caaSJens Wiklander #include <util.h>
1163f89caaSJens Wiklander #include <tee_internal_api.h>
1263f89caaSJens Wiklander #include <tee_internal_api_extensions.h>
1363f89caaSJens Wiklander #include <trace.h>
1463f89caaSJens Wiklander 
1563f89caaSJens Wiklander #include "attributes.h"
1663f89caaSJens Wiklander #include "pkcs11_helpers.h"
1763f89caaSJens Wiklander #include "sanitize_object.h"
1863f89caaSJens Wiklander #include "serializer.h"
1963f89caaSJens Wiklander #include "token_capabilities.h"
2063f89caaSJens Wiklander 
2163f89caaSJens Wiklander /*
2263f89caaSJens Wiklander  * Functions to generate a serialized object.
2363f89caaSJens Wiklander  * References are pointers to struct serializer.
2463f89caaSJens Wiklander  */
2563f89caaSJens Wiklander 
2663f89caaSJens Wiklander bool sanitize_consistent_class_and_type(struct obj_attrs *attrs)
2763f89caaSJens Wiklander {
2863f89caaSJens Wiklander 	switch (get_class(attrs)) {
2963f89caaSJens Wiklander 	case PKCS11_CKO_DATA:
3063f89caaSJens Wiklander 		return true;
3163f89caaSJens Wiklander 	case PKCS11_CKO_SECRET_KEY:
3263f89caaSJens Wiklander 		return key_type_is_symm_key(get_key_type(attrs));
3363f89caaSJens Wiklander 	case PKCS11_CKO_MECHANISM:
3463f89caaSJens Wiklander 		return mechanism_is_valid(get_mechanism_type(attrs));
3563f89caaSJens Wiklander 	case PKCS11_CKO_PUBLIC_KEY:
3663f89caaSJens Wiklander 	case PKCS11_CKO_PRIVATE_KEY:
3763f89caaSJens Wiklander 		return key_type_is_asymm_key(get_key_type(attrs));
3863f89caaSJens Wiklander 	case PKCS11_CKO_OTP_KEY:
3963f89caaSJens Wiklander 	case PKCS11_CKO_CERTIFICATE:
4063f89caaSJens Wiklander 	case PKCS11_CKO_DOMAIN_PARAMETERS:
4163f89caaSJens Wiklander 	case PKCS11_CKO_HW_FEATURE:
4263f89caaSJens Wiklander 	default:
4363f89caaSJens Wiklander 		return false;
4463f89caaSJens Wiklander 	}
4563f89caaSJens Wiklander 
4663f89caaSJens Wiklander 	return false;
4763f89caaSJens Wiklander }
4863f89caaSJens Wiklander 
4963f89caaSJens Wiklander static enum pkcs11_rc read_attr_advance(void *buf, size_t blen, size_t *pos,
5063f89caaSJens Wiklander 					struct pkcs11_attribute_head *attr,
5163f89caaSJens Wiklander 					void **data)
5263f89caaSJens Wiklander {
5363f89caaSJens Wiklander 	uint8_t *b = buf;
5463f89caaSJens Wiklander 	size_t data_pos = 0;
5563f89caaSJens Wiklander 	size_t next_pos = 0;
5663f89caaSJens Wiklander 
5763f89caaSJens Wiklander 	if (ADD_OVERFLOW(*pos, sizeof(*attr), &data_pos) || data_pos > blen)
5863f89caaSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
5963f89caaSJens Wiklander 	TEE_MemMove(attr, b + *pos, sizeof(*attr));
6063f89caaSJens Wiklander 
6163f89caaSJens Wiklander 	if (ADD_OVERFLOW(data_pos, attr->size, &next_pos) || next_pos > blen)
6263f89caaSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
6363f89caaSJens Wiklander 
6463f89caaSJens Wiklander 	*data = b + data_pos;
6563f89caaSJens Wiklander 	*pos = next_pos;
6663f89caaSJens Wiklander 
6763f89caaSJens Wiklander 	return PKCS11_CKR_OK;
6863f89caaSJens Wiklander }
6963f89caaSJens Wiklander 
7063f89caaSJens Wiklander /* Sanitize class/type in a client attribute list */
7163f89caaSJens Wiklander static enum pkcs11_rc sanitize_class_and_type(struct obj_attrs **dst, void *src,
72*dcad3409SRuchika Gupta 					      size_t src_size,
73*dcad3409SRuchika Gupta 					      uint32_t class_hint,
74*dcad3409SRuchika Gupta 					      uint32_t type_hint)
7563f89caaSJens Wiklander {
7663f89caaSJens Wiklander 	uint32_t class_found = PKCS11_CKO_UNDEFINED_ID;
7763f89caaSJens Wiklander 	size_t pos = sizeof(struct pkcs11_object_head);
7863f89caaSJens Wiklander 	struct pkcs11_attribute_head cli_ref = { };
7963f89caaSJens Wiklander 	uint32_t type_found = PKCS11_UNDEFINED_ID;
8063f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
8163f89caaSJens Wiklander 	void *data = NULL;
8263f89caaSJens Wiklander 
8363f89caaSJens Wiklander 	while (pos != src_size) {
8463f89caaSJens Wiklander 		rc = read_attr_advance(src, src_size, &pos, &cli_ref, &data);
8563f89caaSJens Wiklander 		if (rc)
8663f89caaSJens Wiklander 			goto err;
8763f89caaSJens Wiklander 
8863f89caaSJens Wiklander 		if (cli_ref.id == PKCS11_CKA_CLASS) {
8963f89caaSJens Wiklander 			uint32_t class = 0;
9063f89caaSJens Wiklander 
9163f89caaSJens Wiklander 			if (cli_ref.size != sizeof(class)) {
9263f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
9363f89caaSJens Wiklander 				goto err;
9463f89caaSJens Wiklander 			}
9563f89caaSJens Wiklander 
9663f89caaSJens Wiklander 			TEE_MemMove(&class, data, sizeof(class));
9763f89caaSJens Wiklander 
9863f89caaSJens Wiklander 			if (class_found != PKCS11_CKO_UNDEFINED_ID &&
9963f89caaSJens Wiklander 			    class_found != class) {
10063f89caaSJens Wiklander 				EMSG("Conflicting class value");
10163f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
10263f89caaSJens Wiklander 				goto err;
10363f89caaSJens Wiklander 			}
10463f89caaSJens Wiklander 
10563f89caaSJens Wiklander 			class_found = class;
10663f89caaSJens Wiklander 			continue;
10763f89caaSJens Wiklander 		}
10863f89caaSJens Wiklander 
10963f89caaSJens Wiklander 		/* The attribute is a type-in-class */
11063f89caaSJens Wiklander 		if (pkcs11_attr_is_type(cli_ref.id)) {
11163f89caaSJens Wiklander 			uint32_t type = 0;
11263f89caaSJens Wiklander 
11363f89caaSJens Wiklander 			if (cli_ref.size != sizeof(type)) {
11463f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
11563f89caaSJens Wiklander 				goto err;
11663f89caaSJens Wiklander 			}
11763f89caaSJens Wiklander 
11863f89caaSJens Wiklander 			TEE_MemMove(&type, data, sizeof(type));
11963f89caaSJens Wiklander 
12063f89caaSJens Wiklander 			if (type_found != PKCS11_CKK_UNDEFINED_ID &&
12163f89caaSJens Wiklander 			    type_found != type) {
12263f89caaSJens Wiklander 				EMSG("Conflicting type-in-class value");
12363f89caaSJens Wiklander 				rc = PKCS11_CKR_TEMPLATE_INCONSISTENT;
12463f89caaSJens Wiklander 				goto err;
12563f89caaSJens Wiklander 			}
12663f89caaSJens Wiklander 
12763f89caaSJens Wiklander 			type_found = type;
12863f89caaSJens Wiklander 		}
12963f89caaSJens Wiklander 	}
13063f89caaSJens Wiklander 
13163f89caaSJens Wiklander 	if (class_found != PKCS11_CKO_UNDEFINED_ID) {
13263f89caaSJens Wiklander 		rc = add_attribute(dst, PKCS11_CKA_CLASS,
13363f89caaSJens Wiklander 				   &class_found, sizeof(class_found));
13463f89caaSJens Wiklander 		if (rc)
13563f89caaSJens Wiklander 			return rc;
136*dcad3409SRuchika Gupta 	} else {
137*dcad3409SRuchika Gupta 		if (class_hint != PKCS11_CKO_UNDEFINED_ID) {
138*dcad3409SRuchika Gupta 			rc = add_attribute(dst, PKCS11_CKA_CLASS,
139*dcad3409SRuchika Gupta 					   &class_hint, sizeof(class_hint));
140*dcad3409SRuchika Gupta 			if (rc)
141*dcad3409SRuchika Gupta 				return rc;
142*dcad3409SRuchika Gupta 		}
14363f89caaSJens Wiklander 	}
14463f89caaSJens Wiklander 
14563f89caaSJens Wiklander 	if (type_found != PKCS11_UNDEFINED_ID) {
14663f89caaSJens Wiklander 		rc = add_attribute(dst, PKCS11_CKA_KEY_TYPE,
14763f89caaSJens Wiklander 				   &type_found, sizeof(type_found));
14863f89caaSJens Wiklander 		if (rc)
14963f89caaSJens Wiklander 			return rc;
150*dcad3409SRuchika Gupta 	} else {
151*dcad3409SRuchika Gupta 		if (type_hint != PKCS11_UNDEFINED_ID) {
152*dcad3409SRuchika Gupta 			rc = add_attribute(dst, PKCS11_CKA_KEY_TYPE,
153*dcad3409SRuchika Gupta 					   &type_hint, sizeof(type_hint));
154*dcad3409SRuchika Gupta 			if (rc)
155*dcad3409SRuchika Gupta 				return rc;
156*dcad3409SRuchika Gupta 		}
15763f89caaSJens Wiklander 	}
15863f89caaSJens Wiklander 
15963f89caaSJens Wiklander 	return PKCS11_CKR_OK;
16063f89caaSJens Wiklander 
16163f89caaSJens Wiklander err:
16263f89caaSJens Wiklander 	trace_attributes_from_api_head("bad-template", src, src_size);
16363f89caaSJens Wiklander 
16463f89caaSJens Wiklander 	return rc;
16563f89caaSJens Wiklander }
16663f89caaSJens Wiklander 
16763f89caaSJens Wiklander static enum pkcs11_rc sanitize_boolprops(struct obj_attrs **dst, void *src,
16863f89caaSJens Wiklander 					 size_t src_size)
16963f89caaSJens Wiklander {
17063f89caaSJens Wiklander 	bitstr_t bit_decl(seen_attrs, PKCS11_BOOLPROPS_MAX_COUNT) = { 0 };
17163f89caaSJens Wiklander 	bitstr_t bit_decl(boolprops, PKCS11_BOOLPROPS_MAX_COUNT) = { 0 };
17263f89caaSJens Wiklander 	size_t pos = sizeof(struct pkcs11_object_head);
17363f89caaSJens Wiklander 	struct pkcs11_attribute_head cli_ref = { };
17463f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
17563f89caaSJens Wiklander 	bool value = false;
17663f89caaSJens Wiklander 	void *data = NULL;
17763f89caaSJens Wiklander 	int idx = 0;
17863f89caaSJens Wiklander 
17963f89caaSJens Wiklander 	/*
18063f89caaSJens Wiklander 	 * We're keeping track of seen boolean attributes in the bitstring
18163f89caaSJens Wiklander 	 * seen_attrs. The bitstring boolprops holds the recorded value
18263f89caaSJens Wiklander 	 * once seen_attrs has been updated.
18363f89caaSJens Wiklander 	 */
18463f89caaSJens Wiklander 
18563f89caaSJens Wiklander 	while (pos != src_size) {
18663f89caaSJens Wiklander 		rc = read_attr_advance(src, src_size, &pos, &cli_ref, &data);
18763f89caaSJens Wiklander 		if (rc)
18863f89caaSJens Wiklander 			return rc;
18963f89caaSJens Wiklander 
19063f89caaSJens Wiklander 		idx = pkcs11_attr2boolprop_shift(cli_ref.id);
19163f89caaSJens Wiklander 		if (idx < 0)
19263f89caaSJens Wiklander 			continue; /* skipping non-boolean attributes */
19363f89caaSJens Wiklander 
19463f89caaSJens Wiklander 		if (idx >= PKCS11_BOOLPROPS_MAX_COUNT ||
19563f89caaSJens Wiklander 		    cli_ref.size != sizeof(uint8_t))
19663f89caaSJens Wiklander 			return PKCS11_CKR_FUNCTION_FAILED;
19763f89caaSJens Wiklander 
19863f89caaSJens Wiklander 		value = *(uint8_t *)data;
19963f89caaSJens Wiklander 
20063f89caaSJens Wiklander 		/*
20163f89caaSJens Wiklander 		 * If this attribute has already been seen, check that it
20263f89caaSJens Wiklander 		 * still holds the same value as last time.
20363f89caaSJens Wiklander 		 */
20463f89caaSJens Wiklander 		if (bit_test(seen_attrs, idx) &&
20563f89caaSJens Wiklander 		    value != (bool)bit_test(boolprops, idx))
20663f89caaSJens Wiklander 			return PKCS11_CKR_TEMPLATE_INCONSISTENT;
20763f89caaSJens Wiklander 
20863f89caaSJens Wiklander 		if (value)
20963f89caaSJens Wiklander 			bit_set(boolprops, idx);
21063f89caaSJens Wiklander 
21163f89caaSJens Wiklander 		if (!bit_test(seen_attrs, idx)) {
21263f89caaSJens Wiklander 			uint8_t pkcs11_bool = value;
21363f89caaSJens Wiklander 
21463f89caaSJens Wiklander 			rc = add_attribute(dst, cli_ref.id, &pkcs11_bool,
21563f89caaSJens Wiklander 					   sizeof(pkcs11_bool));
21663f89caaSJens Wiklander 			if (rc)
21763f89caaSJens Wiklander 				return rc;
21863f89caaSJens Wiklander 		}
21963f89caaSJens Wiklander 		bit_set(seen_attrs, idx);
22063f89caaSJens Wiklander 	}
22163f89caaSJens Wiklander 
22263f89caaSJens Wiklander 	return PKCS11_CKR_OK;
22363f89caaSJens Wiklander }
22463f89caaSJens Wiklander 
22563f89caaSJens Wiklander static uint32_t sanitize_indirect_attr(struct obj_attrs **dst,
22663f89caaSJens Wiklander 				       struct pkcs11_attribute_head *cli_ref,
22763f89caaSJens Wiklander 				       char *data)
22863f89caaSJens Wiklander {
22963f89caaSJens Wiklander 	struct obj_attrs *obj2 = NULL;
23063f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
23163f89caaSJens Wiklander 	enum pkcs11_class_id class = get_class(*dst);
23263f89caaSJens Wiklander 
23363f89caaSJens Wiklander 	/*
23463f89caaSJens Wiklander 	 * Serialized attributes: current applicable only to the key
23563f89caaSJens Wiklander 	 * templates which are tables of attributes.
23663f89caaSJens Wiklander 	 */
23763f89caaSJens Wiklander 	switch (cli_ref->id) {
23863f89caaSJens Wiklander 	case PKCS11_CKA_WRAP_TEMPLATE:
23963f89caaSJens Wiklander 	case PKCS11_CKA_UNWRAP_TEMPLATE:
24063f89caaSJens Wiklander 	case PKCS11_CKA_DERIVE_TEMPLATE:
24163f89caaSJens Wiklander 		break;
24263f89caaSJens Wiklander 	default:
24363f89caaSJens Wiklander 		return PKCS11_RV_NOT_FOUND;
24463f89caaSJens Wiklander 	}
2455440719dSRuchika Gupta 
2465440719dSRuchika Gupta 	if (class == PKCS11_CKO_UNDEFINED_ID) {
2475440719dSRuchika Gupta 		DMSG("Template without CLASS not supported yet");
2485440719dSRuchika Gupta 		return PKCS11_CKR_TEMPLATE_INCOMPLETE;
2495440719dSRuchika Gupta 	}
2505440719dSRuchika Gupta 
25163f89caaSJens Wiklander 	/* Such attributes are expected only for keys (and vendor defined) */
25263f89caaSJens Wiklander 	if (pkcs11_attr_class_is_key(class))
25363f89caaSJens Wiklander 		return PKCS11_CKR_TEMPLATE_INCONSISTENT;
25463f89caaSJens Wiklander 
25563f89caaSJens Wiklander 	rc = init_attributes_head(&obj2);
25663f89caaSJens Wiklander 	if (rc)
25763f89caaSJens Wiklander 		return rc;
25863f89caaSJens Wiklander 
25963f89caaSJens Wiklander 	/* Build a new serial object while sanitizing the attributes list */
260*dcad3409SRuchika Gupta 	rc = sanitize_client_object(&obj2, data, cli_ref->size,
261*dcad3409SRuchika Gupta 				    PKCS11_CKO_UNDEFINED_ID,
262*dcad3409SRuchika Gupta 				    PKCS11_UNDEFINED_ID);
26363f89caaSJens Wiklander 	if (rc)
26463f89caaSJens Wiklander 		goto out;
26563f89caaSJens Wiklander 
26663f89caaSJens Wiklander 	rc = add_attribute(dst, cli_ref->id, obj2,
26763f89caaSJens Wiklander 			   sizeof(*obj2) + obj2->attrs_size);
26863f89caaSJens Wiklander out:
26963f89caaSJens Wiklander 	TEE_Free(obj2);
27063f89caaSJens Wiklander 	return rc;
27163f89caaSJens Wiklander }
27263f89caaSJens Wiklander 
27363f89caaSJens Wiklander enum pkcs11_rc sanitize_client_object(struct obj_attrs **dst, void *src,
274*dcad3409SRuchika Gupta 				      size_t size, uint32_t class_hint,
275*dcad3409SRuchika Gupta 				      uint32_t type_hint)
27663f89caaSJens Wiklander {
27763f89caaSJens Wiklander 	struct pkcs11_attribute_head cli_ref = { };
27863f89caaSJens Wiklander 	struct pkcs11_object_head head = { };
27963f89caaSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
28063f89caaSJens Wiklander 	size_t pos = sizeof(head);
28163f89caaSJens Wiklander 	size_t sz_from_hdr = 0;
28263f89caaSJens Wiklander 	void *data = NULL;
28363f89caaSJens Wiklander 
28463f89caaSJens Wiklander 	if (size < sizeof(head))
28563f89caaSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
28663f89caaSJens Wiklander 
28763f89caaSJens Wiklander 	TEE_MemMove(&head, src, sizeof(head));
28863f89caaSJens Wiklander 
28963f89caaSJens Wiklander 	if (ADD_OVERFLOW(sizeof(head), head.attrs_size, &sz_from_hdr) ||
29063f89caaSJens Wiklander 	    size < sz_from_hdr)
29163f89caaSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
29263f89caaSJens Wiklander 
29363f89caaSJens Wiklander 	rc = init_attributes_head(dst);
29463f89caaSJens Wiklander 	if (rc)
29563f89caaSJens Wiklander 		return rc;
29663f89caaSJens Wiklander 
297*dcad3409SRuchika Gupta 	rc = sanitize_class_and_type(dst, src, sz_from_hdr, class_hint,
298*dcad3409SRuchika Gupta 				     type_hint);
29963f89caaSJens Wiklander 	if (rc)
30063f89caaSJens Wiklander 		return rc;
30163f89caaSJens Wiklander 
30263f89caaSJens Wiklander 	rc = sanitize_boolprops(dst, src, sz_from_hdr);
30363f89caaSJens Wiklander 	if (rc)
30463f89caaSJens Wiklander 		return rc;
30563f89caaSJens Wiklander 
30663f89caaSJens Wiklander 	while (pos != sz_from_hdr) {
30763f89caaSJens Wiklander 		rc = read_attr_advance(src, sz_from_hdr, &pos, &cli_ref, &data);
30863f89caaSJens Wiklander 		if (rc)
30963f89caaSJens Wiklander 			return rc;
31063f89caaSJens Wiklander 
31163f89caaSJens Wiklander 		if (cli_ref.id == PKCS11_CKA_CLASS ||
31263f89caaSJens Wiklander 		    pkcs11_attr_is_type(cli_ref.id) ||
31363f89caaSJens Wiklander 		    pkcs11_attr_is_boolean(cli_ref.id))
31463f89caaSJens Wiklander 			continue;
31563f89caaSJens Wiklander 
31663f89caaSJens Wiklander 		rc = sanitize_indirect_attr(dst, &cli_ref, data);
31763f89caaSJens Wiklander 		if (rc == PKCS11_CKR_OK)
31863f89caaSJens Wiklander 			continue;
31963f89caaSJens Wiklander 		if (rc != PKCS11_RV_NOT_FOUND)
32063f89caaSJens Wiklander 			return rc;
32163f89caaSJens Wiklander 
32263f89caaSJens Wiklander 		if (!valid_pkcs11_attribute_id(cli_ref.id, cli_ref.size)) {
32363f89caaSJens Wiklander 			EMSG("Invalid attribute id %#"PRIx32, cli_ref.id);
32463f89caaSJens Wiklander 			return PKCS11_CKR_TEMPLATE_INCONSISTENT;
32563f89caaSJens Wiklander 		}
32663f89caaSJens Wiklander 
32763f89caaSJens Wiklander 		rc = add_attribute(dst, cli_ref.id, data, cli_ref.size);
32863f89caaSJens Wiklander 		if (rc)
32963f89caaSJens Wiklander 			return rc;
33063f89caaSJens Wiklander 	}
33163f89caaSJens Wiklander 
33263f89caaSJens Wiklander 	return rc;
33363f89caaSJens Wiklander }
33463f89caaSJens Wiklander 
33563f89caaSJens Wiklander /*
33663f89caaSJens Wiklander  * Debug: dump object attribute array to output trace
33763f89caaSJens Wiklander  */
33863f89caaSJens Wiklander 
33963f89caaSJens Wiklander static void __trace_attributes(char *prefix, void *src, void *end)
34063f89caaSJens Wiklander {
34163f89caaSJens Wiklander 	size_t next = 0;
34263f89caaSJens Wiklander 	char *prefix2 = NULL;
34363f89caaSJens Wiklander 	size_t prefix_len = strlen(prefix);
34463f89caaSJens Wiklander 	char *cur = src;
34563f89caaSJens Wiklander 
34663f89caaSJens Wiklander 	/* append 4 spaces to the prefix plus terminal '\0' */
34763f89caaSJens Wiklander 	prefix2 = TEE_Malloc(prefix_len + 1 + 4, TEE_MALLOC_FILL_ZERO);
34863f89caaSJens Wiklander 	if (!prefix2)
34963f89caaSJens Wiklander 		return;
35063f89caaSJens Wiklander 
35163f89caaSJens Wiklander 	TEE_MemMove(prefix2, prefix, prefix_len + 1);
35263f89caaSJens Wiklander 	TEE_MemFill(prefix2 + prefix_len, ' ', 4);
35363f89caaSJens Wiklander 	*(prefix2 + prefix_len + 4) = '\0';
35463f89caaSJens Wiklander 
35563f89caaSJens Wiklander 	for (; cur < (char *)end; cur += next) {
35663f89caaSJens Wiklander 		struct pkcs11_attribute_head pkcs11_ref;
35763f89caaSJens Wiklander 		uint8_t data[4] = { 0 };
35863f89caaSJens Wiklander 		uint32_t data_u32 = 0;
35963f89caaSJens Wiklander 
36063f89caaSJens Wiklander 		TEE_MemMove(&pkcs11_ref, cur, sizeof(pkcs11_ref));
36163f89caaSJens Wiklander 		TEE_MemMove(&data[0], cur + sizeof(pkcs11_ref),
36263f89caaSJens Wiklander 			    MIN(pkcs11_ref.size, sizeof(data)));
36363f89caaSJens Wiklander 		TEE_MemMove(&data_u32, cur + sizeof(pkcs11_ref),
36463f89caaSJens Wiklander 			    sizeof(data_u32));
36563f89caaSJens Wiklander 
36663f89caaSJens Wiklander 		next = sizeof(pkcs11_ref) + pkcs11_ref.size;
36763f89caaSJens Wiklander 
36863f89caaSJens Wiklander 		DMSG_RAW("%s Attr %s / %s (%#04"PRIx32" %"PRIu32"-byte)",
36963f89caaSJens Wiklander 			 prefix, id2str_attr(pkcs11_ref.id),
37063f89caaSJens Wiklander 			 id2str_attr_value(pkcs11_ref.id, pkcs11_ref.size,
37163f89caaSJens Wiklander 					   cur + sizeof(pkcs11_ref)),
37263f89caaSJens Wiklander 			 pkcs11_ref.id, pkcs11_ref.size);
37363f89caaSJens Wiklander 
37463f89caaSJens Wiklander 		switch (pkcs11_ref.size) {
37563f89caaSJens Wiklander 		case 0:
37663f89caaSJens Wiklander 			break;
37763f89caaSJens Wiklander 		case 1:
37863f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x", prefix, data[0]);
37963f89caaSJens Wiklander 			break;
38063f89caaSJens Wiklander 		case 2:
38163f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x",
38263f89caaSJens Wiklander 				 prefix, data[0], data[1]);
38363f89caaSJens Wiklander 			break;
38463f89caaSJens Wiklander 		case 3:
38563f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x %02x",
38663f89caaSJens Wiklander 				 prefix, data[0], data[1], data[2]);
38763f89caaSJens Wiklander 			break;
38863f89caaSJens Wiklander 		case 4:
38963f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x",
39063f89caaSJens Wiklander 				 prefix, data[0], data[1], data[2], data[3]);
39163f89caaSJens Wiklander 			break;
39263f89caaSJens Wiklander 		default:
39363f89caaSJens Wiklander 			DMSG_RAW("%s Attr byte value: %02x %02x %02x %02x ...",
39463f89caaSJens Wiklander 				 prefix, data[0], data[1], data[2], data[3]);
39563f89caaSJens Wiklander 			break;
39663f89caaSJens Wiklander 		}
39763f89caaSJens Wiklander 
39863f89caaSJens Wiklander 		switch (pkcs11_ref.id) {
39963f89caaSJens Wiklander 		case PKCS11_CKA_WRAP_TEMPLATE:
40063f89caaSJens Wiklander 		case PKCS11_CKA_UNWRAP_TEMPLATE:
40163f89caaSJens Wiklander 		case PKCS11_CKA_DERIVE_TEMPLATE:
40263f89caaSJens Wiklander 			trace_attributes_from_api_head(prefix2,
40363f89caaSJens Wiklander 						       cur + sizeof(pkcs11_ref),
40463f89caaSJens Wiklander 						       (char *)end - cur);
40563f89caaSJens Wiklander 			break;
40663f89caaSJens Wiklander 		default:
40763f89caaSJens Wiklander 			break;
40863f89caaSJens Wiklander 		}
40963f89caaSJens Wiklander 	}
41063f89caaSJens Wiklander 
41163f89caaSJens Wiklander 	/* Sanity */
41263f89caaSJens Wiklander 	if (cur != (char *)end)
41363f89caaSJens Wiklander 		EMSG("Warning: unexpected alignment issue");
41463f89caaSJens Wiklander 
41563f89caaSJens Wiklander 	TEE_Free(prefix2);
41663f89caaSJens Wiklander }
41763f89caaSJens Wiklander 
41863f89caaSJens Wiklander void trace_attributes_from_api_head(const char *prefix, void *ref, size_t size)
41963f89caaSJens Wiklander {
42063f89caaSJens Wiklander 	struct pkcs11_object_head head = { };
42163f89caaSJens Wiklander 	char *pre = NULL;
42263f89caaSJens Wiklander 	size_t offset = 0;
42363f89caaSJens Wiklander 
42463f89caaSJens Wiklander 	TEE_MemMove(&head, ref, sizeof(head));
42563f89caaSJens Wiklander 
42663f89caaSJens Wiklander 	if (size > sizeof(head) + head.attrs_size) {
42763f89caaSJens Wiklander 		EMSG("template overflows client buffer (%zu/%zu)",
42863f89caaSJens Wiklander 		     size, sizeof(head) + head.attrs_size);
42963f89caaSJens Wiklander 		return;
43063f89caaSJens Wiklander 	}
43163f89caaSJens Wiklander 
43263f89caaSJens Wiklander 	pre = TEE_Malloc(prefix ? strlen(prefix) + 2 : 2, TEE_MALLOC_FILL_ZERO);
43363f89caaSJens Wiklander 	if (!pre) {
43463f89caaSJens Wiklander 		EMSG("%s: out of memory", prefix);
43563f89caaSJens Wiklander 		return;
43663f89caaSJens Wiklander 	}
43763f89caaSJens Wiklander 	if (prefix)
43863f89caaSJens Wiklander 		TEE_MemMove(pre, prefix, strlen(prefix));
43963f89caaSJens Wiklander 
44063f89caaSJens Wiklander 	DMSG_RAW("%s,--- (serial object) Attributes list --------", pre);
44163f89caaSJens Wiklander 	DMSG_RAW("%s| %"PRIu32" item(s) - %"PRIu32" bytes",
44263f89caaSJens Wiklander 		 pre, head.attrs_count, head.attrs_size);
44363f89caaSJens Wiklander 
44463f89caaSJens Wiklander 	offset = sizeof(head);
44563f89caaSJens Wiklander 	pre[prefix ? strlen(prefix) : 0] = '|';
44663f89caaSJens Wiklander 	__trace_attributes(pre, (char *)ref + offset,
44763f89caaSJens Wiklander 			   (char *)ref + offset + head.attrs_size);
44863f89caaSJens Wiklander 
44963f89caaSJens Wiklander 	DMSG_RAW("%s`-----------------------", prefix ? prefix : "");
45063f89caaSJens Wiklander 
45163f89caaSJens Wiklander 	TEE_Free(pre);
45263f89caaSJens Wiklander }
453