xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision 1d3ebedbeb4759c8e92aff8950bc9c3e091d764a)
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 
27c84ccd0aSEtienne Carriere /* Static allocation of tokens runtime instances (reset to 0 at load) */
28c84ccd0aSEtienne Carriere struct ck_token ck_token[TOKEN_COUNT];
29c84ccd0aSEtienne Carriere 
30c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id)
31c84ccd0aSEtienne Carriere {
32d38f9635SEtienne Carriere 	if (token_id < TOKEN_COUNT)
33d38f9635SEtienne Carriere 		return &ck_token[confine_array_index(token_id, TOKEN_COUNT)];
34c84ccd0aSEtienne Carriere 
35d38f9635SEtienne Carriere 	return NULL;
36c84ccd0aSEtienne Carriere }
37c84ccd0aSEtienne Carriere 
38c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token)
39c84ccd0aSEtienne Carriere {
40c84ccd0aSEtienne Carriere 	ptrdiff_t id = token - ck_token;
41c84ccd0aSEtienne Carriere 
42c84ccd0aSEtienne Carriere 	assert(id >= 0 && id < TOKEN_COUNT);
43c84ccd0aSEtienne Carriere 	return id;
44c84ccd0aSEtienne Carriere }
45c84ccd0aSEtienne Carriere 
46c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id)
47c84ccd0aSEtienne Carriere {
48c84ccd0aSEtienne Carriere 	struct ck_token *token = init_persistent_db(id);
49c84ccd0aSEtienne Carriere 
50c84ccd0aSEtienne Carriere 	if (!token)
51c84ccd0aSEtienne Carriere 		return TEE_ERROR_SECURITY;
52c84ccd0aSEtienne Carriere 
53c84ccd0aSEtienne Carriere 	if (token->state == PKCS11_TOKEN_RESET) {
54c84ccd0aSEtienne Carriere 		/* As per PKCS#11 spec, token resets to read/write state */
55c84ccd0aSEtienne Carriere 		token->state = PKCS11_TOKEN_READ_WRITE;
56c84ccd0aSEtienne Carriere 		token->session_count = 0;
57c84ccd0aSEtienne Carriere 		token->rw_session_count = 0;
58c84ccd0aSEtienne Carriere 	}
59c84ccd0aSEtienne Carriere 
60c84ccd0aSEtienne Carriere 	return TEE_SUCCESS;
61c84ccd0aSEtienne Carriere }
62c84ccd0aSEtienne Carriere 
63c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void)
64c84ccd0aSEtienne Carriere {
65c84ccd0aSEtienne Carriere 	unsigned int id = 0;
66c84ccd0aSEtienne Carriere 	TEE_Result ret = TEE_ERROR_GENERIC;
67c84ccd0aSEtienne Carriere 
68c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++) {
69c84ccd0aSEtienne Carriere 		ret = pkcs11_token_init(id);
70c84ccd0aSEtienne Carriere 		if (ret)
71c84ccd0aSEtienne Carriere 			return ret;
72c84ccd0aSEtienne Carriere 	}
73c84ccd0aSEtienne Carriere 
74c84ccd0aSEtienne Carriere 	return ret;
75c84ccd0aSEtienne Carriere }
76c84ccd0aSEtienne Carriere 
77c84ccd0aSEtienne Carriere void pkcs11_deinit(void)
78c84ccd0aSEtienne Carriere {
79c84ccd0aSEtienne Carriere 	unsigned int id = 0;
80c84ccd0aSEtienne Carriere 
81c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++)
82c84ccd0aSEtienne Carriere 		close_persistent_db(get_token(id));
83c84ccd0aSEtienne Carriere }
8422ac6984SEtienne Carriere 
8522ac6984SEtienne Carriere uint32_t entry_ck_slot_list(uint32_t ptypes, TEE_Param *params)
8622ac6984SEtienne Carriere {
8722ac6984SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
8822ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
8922ac6984SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
9022ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
9122ac6984SEtienne Carriere 	TEE_Param *out = &params[2];
9222ac6984SEtienne Carriere 	uint32_t token_id = 0;
9322ac6984SEtienne Carriere 	const size_t out_size = sizeof(token_id) * TOKEN_COUNT;
9422ac6984SEtienne Carriere 	uint8_t *id = NULL;
9522ac6984SEtienne Carriere 
9622ac6984SEtienne Carriere 	if (ptypes != exp_pt ||
9722ac6984SEtienne Carriere 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN)
9822ac6984SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
9922ac6984SEtienne Carriere 
10022ac6984SEtienne Carriere 	if (out->memref.size < out_size) {
10122ac6984SEtienne Carriere 		out->memref.size = out_size;
10222ac6984SEtienne Carriere 
10322ac6984SEtienne Carriere 		if (out->memref.buffer)
10422ac6984SEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
10522ac6984SEtienne Carriere 		else
10622ac6984SEtienne Carriere 			return PKCS11_CKR_OK;
10722ac6984SEtienne Carriere 	}
10822ac6984SEtienne Carriere 
10922ac6984SEtienne Carriere 	for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT;
11022ac6984SEtienne Carriere 	     token_id++, id += sizeof(token_id))
11122ac6984SEtienne Carriere 		TEE_MemMove(id, &token_id, sizeof(token_id));
11222ac6984SEtienne Carriere 
11322ac6984SEtienne Carriere 	out->memref.size = out_size;
11422ac6984SEtienne Carriere 
11522ac6984SEtienne Carriere 	return PKCS11_CKR_OK;
11622ac6984SEtienne Carriere }
117ce94efefSEtienne Carriere 
118b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size)
119b3ac5035SEtienne Carriere {
120b3ac5035SEtienne Carriere 	int n = strnlen((char *)str, size);
121b3ac5035SEtienne Carriere 
122b3ac5035SEtienne Carriere 	TEE_MemFill(str + n, ' ', size - n);
123b3ac5035SEtienne Carriere }
124b3ac5035SEtienne Carriere 
125ce94efefSEtienne Carriere uint32_t entry_ck_slot_info(uint32_t ptypes, TEE_Param *params)
126ce94efefSEtienne Carriere {
127ce94efefSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
128ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
129ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
130ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
131ce94efefSEtienne Carriere 	TEE_Param *ctrl = &params[0];
132ce94efefSEtienne Carriere 	TEE_Param *out = &params[2];
133ce94efefSEtienne Carriere 	uint32_t rv = 0;
134ce94efefSEtienne Carriere 	struct serialargs ctrlargs = { };
135ce94efefSEtienne Carriere 	uint32_t token_id = 0;
136ce94efefSEtienne Carriere 	struct ck_token *token = NULL;
137ce94efefSEtienne Carriere 	struct pkcs11_slot_info info = {
138ce94efefSEtienne Carriere 		.slot_description = PKCS11_SLOT_DESCRIPTION,
139ce94efefSEtienne Carriere 		.manufacturer_id = PKCS11_SLOT_MANUFACTURER,
140ce94efefSEtienne Carriere 		.flags = PKCS11_CKFS_TOKEN_PRESENT,
141ce94efefSEtienne Carriere 		.hardware_version = PKCS11_SLOT_HW_VERSION,
142ce94efefSEtienne Carriere 		.firmware_version = PKCS11_SLOT_FW_VERSION,
143ce94efefSEtienne Carriere 	};
144ce94efefSEtienne Carriere 
145ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <=
146ce94efefSEtienne Carriere 			    sizeof(info.slot_description));
147ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <=
148ce94efefSEtienne Carriere 			    sizeof(info.manufacturer_id));
149ce94efefSEtienne Carriere 
150ce94efefSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
151ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
152ce94efefSEtienne Carriere 
153ce94efefSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
154ce94efefSEtienne Carriere 
155ce94efefSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
156ce94efefSEtienne Carriere 	if (rv)
157ce94efefSEtienne Carriere 		return rv;
158ce94efefSEtienne Carriere 
159ce94efefSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
160ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
161ce94efefSEtienne Carriere 
162ce94efefSEtienne Carriere 	token = get_token(token_id);
163ce94efefSEtienne Carriere 	if (!token)
164ce94efefSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
165ce94efefSEtienne Carriere 
166b3ac5035SEtienne Carriere 	pad_str(info.slot_description, sizeof(info.slot_description));
167b3ac5035SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
168ce94efefSEtienne Carriere 
169ce94efefSEtienne Carriere 	out->memref.size = sizeof(info);
170ce94efefSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
171ce94efefSEtienne Carriere 
172ce94efefSEtienne Carriere 	return PKCS11_CKR_OK;
173ce94efefSEtienne Carriere }
174030e7392SEtienne Carriere 
175030e7392SEtienne Carriere uint32_t entry_ck_token_info(uint32_t ptypes, TEE_Param *params)
176030e7392SEtienne Carriere {
177030e7392SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
178030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
179030e7392SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
180030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
181030e7392SEtienne Carriere 	TEE_Param *ctrl = &params[0];
182030e7392SEtienne Carriere 	TEE_Param *out = &params[2];
183030e7392SEtienne Carriere 	uint32_t rv = 0;
184030e7392SEtienne Carriere 	struct serialargs ctrlargs = { };
185030e7392SEtienne Carriere 	uint32_t token_id = 0;
186030e7392SEtienne Carriere 	struct ck_token *token = NULL;
187030e7392SEtienne Carriere 	struct pkcs11_token_info info = {
188030e7392SEtienne Carriere 		.manufacturer_id = PKCS11_TOKEN_MANUFACTURER,
189030e7392SEtienne Carriere 		.model = PKCS11_TOKEN_MODEL,
190030e7392SEtienne Carriere 		.serial_number = PKCS11_TOKEN_SERIAL_NUMBER,
191030e7392SEtienne Carriere 		.max_session_count = UINT32_MAX,
192030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
193030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
194030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
195030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
196030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
197030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
198030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
199030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
200030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
201030e7392SEtienne Carriere 	};
202030e7392SEtienne Carriere 
203030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
204030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
205030e7392SEtienne Carriere 
206030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
207030e7392SEtienne Carriere 
208030e7392SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
209030e7392SEtienne Carriere 	if (rv)
210030e7392SEtienne Carriere 		return rv;
211030e7392SEtienne Carriere 
212030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
213030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
214030e7392SEtienne Carriere 
215030e7392SEtienne Carriere 	token = get_token(token_id);
216030e7392SEtienne Carriere 	if (!token)
217030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
218030e7392SEtienne Carriere 
219030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
220030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
221030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
222030e7392SEtienne Carriere 
223030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
224030e7392SEtienne Carriere 
225030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
226030e7392SEtienne Carriere 	info.session_count = token->session_count;
227030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
228030e7392SEtienne Carriere 
229030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
230030e7392SEtienne Carriere 
231030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
232030e7392SEtienne Carriere }
2336f74919dSEtienne Carriere 
2346f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
2356f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
2366f74919dSEtienne Carriere 					   size_t count __maybe_unused)
2376f74919dSEtienne Carriere {
2386f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
2396f74919dSEtienne Carriere 
2406f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
2416f74919dSEtienne Carriere 		return;
2426f74919dSEtienne Carriere 
2436f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
2446f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
2456f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
2466f74919dSEtienne Carriere }
2476f74919dSEtienne Carriere 
2486f74919dSEtienne Carriere uint32_t entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
2496f74919dSEtienne Carriere {
2506f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
2516f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
2526f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
2536f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
2546f74919dSEtienne Carriere 	TEE_Param *ctrl = &params[0];
2556f74919dSEtienne Carriere 	TEE_Param *out = &params[2];
2566f74919dSEtienne Carriere 	uint32_t rv = 0;
2576f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
2586f74919dSEtienne Carriere 	uint32_t token_id = 0;
2596f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
2606f74919dSEtienne Carriere 	size_t count = 0;
2616f74919dSEtienne Carriere 	uint32_t *array = NULL;
2626f74919dSEtienne Carriere 
2636f74919dSEtienne Carriere 	if (ptypes != exp_pt)
2646f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
2656f74919dSEtienne Carriere 
2666f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
2676f74919dSEtienne Carriere 
2686f74919dSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
2696f74919dSEtienne Carriere 	if (rv)
2706f74919dSEtienne Carriere 		return rv;
2716f74919dSEtienne Carriere 
2726f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
2736f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
2746f74919dSEtienne Carriere 
2756f74919dSEtienne Carriere 	token = get_token(token_id);
2766f74919dSEtienne Carriere 	if (!token)
2776f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
2786f74919dSEtienne Carriere 
2796f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
2806f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
2816f74919dSEtienne Carriere 
2826f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
2836f74919dSEtienne Carriere 		assert(!array);
2846f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
2856f74919dSEtienne Carriere 		return PKCS11_CKR_BUFFER_TOO_SMALL;
2866f74919dSEtienne Carriere 	}
2876f74919dSEtienne Carriere 
2886f74919dSEtienne Carriere 	if (!array)
2896f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
2906f74919dSEtienne Carriere 
2916f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
2926f74919dSEtienne Carriere 
2936f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
2946f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
2956f74919dSEtienne Carriere 
2966f74919dSEtienne Carriere 	TEE_Free(array);
2976f74919dSEtienne Carriere 
2986f74919dSEtienne Carriere 	return rv;
2996f74919dSEtienne Carriere }
300*1d3ebedbSEtienne Carriere 
301*1d3ebedbSEtienne Carriere static void supported_mechanism_key_size(uint32_t proc_id,
302*1d3ebedbSEtienne Carriere 					 uint32_t *max_key_size,
303*1d3ebedbSEtienne Carriere 					 uint32_t *min_key_size)
304*1d3ebedbSEtienne Carriere {
305*1d3ebedbSEtienne Carriere 	switch (proc_id) {
306*1d3ebedbSEtienne Carriere 	/* Will be filled once TA supports mechanisms */
307*1d3ebedbSEtienne Carriere 	default:
308*1d3ebedbSEtienne Carriere 		*min_key_size = 0;
309*1d3ebedbSEtienne Carriere 		*max_key_size = 0;
310*1d3ebedbSEtienne Carriere 		break;
311*1d3ebedbSEtienne Carriere 	}
312*1d3ebedbSEtienne Carriere }
313*1d3ebedbSEtienne Carriere 
314*1d3ebedbSEtienne Carriere uint32_t entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
315*1d3ebedbSEtienne Carriere {
316*1d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
317*1d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
318*1d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
319*1d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
320*1d3ebedbSEtienne Carriere 	TEE_Param *ctrl = &params[0];
321*1d3ebedbSEtienne Carriere 	TEE_Param *out = &params[2];
322*1d3ebedbSEtienne Carriere 	uint32_t rv = 0;
323*1d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
324*1d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
325*1d3ebedbSEtienne Carriere 	uint32_t type = 0;
326*1d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
327*1d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
328*1d3ebedbSEtienne Carriere 
329*1d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
330*1d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
331*1d3ebedbSEtienne Carriere 
332*1d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
333*1d3ebedbSEtienne Carriere 
334*1d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
335*1d3ebedbSEtienne Carriere 	if (rv)
336*1d3ebedbSEtienne Carriere 		return rv;
337*1d3ebedbSEtienne Carriere 
338*1d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
339*1d3ebedbSEtienne Carriere 	if (rv)
340*1d3ebedbSEtienne Carriere 		return rv;
341*1d3ebedbSEtienne Carriere 
342*1d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
343*1d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
344*1d3ebedbSEtienne Carriere 
345*1d3ebedbSEtienne Carriere 	token = get_token(token_id);
346*1d3ebedbSEtienne Carriere 	if (!token)
347*1d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
348*1d3ebedbSEtienne Carriere 
349*1d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
350*1d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
351*1d3ebedbSEtienne Carriere 
352*1d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
353*1d3ebedbSEtienne Carriere 
354*1d3ebedbSEtienne Carriere 	supported_mechanism_key_size(type, &info.min_key_size,
355*1d3ebedbSEtienne Carriere 				     &info.max_key_size);
356*1d3ebedbSEtienne Carriere 
357*1d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
358*1d3ebedbSEtienne Carriere 
359*1d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
360*1d3ebedbSEtienne Carriere 	     token_id, type);
361*1d3ebedbSEtienne Carriere 
362*1d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
363*1d3ebedbSEtienne Carriere }
364