xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision e084583eada41a648a9ff9195899489402415cc2)
1c84ccd0aSEtienne Carriere // SPDX-License-Identifier: BSD-2-Clause
2c84ccd0aSEtienne Carriere /*
3c84ccd0aSEtienne Carriere  * Copyright (c) 2017-2020, Linaro Limited
4c84ccd0aSEtienne Carriere  */
5c84ccd0aSEtienne Carriere 
6c84ccd0aSEtienne Carriere #include <assert.h>
7d38f9635SEtienne Carriere #include <confine_array_index.h>
8c84ccd0aSEtienne Carriere #include <pkcs11_ta.h>
9c84ccd0aSEtienne Carriere #include <string.h>
10c84ccd0aSEtienne Carriere #include <string_ext.h>
11c84ccd0aSEtienne Carriere #include <sys/queue.h>
12c84ccd0aSEtienne Carriere #include <tee_api_types.h>
13c84ccd0aSEtienne Carriere #include <tee_internal_api_extensions.h>
14c84ccd0aSEtienne Carriere #include <util.h>
15c84ccd0aSEtienne Carriere 
16c84ccd0aSEtienne Carriere #include "pkcs11_token.h"
17c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h"
1822ac6984SEtienne Carriere #include "serializer.h"
19c84ccd0aSEtienne Carriere 
20c84ccd0aSEtienne Carriere /* Provide 3 slots/tokens, ID is token index */
21c84ccd0aSEtienne Carriere #ifndef CFG_PKCS11_TA_TOKEN_COUNT
22c84ccd0aSEtienne Carriere #define TOKEN_COUNT		3
23c84ccd0aSEtienne Carriere #else
24c84ccd0aSEtienne Carriere #define TOKEN_COUNT		CFG_PKCS11_TA_TOKEN_COUNT
25c84ccd0aSEtienne Carriere #endif
26c84ccd0aSEtienne Carriere 
27*e084583eSEtienne Carriere /*
28*e084583eSEtienne Carriere  * Structure tracking client applications
29*e084583eSEtienne Carriere  *
30*e084583eSEtienne Carriere  * @link - chained list of registered client applications
31*e084583eSEtienne Carriere  * @sessions - list of the PKCS11 sessions opened by the client application
32*e084583eSEtienne Carriere  */
33*e084583eSEtienne Carriere struct pkcs11_client {
34*e084583eSEtienne Carriere 	TAILQ_ENTRY(pkcs11_client) link;
35*e084583eSEtienne Carriere 	struct session_list session_list;
36*e084583eSEtienne Carriere 	struct handle_db session_handle_db;
37*e084583eSEtienne Carriere };
38*e084583eSEtienne Carriere 
39c84ccd0aSEtienne Carriere /* Static allocation of tokens runtime instances (reset to 0 at load) */
40c84ccd0aSEtienne Carriere struct ck_token ck_token[TOKEN_COUNT];
41c84ccd0aSEtienne Carriere 
42*e084583eSEtienne Carriere static struct client_list pkcs11_client_list =
43*e084583eSEtienne Carriere 	TAILQ_HEAD_INITIALIZER(pkcs11_client_list);
44*e084583eSEtienne Carriere 
45c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id)
46c84ccd0aSEtienne Carriere {
47d38f9635SEtienne Carriere 	if (token_id < TOKEN_COUNT)
48d38f9635SEtienne Carriere 		return &ck_token[confine_array_index(token_id, TOKEN_COUNT)];
49c84ccd0aSEtienne Carriere 
50d38f9635SEtienne Carriere 	return NULL;
51c84ccd0aSEtienne Carriere }
52c84ccd0aSEtienne Carriere 
53c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token)
54c84ccd0aSEtienne Carriere {
55c84ccd0aSEtienne Carriere 	ptrdiff_t id = token - ck_token;
56c84ccd0aSEtienne Carriere 
57c84ccd0aSEtienne Carriere 	assert(id >= 0 && id < TOKEN_COUNT);
58c84ccd0aSEtienne Carriere 	return id;
59c84ccd0aSEtienne Carriere }
60c84ccd0aSEtienne Carriere 
61*e084583eSEtienne Carriere struct pkcs11_client *tee_session2client(void *tee_session)
62*e084583eSEtienne Carriere {
63*e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
64*e084583eSEtienne Carriere 
65*e084583eSEtienne Carriere 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
66*e084583eSEtienne Carriere 		if (client == tee_session)
67*e084583eSEtienne Carriere 			break;
68*e084583eSEtienne Carriere 
69*e084583eSEtienne Carriere 	return client;
70*e084583eSEtienne Carriere }
71*e084583eSEtienne Carriere 
72*e084583eSEtienne Carriere struct pkcs11_client *register_client(void)
73*e084583eSEtienne Carriere {
74*e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
75*e084583eSEtienne Carriere 
76*e084583eSEtienne Carriere 	client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO);
77*e084583eSEtienne Carriere 	if (!client)
78*e084583eSEtienne Carriere 		return NULL;
79*e084583eSEtienne Carriere 
80*e084583eSEtienne Carriere 	TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link);
81*e084583eSEtienne Carriere 	TAILQ_INIT(&client->session_list);
82*e084583eSEtienne Carriere 	handle_db_init(&client->session_handle_db);
83*e084583eSEtienne Carriere 
84*e084583eSEtienne Carriere 	return client;
85*e084583eSEtienne Carriere }
86*e084583eSEtienne Carriere 
87*e084583eSEtienne Carriere void unregister_client(struct pkcs11_client *client)
88*e084583eSEtienne Carriere {
89*e084583eSEtienne Carriere 	if (!client) {
90*e084583eSEtienne Carriere 		EMSG("Invalid TEE session handle");
91*e084583eSEtienne Carriere 		return;
92*e084583eSEtienne Carriere 	}
93*e084583eSEtienne Carriere 
94*e084583eSEtienne Carriere 	TAILQ_REMOVE(&pkcs11_client_list, client, link);
95*e084583eSEtienne Carriere 	handle_db_destroy(&client->session_handle_db);
96*e084583eSEtienne Carriere 	TEE_Free(client);
97*e084583eSEtienne Carriere }
98*e084583eSEtienne Carriere 
99c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id)
100c84ccd0aSEtienne Carriere {
101c84ccd0aSEtienne Carriere 	struct ck_token *token = init_persistent_db(id);
102c84ccd0aSEtienne Carriere 
103c84ccd0aSEtienne Carriere 	if (!token)
104c84ccd0aSEtienne Carriere 		return TEE_ERROR_SECURITY;
105c84ccd0aSEtienne Carriere 
106c84ccd0aSEtienne Carriere 	if (token->state == PKCS11_TOKEN_RESET) {
107c84ccd0aSEtienne Carriere 		/* As per PKCS#11 spec, token resets to read/write state */
108c84ccd0aSEtienne Carriere 		token->state = PKCS11_TOKEN_READ_WRITE;
109c84ccd0aSEtienne Carriere 		token->session_count = 0;
110c84ccd0aSEtienne Carriere 		token->rw_session_count = 0;
111c84ccd0aSEtienne Carriere 	}
112c84ccd0aSEtienne Carriere 
113c84ccd0aSEtienne Carriere 	return TEE_SUCCESS;
114c84ccd0aSEtienne Carriere }
115c84ccd0aSEtienne Carriere 
116c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void)
117c84ccd0aSEtienne Carriere {
118c84ccd0aSEtienne Carriere 	unsigned int id = 0;
119c84ccd0aSEtienne Carriere 	TEE_Result ret = TEE_ERROR_GENERIC;
120c84ccd0aSEtienne Carriere 
121c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++) {
122c84ccd0aSEtienne Carriere 		ret = pkcs11_token_init(id);
123c84ccd0aSEtienne Carriere 		if (ret)
124*e084583eSEtienne Carriere 			break;
125c84ccd0aSEtienne Carriere 	}
126c84ccd0aSEtienne Carriere 
127c84ccd0aSEtienne Carriere 	return ret;
128c84ccd0aSEtienne Carriere }
129c84ccd0aSEtienne Carriere 
130c84ccd0aSEtienne Carriere void pkcs11_deinit(void)
131c84ccd0aSEtienne Carriere {
132c84ccd0aSEtienne Carriere 	unsigned int id = 0;
133c84ccd0aSEtienne Carriere 
134c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++)
135c84ccd0aSEtienne Carriere 		close_persistent_db(get_token(id));
136c84ccd0aSEtienne Carriere }
13722ac6984SEtienne Carriere 
13822ac6984SEtienne Carriere uint32_t entry_ck_slot_list(uint32_t ptypes, TEE_Param *params)
13922ac6984SEtienne Carriere {
14022ac6984SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
14122ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
14222ac6984SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
14322ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
14422ac6984SEtienne Carriere 	TEE_Param *out = &params[2];
14522ac6984SEtienne Carriere 	uint32_t token_id = 0;
14622ac6984SEtienne Carriere 	const size_t out_size = sizeof(token_id) * TOKEN_COUNT;
14722ac6984SEtienne Carriere 	uint8_t *id = NULL;
14822ac6984SEtienne Carriere 
14922ac6984SEtienne Carriere 	if (ptypes != exp_pt ||
15022ac6984SEtienne Carriere 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN)
15122ac6984SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
15222ac6984SEtienne Carriere 
15322ac6984SEtienne Carriere 	if (out->memref.size < out_size) {
15422ac6984SEtienne Carriere 		out->memref.size = out_size;
15522ac6984SEtienne Carriere 
15622ac6984SEtienne Carriere 		if (out->memref.buffer)
15722ac6984SEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
15822ac6984SEtienne Carriere 		else
15922ac6984SEtienne Carriere 			return PKCS11_CKR_OK;
16022ac6984SEtienne Carriere 	}
16122ac6984SEtienne Carriere 
16222ac6984SEtienne Carriere 	for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT;
16322ac6984SEtienne Carriere 	     token_id++, id += sizeof(token_id))
16422ac6984SEtienne Carriere 		TEE_MemMove(id, &token_id, sizeof(token_id));
16522ac6984SEtienne Carriere 
16622ac6984SEtienne Carriere 	out->memref.size = out_size;
16722ac6984SEtienne Carriere 
16822ac6984SEtienne Carriere 	return PKCS11_CKR_OK;
16922ac6984SEtienne Carriere }
170ce94efefSEtienne Carriere 
171b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size)
172b3ac5035SEtienne Carriere {
173b3ac5035SEtienne Carriere 	int n = strnlen((char *)str, size);
174b3ac5035SEtienne Carriere 
175b3ac5035SEtienne Carriere 	TEE_MemFill(str + n, ' ', size - n);
176b3ac5035SEtienne Carriere }
177b3ac5035SEtienne Carriere 
178ce94efefSEtienne Carriere uint32_t entry_ck_slot_info(uint32_t ptypes, TEE_Param *params)
179ce94efefSEtienne Carriere {
180ce94efefSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
181ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
182ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
183ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
184ce94efefSEtienne Carriere 	TEE_Param *ctrl = &params[0];
185ce94efefSEtienne Carriere 	TEE_Param *out = &params[2];
186ce94efefSEtienne Carriere 	uint32_t rv = 0;
187ce94efefSEtienne Carriere 	struct serialargs ctrlargs = { };
188ce94efefSEtienne Carriere 	uint32_t token_id = 0;
189ce94efefSEtienne Carriere 	struct ck_token *token = NULL;
190ce94efefSEtienne Carriere 	struct pkcs11_slot_info info = {
191ce94efefSEtienne Carriere 		.slot_description = PKCS11_SLOT_DESCRIPTION,
192ce94efefSEtienne Carriere 		.manufacturer_id = PKCS11_SLOT_MANUFACTURER,
193ce94efefSEtienne Carriere 		.flags = PKCS11_CKFS_TOKEN_PRESENT,
194ce94efefSEtienne Carriere 		.hardware_version = PKCS11_SLOT_HW_VERSION,
195ce94efefSEtienne Carriere 		.firmware_version = PKCS11_SLOT_FW_VERSION,
196ce94efefSEtienne Carriere 	};
197ce94efefSEtienne Carriere 
198ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <=
199ce94efefSEtienne Carriere 			    sizeof(info.slot_description));
200ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <=
201ce94efefSEtienne Carriere 			    sizeof(info.manufacturer_id));
202ce94efefSEtienne Carriere 
203ce94efefSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
204ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
205ce94efefSEtienne Carriere 
206ce94efefSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
207ce94efefSEtienne Carriere 
208ce94efefSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
209ce94efefSEtienne Carriere 	if (rv)
210ce94efefSEtienne Carriere 		return rv;
211ce94efefSEtienne Carriere 
212ce94efefSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
213ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
214ce94efefSEtienne Carriere 
215ce94efefSEtienne Carriere 	token = get_token(token_id);
216ce94efefSEtienne Carriere 	if (!token)
217ce94efefSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
218ce94efefSEtienne Carriere 
219b3ac5035SEtienne Carriere 	pad_str(info.slot_description, sizeof(info.slot_description));
220b3ac5035SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
221ce94efefSEtienne Carriere 
222ce94efefSEtienne Carriere 	out->memref.size = sizeof(info);
223ce94efefSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
224ce94efefSEtienne Carriere 
225ce94efefSEtienne Carriere 	return PKCS11_CKR_OK;
226ce94efefSEtienne Carriere }
227030e7392SEtienne Carriere 
228030e7392SEtienne Carriere uint32_t entry_ck_token_info(uint32_t ptypes, TEE_Param *params)
229030e7392SEtienne Carriere {
230030e7392SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
231030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
232030e7392SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
233030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
234030e7392SEtienne Carriere 	TEE_Param *ctrl = &params[0];
235030e7392SEtienne Carriere 	TEE_Param *out = &params[2];
236030e7392SEtienne Carriere 	uint32_t rv = 0;
237030e7392SEtienne Carriere 	struct serialargs ctrlargs = { };
238030e7392SEtienne Carriere 	uint32_t token_id = 0;
239030e7392SEtienne Carriere 	struct ck_token *token = NULL;
240030e7392SEtienne Carriere 	struct pkcs11_token_info info = {
241030e7392SEtienne Carriere 		.manufacturer_id = PKCS11_TOKEN_MANUFACTURER,
242030e7392SEtienne Carriere 		.model = PKCS11_TOKEN_MODEL,
243030e7392SEtienne Carriere 		.serial_number = PKCS11_TOKEN_SERIAL_NUMBER,
244030e7392SEtienne Carriere 		.max_session_count = UINT32_MAX,
245030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
246030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
247030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
248030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
249030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
250030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
251030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
252030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
253030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
254030e7392SEtienne Carriere 	};
255030e7392SEtienne Carriere 
256030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
257030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
258030e7392SEtienne Carriere 
259030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
260030e7392SEtienne Carriere 
261030e7392SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
262030e7392SEtienne Carriere 	if (rv)
263030e7392SEtienne Carriere 		return rv;
264030e7392SEtienne Carriere 
265030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
266030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
267030e7392SEtienne Carriere 
268030e7392SEtienne Carriere 	token = get_token(token_id);
269030e7392SEtienne Carriere 	if (!token)
270030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
271030e7392SEtienne Carriere 
272030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
273030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
274030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
275030e7392SEtienne Carriere 
276030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
277030e7392SEtienne Carriere 
278030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
279030e7392SEtienne Carriere 	info.session_count = token->session_count;
280030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
281030e7392SEtienne Carriere 
282030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
283030e7392SEtienne Carriere 
284030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
285030e7392SEtienne Carriere }
2866f74919dSEtienne Carriere 
2876f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
2886f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
2896f74919dSEtienne Carriere 					   size_t count __maybe_unused)
2906f74919dSEtienne Carriere {
2916f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
2926f74919dSEtienne Carriere 
2936f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
2946f74919dSEtienne Carriere 		return;
2956f74919dSEtienne Carriere 
2966f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
2976f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
2986f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
2996f74919dSEtienne Carriere }
3006f74919dSEtienne Carriere 
3016f74919dSEtienne Carriere uint32_t entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
3026f74919dSEtienne Carriere {
3036f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3046f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3056f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3066f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3076f74919dSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3086f74919dSEtienne Carriere 	TEE_Param *out = &params[2];
3096f74919dSEtienne Carriere 	uint32_t rv = 0;
3106f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
3116f74919dSEtienne Carriere 	uint32_t token_id = 0;
3126f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
3136f74919dSEtienne Carriere 	size_t count = 0;
3146f74919dSEtienne Carriere 	uint32_t *array = NULL;
3156f74919dSEtienne Carriere 
3166f74919dSEtienne Carriere 	if (ptypes != exp_pt)
3176f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3186f74919dSEtienne Carriere 
3196f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
3206f74919dSEtienne Carriere 
3216f74919dSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3226f74919dSEtienne Carriere 	if (rv)
3236f74919dSEtienne Carriere 		return rv;
3246f74919dSEtienne Carriere 
3256f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
3266f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3276f74919dSEtienne Carriere 
3286f74919dSEtienne Carriere 	token = get_token(token_id);
3296f74919dSEtienne Carriere 	if (!token)
3306f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
3316f74919dSEtienne Carriere 
3326f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
3336f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
3346f74919dSEtienne Carriere 
3356f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
3366f74919dSEtienne Carriere 		assert(!array);
3376f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
3386f74919dSEtienne Carriere 		return PKCS11_CKR_BUFFER_TOO_SMALL;
3396f74919dSEtienne Carriere 	}
3406f74919dSEtienne Carriere 
3416f74919dSEtienne Carriere 	if (!array)
3426f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
3436f74919dSEtienne Carriere 
3446f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
3456f74919dSEtienne Carriere 
3466f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
3476f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
3486f74919dSEtienne Carriere 
3496f74919dSEtienne Carriere 	TEE_Free(array);
3506f74919dSEtienne Carriere 
3516f74919dSEtienne Carriere 	return rv;
3526f74919dSEtienne Carriere }
3531d3ebedbSEtienne Carriere 
3541d3ebedbSEtienne Carriere static void supported_mechanism_key_size(uint32_t proc_id,
3551d3ebedbSEtienne Carriere 					 uint32_t *max_key_size,
3561d3ebedbSEtienne Carriere 					 uint32_t *min_key_size)
3571d3ebedbSEtienne Carriere {
3581d3ebedbSEtienne Carriere 	switch (proc_id) {
3591d3ebedbSEtienne Carriere 	/* Will be filled once TA supports mechanisms */
3601d3ebedbSEtienne Carriere 	default:
3611d3ebedbSEtienne Carriere 		*min_key_size = 0;
3621d3ebedbSEtienne Carriere 		*max_key_size = 0;
3631d3ebedbSEtienne Carriere 		break;
3641d3ebedbSEtienne Carriere 	}
3651d3ebedbSEtienne Carriere }
3661d3ebedbSEtienne Carriere 
3671d3ebedbSEtienne Carriere uint32_t entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
3681d3ebedbSEtienne Carriere {
3691d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3701d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3711d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3721d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3731d3ebedbSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3741d3ebedbSEtienne Carriere 	TEE_Param *out = &params[2];
3751d3ebedbSEtienne Carriere 	uint32_t rv = 0;
3761d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
3771d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
3781d3ebedbSEtienne Carriere 	uint32_t type = 0;
3791d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
3801d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
3811d3ebedbSEtienne Carriere 
3821d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
3831d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3841d3ebedbSEtienne Carriere 
3851d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
3861d3ebedbSEtienne Carriere 
3871d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
3881d3ebedbSEtienne Carriere 	if (rv)
3891d3ebedbSEtienne Carriere 		return rv;
3901d3ebedbSEtienne Carriere 
3911d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
3921d3ebedbSEtienne Carriere 	if (rv)
3931d3ebedbSEtienne Carriere 		return rv;
3941d3ebedbSEtienne Carriere 
3951d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
3961d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3971d3ebedbSEtienne Carriere 
3981d3ebedbSEtienne Carriere 	token = get_token(token_id);
3991d3ebedbSEtienne Carriere 	if (!token)
4001d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4011d3ebedbSEtienne Carriere 
4021d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
4031d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
4041d3ebedbSEtienne Carriere 
4051d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
4061d3ebedbSEtienne Carriere 
4071d3ebedbSEtienne Carriere 	supported_mechanism_key_size(type, &info.min_key_size,
4081d3ebedbSEtienne Carriere 				     &info.max_key_size);
4091d3ebedbSEtienne Carriere 
4101d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
4111d3ebedbSEtienne Carriere 
4121d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
4131d3ebedbSEtienne Carriere 	     token_id, type);
4141d3ebedbSEtienne Carriere 
4151d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
4161d3ebedbSEtienne Carriere }
417