xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision 29b0949a5c3f554f5d1494420fe8906a4d63a8c4)
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_helpers.h"
17ee49d9f2SEtienne Carriere #include "pkcs11_token.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 
27e084583eSEtienne Carriere /*
28e084583eSEtienne Carriere  * Structure tracking client applications
29e084583eSEtienne Carriere  *
30e084583eSEtienne Carriere  * @link - chained list of registered client applications
31e084583eSEtienne Carriere  * @sessions - list of the PKCS11 sessions opened by the client application
32e084583eSEtienne Carriere  */
33e084583eSEtienne Carriere struct pkcs11_client {
34e084583eSEtienne Carriere 	TAILQ_ENTRY(pkcs11_client) link;
35e084583eSEtienne Carriere 	struct session_list session_list;
36e084583eSEtienne Carriere 	struct handle_db session_handle_db;
37e084583eSEtienne Carriere };
38e084583eSEtienne 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 
42e084583eSEtienne Carriere static struct client_list pkcs11_client_list =
43e084583eSEtienne Carriere 	TAILQ_HEAD_INITIALIZER(pkcs11_client_list);
44e084583eSEtienne Carriere 
456e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session);
466e4f8f17SEtienne Carriere 
47c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id)
48c84ccd0aSEtienne Carriere {
49d38f9635SEtienne Carriere 	if (token_id < TOKEN_COUNT)
50d38f9635SEtienne Carriere 		return &ck_token[confine_array_index(token_id, TOKEN_COUNT)];
51c84ccd0aSEtienne Carriere 
52d38f9635SEtienne Carriere 	return NULL;
53c84ccd0aSEtienne Carriere }
54c84ccd0aSEtienne Carriere 
55c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token)
56c84ccd0aSEtienne Carriere {
57c84ccd0aSEtienne Carriere 	ptrdiff_t id = token - ck_token;
58c84ccd0aSEtienne Carriere 
59c84ccd0aSEtienne Carriere 	assert(id >= 0 && id < TOKEN_COUNT);
60c84ccd0aSEtienne Carriere 	return id;
61c84ccd0aSEtienne Carriere }
62c84ccd0aSEtienne Carriere 
63e084583eSEtienne Carriere struct pkcs11_client *tee_session2client(void *tee_session)
64e084583eSEtienne Carriere {
65e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
66e084583eSEtienne Carriere 
67e084583eSEtienne Carriere 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
68e084583eSEtienne Carriere 		if (client == tee_session)
69e084583eSEtienne Carriere 			break;
70e084583eSEtienne Carriere 
71e084583eSEtienne Carriere 	return client;
72e084583eSEtienne Carriere }
73e084583eSEtienne Carriere 
746e4f8f17SEtienne Carriere struct pkcs11_session *pkcs11_handle2session(uint32_t handle,
756e4f8f17SEtienne Carriere 					     struct pkcs11_client *client)
766e4f8f17SEtienne Carriere {
776e4f8f17SEtienne Carriere 	return handle_lookup(&client->session_handle_db, handle);
786e4f8f17SEtienne Carriere }
796e4f8f17SEtienne Carriere 
80e084583eSEtienne Carriere struct pkcs11_client *register_client(void)
81e084583eSEtienne Carriere {
82e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
83e084583eSEtienne Carriere 
84e084583eSEtienne Carriere 	client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO);
85e084583eSEtienne Carriere 	if (!client)
86e084583eSEtienne Carriere 		return NULL;
87e084583eSEtienne Carriere 
88e084583eSEtienne Carriere 	TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link);
89e084583eSEtienne Carriere 	TAILQ_INIT(&client->session_list);
90e084583eSEtienne Carriere 	handle_db_init(&client->session_handle_db);
91e084583eSEtienne Carriere 
92e084583eSEtienne Carriere 	return client;
93e084583eSEtienne Carriere }
94e084583eSEtienne Carriere 
95e084583eSEtienne Carriere void unregister_client(struct pkcs11_client *client)
96e084583eSEtienne Carriere {
976e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
986e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
996e4f8f17SEtienne Carriere 
100e084583eSEtienne Carriere 	if (!client) {
101e084583eSEtienne Carriere 		EMSG("Invalid TEE session handle");
102e084583eSEtienne Carriere 		return;
103e084583eSEtienne Carriere 	}
104e084583eSEtienne Carriere 
1056e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
1066e4f8f17SEtienne Carriere 		close_ck_session(session);
1076e4f8f17SEtienne Carriere 
108e084583eSEtienne Carriere 	TAILQ_REMOVE(&pkcs11_client_list, client, link);
109e084583eSEtienne Carriere 	handle_db_destroy(&client->session_handle_db);
110e084583eSEtienne Carriere 	TEE_Free(client);
111e084583eSEtienne Carriere }
112e084583eSEtienne Carriere 
113c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id)
114c84ccd0aSEtienne Carriere {
115c84ccd0aSEtienne Carriere 	struct ck_token *token = init_persistent_db(id);
116c84ccd0aSEtienne Carriere 
117c84ccd0aSEtienne Carriere 	if (!token)
118c84ccd0aSEtienne Carriere 		return TEE_ERROR_SECURITY;
119c84ccd0aSEtienne Carriere 
120c84ccd0aSEtienne Carriere 	if (token->state == PKCS11_TOKEN_RESET) {
121c84ccd0aSEtienne Carriere 		/* As per PKCS#11 spec, token resets to read/write state */
122c84ccd0aSEtienne Carriere 		token->state = PKCS11_TOKEN_READ_WRITE;
123c84ccd0aSEtienne Carriere 		token->session_count = 0;
124c84ccd0aSEtienne Carriere 		token->rw_session_count = 0;
125c84ccd0aSEtienne Carriere 	}
126c84ccd0aSEtienne Carriere 
127c84ccd0aSEtienne Carriere 	return TEE_SUCCESS;
128c84ccd0aSEtienne Carriere }
129c84ccd0aSEtienne Carriere 
130c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void)
131c84ccd0aSEtienne Carriere {
132c84ccd0aSEtienne Carriere 	unsigned int id = 0;
133c84ccd0aSEtienne Carriere 	TEE_Result ret = TEE_ERROR_GENERIC;
134c84ccd0aSEtienne Carriere 
135c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++) {
136c84ccd0aSEtienne Carriere 		ret = pkcs11_token_init(id);
137c84ccd0aSEtienne Carriere 		if (ret)
138e084583eSEtienne Carriere 			break;
139c84ccd0aSEtienne Carriere 	}
140c84ccd0aSEtienne Carriere 
141c84ccd0aSEtienne Carriere 	return ret;
142c84ccd0aSEtienne Carriere }
143c84ccd0aSEtienne Carriere 
144c84ccd0aSEtienne Carriere void pkcs11_deinit(void)
145c84ccd0aSEtienne Carriere {
146c84ccd0aSEtienne Carriere 	unsigned int id = 0;
147c84ccd0aSEtienne Carriere 
148c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++)
149c84ccd0aSEtienne Carriere 		close_persistent_db(get_token(id));
150c84ccd0aSEtienne Carriere }
15122ac6984SEtienne Carriere 
15222ac6984SEtienne Carriere uint32_t entry_ck_slot_list(uint32_t ptypes, TEE_Param *params)
15322ac6984SEtienne Carriere {
15422ac6984SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
15522ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
15622ac6984SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
15722ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
15822ac6984SEtienne Carriere 	TEE_Param *out = &params[2];
15922ac6984SEtienne Carriere 	uint32_t token_id = 0;
16022ac6984SEtienne Carriere 	const size_t out_size = sizeof(token_id) * TOKEN_COUNT;
16122ac6984SEtienne Carriere 	uint8_t *id = NULL;
16222ac6984SEtienne Carriere 
16322ac6984SEtienne Carriere 	if (ptypes != exp_pt ||
16422ac6984SEtienne Carriere 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN)
16522ac6984SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
16622ac6984SEtienne Carriere 
16722ac6984SEtienne Carriere 	if (out->memref.size < out_size) {
16822ac6984SEtienne Carriere 		out->memref.size = out_size;
16922ac6984SEtienne Carriere 
17022ac6984SEtienne Carriere 		if (out->memref.buffer)
17122ac6984SEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
17222ac6984SEtienne Carriere 		else
17322ac6984SEtienne Carriere 			return PKCS11_CKR_OK;
17422ac6984SEtienne Carriere 	}
17522ac6984SEtienne Carriere 
17622ac6984SEtienne Carriere 	for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT;
17722ac6984SEtienne Carriere 	     token_id++, id += sizeof(token_id))
17822ac6984SEtienne Carriere 		TEE_MemMove(id, &token_id, sizeof(token_id));
17922ac6984SEtienne Carriere 
18022ac6984SEtienne Carriere 	out->memref.size = out_size;
18122ac6984SEtienne Carriere 
18222ac6984SEtienne Carriere 	return PKCS11_CKR_OK;
18322ac6984SEtienne Carriere }
184ce94efefSEtienne Carriere 
185b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size)
186b3ac5035SEtienne Carriere {
187b3ac5035SEtienne Carriere 	int n = strnlen((char *)str, size);
188b3ac5035SEtienne Carriere 
189b3ac5035SEtienne Carriere 	TEE_MemFill(str + n, ' ', size - n);
190b3ac5035SEtienne Carriere }
191b3ac5035SEtienne Carriere 
192ce94efefSEtienne Carriere uint32_t entry_ck_slot_info(uint32_t ptypes, TEE_Param *params)
193ce94efefSEtienne Carriere {
194ce94efefSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
195ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
196ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
197ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
198ce94efefSEtienne Carriere 	TEE_Param *ctrl = &params[0];
199ce94efefSEtienne Carriere 	TEE_Param *out = &params[2];
200ce94efefSEtienne Carriere 	uint32_t rv = 0;
201ce94efefSEtienne Carriere 	struct serialargs ctrlargs = { };
202ce94efefSEtienne Carriere 	uint32_t token_id = 0;
203ce94efefSEtienne Carriere 	struct pkcs11_slot_info info = {
204ce94efefSEtienne Carriere 		.slot_description = PKCS11_SLOT_DESCRIPTION,
205ce94efefSEtienne Carriere 		.manufacturer_id = PKCS11_SLOT_MANUFACTURER,
206ce94efefSEtienne Carriere 		.flags = PKCS11_CKFS_TOKEN_PRESENT,
207ce94efefSEtienne Carriere 		.hardware_version = PKCS11_SLOT_HW_VERSION,
208ce94efefSEtienne Carriere 		.firmware_version = PKCS11_SLOT_FW_VERSION,
209ce94efefSEtienne Carriere 	};
210ce94efefSEtienne Carriere 
211ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <=
212ce94efefSEtienne Carriere 			    sizeof(info.slot_description));
213ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <=
214ce94efefSEtienne Carriere 			    sizeof(info.manufacturer_id));
215ce94efefSEtienne Carriere 
216ce94efefSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
217ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
218ce94efefSEtienne Carriere 
219ce94efefSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
220ce94efefSEtienne Carriere 
221ce94efefSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
222ce94efefSEtienne Carriere 	if (rv)
223ce94efefSEtienne Carriere 		return rv;
224ce94efefSEtienne Carriere 
225ce94efefSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
226ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
227ce94efefSEtienne Carriere 
228*29b0949aSEtienne Carriere 	if (!get_token(token_id))
229ce94efefSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
230ce94efefSEtienne Carriere 
231b3ac5035SEtienne Carriere 	pad_str(info.slot_description, sizeof(info.slot_description));
232b3ac5035SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
233ce94efefSEtienne Carriere 
234ce94efefSEtienne Carriere 	out->memref.size = sizeof(info);
235ce94efefSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
236ce94efefSEtienne Carriere 
237ce94efefSEtienne Carriere 	return PKCS11_CKR_OK;
238ce94efefSEtienne Carriere }
239030e7392SEtienne Carriere 
240030e7392SEtienne Carriere uint32_t entry_ck_token_info(uint32_t ptypes, TEE_Param *params)
241030e7392SEtienne Carriere {
242030e7392SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
243030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
244030e7392SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
245030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
246030e7392SEtienne Carriere 	TEE_Param *ctrl = &params[0];
247030e7392SEtienne Carriere 	TEE_Param *out = &params[2];
248030e7392SEtienne Carriere 	uint32_t rv = 0;
249030e7392SEtienne Carriere 	struct serialargs ctrlargs = { };
250030e7392SEtienne Carriere 	uint32_t token_id = 0;
251030e7392SEtienne Carriere 	struct ck_token *token = NULL;
252030e7392SEtienne Carriere 	struct pkcs11_token_info info = {
253030e7392SEtienne Carriere 		.manufacturer_id = PKCS11_TOKEN_MANUFACTURER,
254030e7392SEtienne Carriere 		.model = PKCS11_TOKEN_MODEL,
255030e7392SEtienne Carriere 		.serial_number = PKCS11_TOKEN_SERIAL_NUMBER,
256030e7392SEtienne Carriere 		.max_session_count = UINT32_MAX,
257030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
258030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
259030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
260030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
261030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
262030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
263030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
264030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
265030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
266030e7392SEtienne Carriere 	};
267030e7392SEtienne Carriere 
268030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
269030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
270030e7392SEtienne Carriere 
271030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
272030e7392SEtienne Carriere 
273030e7392SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
274030e7392SEtienne Carriere 	if (rv)
275030e7392SEtienne Carriere 		return rv;
276030e7392SEtienne Carriere 
277030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
278030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
279030e7392SEtienne Carriere 
280030e7392SEtienne Carriere 	token = get_token(token_id);
281030e7392SEtienne Carriere 	if (!token)
282030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
283030e7392SEtienne Carriere 
284030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
285030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
286030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
287030e7392SEtienne Carriere 
288030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
289030e7392SEtienne Carriere 
290030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
291030e7392SEtienne Carriere 	info.session_count = token->session_count;
292030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
293030e7392SEtienne Carriere 
294030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
295030e7392SEtienne Carriere 
296030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
297030e7392SEtienne Carriere }
2986f74919dSEtienne Carriere 
2996f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
3006f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
3016f74919dSEtienne Carriere 					   size_t count __maybe_unused)
3026f74919dSEtienne Carriere {
3036f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
3046f74919dSEtienne Carriere 
3056f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
3066f74919dSEtienne Carriere 		return;
3076f74919dSEtienne Carriere 
3086f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
3096f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
3106f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
3116f74919dSEtienne Carriere }
3126f74919dSEtienne Carriere 
3136f74919dSEtienne Carriere uint32_t entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
3146f74919dSEtienne Carriere {
3156f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3166f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3176f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3186f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3196f74919dSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3206f74919dSEtienne Carriere 	TEE_Param *out = &params[2];
3216f74919dSEtienne Carriere 	uint32_t rv = 0;
3226f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
3236f74919dSEtienne Carriere 	uint32_t token_id = 0;
3246f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
3256f74919dSEtienne Carriere 	size_t count = 0;
3266f74919dSEtienne Carriere 	uint32_t *array = NULL;
3276f74919dSEtienne Carriere 
3286f74919dSEtienne Carriere 	if (ptypes != exp_pt)
3296f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3306f74919dSEtienne Carriere 
3316f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
3326f74919dSEtienne Carriere 
3336f74919dSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3346f74919dSEtienne Carriere 	if (rv)
3356f74919dSEtienne Carriere 		return rv;
3366f74919dSEtienne Carriere 
3376f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
3386f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3396f74919dSEtienne Carriere 
3406f74919dSEtienne Carriere 	token = get_token(token_id);
3416f74919dSEtienne Carriere 	if (!token)
3426f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
3436f74919dSEtienne Carriere 
3446f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
3456f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
3466f74919dSEtienne Carriere 
3476f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
3486f74919dSEtienne Carriere 		assert(!array);
3496f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
3506459f267SEtienne Carriere 		if (out->memref.buffer)
3516f74919dSEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
3526459f267SEtienne Carriere 		else
3536459f267SEtienne Carriere 			return PKCS11_CKR_OK;
3546f74919dSEtienne Carriere 	}
3556f74919dSEtienne Carriere 
3566f74919dSEtienne Carriere 	if (!array)
3576f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
3586f74919dSEtienne Carriere 
3596f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
3606f74919dSEtienne Carriere 
3616f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
3626f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
3636f74919dSEtienne Carriere 
3646f74919dSEtienne Carriere 	TEE_Free(array);
3656f74919dSEtienne Carriere 
3666f74919dSEtienne Carriere 	return rv;
3676f74919dSEtienne Carriere }
3681d3ebedbSEtienne Carriere 
3691d3ebedbSEtienne Carriere static void supported_mechanism_key_size(uint32_t proc_id,
3701d3ebedbSEtienne Carriere 					 uint32_t *max_key_size,
3711d3ebedbSEtienne Carriere 					 uint32_t *min_key_size)
3721d3ebedbSEtienne Carriere {
3731d3ebedbSEtienne Carriere 	switch (proc_id) {
3741d3ebedbSEtienne Carriere 	/* Will be filled once TA supports mechanisms */
3751d3ebedbSEtienne Carriere 	default:
3761d3ebedbSEtienne Carriere 		*min_key_size = 0;
3771d3ebedbSEtienne Carriere 		*max_key_size = 0;
3781d3ebedbSEtienne Carriere 		break;
3791d3ebedbSEtienne Carriere 	}
3801d3ebedbSEtienne Carriere }
3811d3ebedbSEtienne Carriere 
3821d3ebedbSEtienne Carriere uint32_t entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
3831d3ebedbSEtienne Carriere {
3841d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3851d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3861d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3871d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3881d3ebedbSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3891d3ebedbSEtienne Carriere 	TEE_Param *out = &params[2];
3901d3ebedbSEtienne Carriere 	uint32_t rv = 0;
3911d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
3921d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
3931d3ebedbSEtienne Carriere 	uint32_t type = 0;
3941d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
3951d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
3961d3ebedbSEtienne Carriere 
3971d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
3981d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3991d3ebedbSEtienne Carriere 
4001d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
4011d3ebedbSEtienne Carriere 
4021d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
4031d3ebedbSEtienne Carriere 	if (rv)
4041d3ebedbSEtienne Carriere 		return rv;
4051d3ebedbSEtienne Carriere 
4061d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
4071d3ebedbSEtienne Carriere 	if (rv)
4081d3ebedbSEtienne Carriere 		return rv;
4091d3ebedbSEtienne Carriere 
4101d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
4111d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4121d3ebedbSEtienne Carriere 
4131d3ebedbSEtienne Carriere 	token = get_token(token_id);
4141d3ebedbSEtienne Carriere 	if (!token)
4151d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4161d3ebedbSEtienne Carriere 
4171d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
4181d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
4191d3ebedbSEtienne Carriere 
4201d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
4211d3ebedbSEtienne Carriere 
4221d3ebedbSEtienne Carriere 	supported_mechanism_key_size(type, &info.min_key_size,
4231d3ebedbSEtienne Carriere 				     &info.max_key_size);
4241d3ebedbSEtienne Carriere 
4251d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
4261d3ebedbSEtienne Carriere 
4271d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
4281d3ebedbSEtienne Carriere 	     token_id, type);
4291d3ebedbSEtienne Carriere 
4301d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
4311d3ebedbSEtienne Carriere }
4326e4f8f17SEtienne Carriere 
4336e4f8f17SEtienne Carriere /* Select the ReadOnly or ReadWrite state for session login state */
4346e4f8f17SEtienne Carriere static void set_session_state(struct pkcs11_client *client,
4356e4f8f17SEtienne Carriere 			      struct pkcs11_session *session, bool readonly)
4366e4f8f17SEtienne Carriere {
4376e4f8f17SEtienne Carriere 	struct pkcs11_session *sess = NULL;
4386e4f8f17SEtienne Carriere 	enum pkcs11_session_state state = PKCS11_CKS_RO_PUBLIC_SESSION;
4396e4f8f17SEtienne Carriere 
4406e4f8f17SEtienne Carriere 	/* Default to public session if no session already registered */
4416e4f8f17SEtienne Carriere 	if (readonly)
4426e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RO_PUBLIC_SESSION;
4436e4f8f17SEtienne Carriere 	else
4446e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RW_PUBLIC_SESSION;
4456e4f8f17SEtienne Carriere 
4466e4f8f17SEtienne Carriere 	/*
4476e4f8f17SEtienne Carriere 	 * No need to check all client sessions, the first found in
4486e4f8f17SEtienne Carriere 	 * target token gives client login configuration.
4496e4f8f17SEtienne Carriere 	 */
4506e4f8f17SEtienne Carriere 	TAILQ_FOREACH(sess, &client->session_list, link) {
4516e4f8f17SEtienne Carriere 		assert(sess != session);
4526e4f8f17SEtienne Carriere 
4536e4f8f17SEtienne Carriere 		if (sess->token == session->token) {
4546e4f8f17SEtienne Carriere 			switch (sess->state) {
4556e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_PUBLIC_SESSION:
4566e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_PUBLIC_SESSION:
4576e4f8f17SEtienne Carriere 				if (readonly)
4586e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_PUBLIC_SESSION;
4596e4f8f17SEtienne Carriere 				else
4606e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_PUBLIC_SESSION;
4616e4f8f17SEtienne Carriere 				break;
4626e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_USER_FUNCTIONS:
4636e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_USER_FUNCTIONS:
4646e4f8f17SEtienne Carriere 				if (readonly)
4656e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_USER_FUNCTIONS;
4666e4f8f17SEtienne Carriere 				else
4676e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_USER_FUNCTIONS;
4686e4f8f17SEtienne Carriere 				break;
4696e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_SO_FUNCTIONS:
4706e4f8f17SEtienne Carriere 				if (readonly)
4716e4f8f17SEtienne Carriere 					TEE_Panic(0);
4726e4f8f17SEtienne Carriere 				else
4736e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_SO_FUNCTIONS;
4746e4f8f17SEtienne Carriere 				break;
4756e4f8f17SEtienne Carriere 			default:
4766e4f8f17SEtienne Carriere 				TEE_Panic(0);
4776e4f8f17SEtienne Carriere 			}
4786e4f8f17SEtienne Carriere 			break;
4796e4f8f17SEtienne Carriere 		}
4806e4f8f17SEtienne Carriere 	}
4816e4f8f17SEtienne Carriere 
4826e4f8f17SEtienne Carriere 	session->state = state;
4836e4f8f17SEtienne Carriere }
4846e4f8f17SEtienne Carriere 
4856e4f8f17SEtienne Carriere uint32_t entry_ck_open_session(struct pkcs11_client *client,
4866e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
4876e4f8f17SEtienne Carriere {
4886e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4896e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4906e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4916e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
4926e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
4936e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
4946e4f8f17SEtienne Carriere 	uint32_t rv = 0;
4956e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
4966e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
4976e4f8f17SEtienne Carriere 	uint32_t flags = 0;
4986e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
4996e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
5006e4f8f17SEtienne Carriere 	bool readonly = false;
5016e4f8f17SEtienne Carriere 
5026e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt ||
5036e4f8f17SEtienne Carriere 	    out->memref.size != sizeof(session->handle))
5046e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5056e4f8f17SEtienne Carriere 
5066e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
5076e4f8f17SEtienne Carriere 
5086e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
5096e4f8f17SEtienne Carriere 	if (rv)
5106e4f8f17SEtienne Carriere 		return rv;
5116e4f8f17SEtienne Carriere 
5126e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &flags, sizeof(flags));
5136e4f8f17SEtienne Carriere 	if (rv)
5146e4f8f17SEtienne Carriere 		return rv;
5156e4f8f17SEtienne Carriere 
5166e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
5176e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5186e4f8f17SEtienne Carriere 
5196e4f8f17SEtienne Carriere 	token = get_token(token_id);
5206e4f8f17SEtienne Carriere 	if (!token)
5216e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
5226e4f8f17SEtienne Carriere 
5236e4f8f17SEtienne Carriere 	/* Sanitize session flags */
5246e4f8f17SEtienne Carriere 	if (!(flags & PKCS11_CKFSS_SERIAL_SESSION) ||
5256e4f8f17SEtienne Carriere 	    (flags & ~(PKCS11_CKFSS_RW_SESSION |
5266e4f8f17SEtienne Carriere 		       PKCS11_CKFSS_SERIAL_SESSION)))
5276e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5286e4f8f17SEtienne Carriere 
5296e4f8f17SEtienne Carriere 	readonly = !(flags & PKCS11_CKFSS_RW_SESSION);
5306e4f8f17SEtienne Carriere 
5316e4f8f17SEtienne Carriere 	if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY)
5326e4f8f17SEtienne Carriere 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
5336e4f8f17SEtienne Carriere 
5346e4f8f17SEtienne Carriere 	if (readonly) {
5356e4f8f17SEtienne Carriere 		/* Specifically reject read-only session under SO login */
5366e4f8f17SEtienne Carriere 		TAILQ_FOREACH(session, &client->session_list, link)
5376e4f8f17SEtienne Carriere 			if (pkcs11_session_is_so(session))
5386e4f8f17SEtienne Carriere 				return PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS;
5396e4f8f17SEtienne Carriere 	}
5406e4f8f17SEtienne Carriere 
5416e4f8f17SEtienne Carriere 	session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO);
5426e4f8f17SEtienne Carriere 	if (!session)
5436e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5446e4f8f17SEtienne Carriere 
5456e4f8f17SEtienne Carriere 	session->handle = handle_get(&client->session_handle_db, session);
5466e4f8f17SEtienne Carriere 	if (!session->handle) {
5476e4f8f17SEtienne Carriere 		TEE_Free(session);
5486e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5496e4f8f17SEtienne Carriere 	}
5506e4f8f17SEtienne Carriere 
5516e4f8f17SEtienne Carriere 	session->token = token;
5526e4f8f17SEtienne Carriere 	session->client = client;
5536e4f8f17SEtienne Carriere 
5546e4f8f17SEtienne Carriere 	set_session_state(client, session, readonly);
5556e4f8f17SEtienne Carriere 
5566e4f8f17SEtienne Carriere 	TAILQ_INSERT_HEAD(&client->session_list, session, link);
5576e4f8f17SEtienne Carriere 
5586e4f8f17SEtienne Carriere 	session->token->session_count++;
5596e4f8f17SEtienne Carriere 	if (!readonly)
5606e4f8f17SEtienne Carriere 		session->token->rw_session_count++;
5616e4f8f17SEtienne Carriere 
5626e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &session->handle,
5636e4f8f17SEtienne Carriere 		    sizeof(session->handle));
5646e4f8f17SEtienne Carriere 
5656e4f8f17SEtienne Carriere 	DMSG("Open PKCS11 session %"PRIu32, session->handle);
5666e4f8f17SEtienne Carriere 
5676e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
5686e4f8f17SEtienne Carriere }
5696e4f8f17SEtienne Carriere 
5706e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session)
5716e4f8f17SEtienne Carriere {
5726e4f8f17SEtienne Carriere 	TAILQ_REMOVE(&session->client->session_list, session, link);
5736e4f8f17SEtienne Carriere 	handle_put(&session->client->session_handle_db, session->handle);
5746e4f8f17SEtienne Carriere 
5756e4f8f17SEtienne Carriere 	session->token->session_count--;
5766e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
5776e4f8f17SEtienne Carriere 		session->token->rw_session_count--;
5786e4f8f17SEtienne Carriere 
5796e4f8f17SEtienne Carriere 	TEE_Free(session);
5806e4f8f17SEtienne Carriere 
5816e4f8f17SEtienne Carriere 	DMSG("Close PKCS11 session %"PRIu32, session->handle);
5826e4f8f17SEtienne Carriere }
5836e4f8f17SEtienne Carriere 
5846e4f8f17SEtienne Carriere uint32_t entry_ck_close_session(struct pkcs11_client *client,
5856e4f8f17SEtienne Carriere 				uint32_t ptypes, TEE_Param *params)
5866e4f8f17SEtienne Carriere {
5876e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
5886e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
5896e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
5906e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
5916e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
5926e4f8f17SEtienne Carriere 	uint32_t rv = 0;
5936e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
5946e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
5956e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
5966e4f8f17SEtienne Carriere 
5976e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
5986e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5996e4f8f17SEtienne Carriere 
6006e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6016e4f8f17SEtienne Carriere 
6026e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
6036e4f8f17SEtienne Carriere 	if (rv)
6046e4f8f17SEtienne Carriere 		return rv;
6056e4f8f17SEtienne Carriere 
6066e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6076e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6086e4f8f17SEtienne Carriere 
6096e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
6106e4f8f17SEtienne Carriere 	if (!session)
6116e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
6126e4f8f17SEtienne Carriere 
6136e4f8f17SEtienne Carriere 	close_ck_session(session);
6146e4f8f17SEtienne Carriere 
6156e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6166e4f8f17SEtienne Carriere }
6176e4f8f17SEtienne Carriere 
6186e4f8f17SEtienne Carriere uint32_t entry_ck_close_all_sessions(struct pkcs11_client *client,
6196e4f8f17SEtienne Carriere 				     uint32_t ptypes, TEE_Param *params)
6206e4f8f17SEtienne Carriere {
6216e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6226e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6236e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6246e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6256e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6266e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6276e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6286e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
6296e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
6306e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6316e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
6326e4f8f17SEtienne Carriere 
6336e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6346e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6356e4f8f17SEtienne Carriere 
6366e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6376e4f8f17SEtienne Carriere 
6386e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
6396e4f8f17SEtienne Carriere 	if (rv)
6406e4f8f17SEtienne Carriere 		return rv;
6416e4f8f17SEtienne Carriere 
6426e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6436e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6446e4f8f17SEtienne Carriere 
6456e4f8f17SEtienne Carriere 	token = get_token(token_id);
6466e4f8f17SEtienne Carriere 	if (!token)
6476e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
6486e4f8f17SEtienne Carriere 
6496e4f8f17SEtienne Carriere 	DMSG("Close all sessions for PKCS11 token %"PRIu32, token_id);
6506e4f8f17SEtienne Carriere 
6516e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
6526e4f8f17SEtienne Carriere 		if (session->token == token)
6536e4f8f17SEtienne Carriere 			close_ck_session(session);
6546e4f8f17SEtienne Carriere 
6556e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6566e4f8f17SEtienne Carriere }
6576e4f8f17SEtienne Carriere 
6586e4f8f17SEtienne Carriere uint32_t entry_ck_session_info(struct pkcs11_client *client,
6596e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
6606e4f8f17SEtienne Carriere {
6616e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6626e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6636e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
6646e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6656e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6666e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
6676e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6686e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6696e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
6706e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6716e4f8f17SEtienne Carriere 	struct pkcs11_session_info info = {
6726e4f8f17SEtienne Carriere 		.flags = PKCS11_CKFSS_SERIAL_SESSION,
6736e4f8f17SEtienne Carriere 	};
6746e4f8f17SEtienne Carriere 
6756e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt || out->memref.size != sizeof(info))
6766e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6776e4f8f17SEtienne Carriere 
6786e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6796e4f8f17SEtienne Carriere 
6806e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
6816e4f8f17SEtienne Carriere 	if (rv)
6826e4f8f17SEtienne Carriere 		return rv;
6836e4f8f17SEtienne Carriere 
6846e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6856e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6866e4f8f17SEtienne Carriere 
6876e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
6886e4f8f17SEtienne Carriere 	if (!session)
6896e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
6906e4f8f17SEtienne Carriere 
6916e4f8f17SEtienne Carriere 	info.slot_id = get_token_id(session->token);
6926e4f8f17SEtienne Carriere 	info.state = session->state;
6936e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
6946e4f8f17SEtienne Carriere 		info.flags |= PKCS11_CKFSS_RW_SESSION;
6956e4f8f17SEtienne Carriere 
6966e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
6976e4f8f17SEtienne Carriere 
6986e4f8f17SEtienne Carriere 	DMSG("Get find on PKCS11 session %"PRIu32, session->handle);
6996e4f8f17SEtienne Carriere 
7006e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7016e4f8f17SEtienne Carriere }
702f485be04SJens Wiklander 
703f485be04SJens Wiklander uint32_t entry_ck_token_initialize(uint32_t ptypes, TEE_Param *params)
704f485be04SJens Wiklander {
705f485be04SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
706f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
707f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
708f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE);
709f485be04SJens Wiklander 	char label[PKCS11_TOKEN_LABEL_SIZE] = { 0 };
710f485be04SJens Wiklander 	struct pkcs11_client *client = NULL;
711f485be04SJens Wiklander 	struct pkcs11_session *sess = NULL;
712f485be04SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
713f485be04SJens Wiklander 	struct serialargs ctrlargs = { };
714f485be04SJens Wiklander 	struct ck_token *token = NULL;
715f485be04SJens Wiklander 	TEE_Param *ctrl = params;
716f485be04SJens Wiklander 	uint32_t token_id = 0;
717f485be04SJens Wiklander 	uint32_t pin_size = 0;
718f485be04SJens Wiklander 	void *pin = NULL;
719f485be04SJens Wiklander 
720f485be04SJens Wiklander 	if (ptypes != exp_pt)
721f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
722f485be04SJens Wiklander 
723f485be04SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
724f485be04SJens Wiklander 
725f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
726f485be04SJens Wiklander 	if (rc)
727f485be04SJens Wiklander 		return rc;
728f485be04SJens Wiklander 
729f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
730f485be04SJens Wiklander 	if (rc)
731f485be04SJens Wiklander 		return rc;
732f485be04SJens Wiklander 
733f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &label, PKCS11_TOKEN_LABEL_SIZE);
734f485be04SJens Wiklander 	if (rc)
735f485be04SJens Wiklander 		return rc;
736f485be04SJens Wiklander 
737f485be04SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
738f485be04SJens Wiklander 	if (rc)
739f485be04SJens Wiklander 		return rc;
740f485be04SJens Wiklander 
741f485be04SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
742f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
743f485be04SJens Wiklander 
744f485be04SJens Wiklander 	token = get_token(token_id);
745f485be04SJens Wiklander 	if (!token)
746f485be04SJens Wiklander 		return PKCS11_CKR_SLOT_ID_INVALID;
747f485be04SJens Wiklander 
748f485be04SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) {
749f485be04SJens Wiklander 		IMSG("Token %"PRIu32": SO PIN locked", token_id);
750f485be04SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
751f485be04SJens Wiklander 	}
752f485be04SJens Wiklander 
753f485be04SJens Wiklander 	/* Check there's no open session on this token */
754f485be04SJens Wiklander 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
755f485be04SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
756f485be04SJens Wiklander 			if (sess->token == token)
757f485be04SJens Wiklander 				return PKCS11_CKR_SESSION_EXISTS;
758f485be04SJens Wiklander 
759f485be04SJens Wiklander 	if (!token->db_main->so_pin_salt) {
760f485be04SJens Wiklander 		/*
761f485be04SJens Wiklander 		 * The spec doesn't permit returning
762f485be04SJens Wiklander 		 * PKCS11_CKR_PIN_LEN_RANGE for this function, take another
763f485be04SJens Wiklander 		 * error code.
764f485be04SJens Wiklander 		 */
765f485be04SJens Wiklander 		if (pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
766f485be04SJens Wiklander 		    pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
767f485be04SJens Wiklander 			return PKCS11_CKR_ARGUMENTS_BAD;
768f485be04SJens Wiklander 
769f485be04SJens Wiklander 		rc = hash_pin(PKCS11_CKU_SO, pin, pin_size,
770f485be04SJens Wiklander 			      &token->db_main->so_pin_salt,
771f485be04SJens Wiklander 			      token->db_main->so_pin_hash);
772f485be04SJens Wiklander 		if (rc)
773f485be04SJens Wiklander 			return rc;
774f485be04SJens Wiklander 
775f485be04SJens Wiklander 		update_persistent_db(token);
776f485be04SJens Wiklander 
777f485be04SJens Wiklander 		goto inited;
778f485be04SJens Wiklander 	}
779f485be04SJens Wiklander 
780f485be04SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
781f485be04SJens Wiklander 			token->db_main->so_pin_salt,
782f485be04SJens Wiklander 			token->db_main->so_pin_hash);
783f485be04SJens Wiklander 	if (rc) {
784f485be04SJens Wiklander 		unsigned int pin_count = 0;
785f485be04SJens Wiklander 
786f485be04SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
787f485be04SJens Wiklander 			return rc;
788f485be04SJens Wiklander 
789f485be04SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
790f485be04SJens Wiklander 		token->db_main->so_pin_count++;
791f485be04SJens Wiklander 
792f485be04SJens Wiklander 		pin_count = token->db_main->so_pin_count;
793f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
794f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
795f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
796f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
797f485be04SJens Wiklander 
798f485be04SJens Wiklander 		update_persistent_db(token);
799f485be04SJens Wiklander 
800f485be04SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
801f485be04SJens Wiklander 	}
802f485be04SJens Wiklander 
803f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
804f485be04SJens Wiklander 				   PKCS11_CKFT_SO_PIN_FINAL_TRY);
805f485be04SJens Wiklander 	token->db_main->so_pin_count = 0;
806f485be04SJens Wiklander 
807f485be04SJens Wiklander inited:
808f485be04SJens Wiklander 	TEE_MemMove(token->db_main->label, label, PKCS11_TOKEN_LABEL_SIZE);
809f485be04SJens Wiklander 	token->db_main->flags |= PKCS11_CKFT_TOKEN_INITIALIZED;
810f485be04SJens Wiklander 	/* Reset user PIN */
811f485be04SJens Wiklander 	token->db_main->user_pin_salt = 0;
812f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_INITIALIZED |
813f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_COUNT_LOW |
814f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_FINAL_TRY |
815f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_LOCKED |
816f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_TO_BE_CHANGED);
817f485be04SJens Wiklander 
818f485be04SJens Wiklander 	update_persistent_db(token);
819f485be04SJens Wiklander 
820f485be04SJens Wiklander 	IMSG("PKCS11 token %"PRIu32": initialized", token_id);
821f485be04SJens Wiklander 
822f485be04SJens Wiklander 	return PKCS11_CKR_OK;
823f485be04SJens Wiklander }
824e8dbd92cSJens Wiklander 
825e8dbd92cSJens Wiklander static enum pkcs11_rc set_pin(struct pkcs11_session *session,
826e8dbd92cSJens Wiklander 			      uint8_t *new_pin, size_t new_pin_size,
827e8dbd92cSJens Wiklander 			      enum pkcs11_user_type user_type)
828e8dbd92cSJens Wiklander {
829e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
830e8dbd92cSJens Wiklander 	uint32_t flags_clear = 0;
831e8dbd92cSJens Wiklander 	uint32_t flags_set = 0;
832e8dbd92cSJens Wiklander 
833e8dbd92cSJens Wiklander 	if (session->token->db_main->flags & PKCS11_CKFT_WRITE_PROTECTED)
834e8dbd92cSJens Wiklander 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
835e8dbd92cSJens Wiklander 
836e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_read_write(session))
837e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
838e8dbd92cSJens Wiklander 
839e8dbd92cSJens Wiklander 	if (new_pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
840e8dbd92cSJens Wiklander 	    new_pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
841e8dbd92cSJens Wiklander 		return PKCS11_CKR_PIN_LEN_RANGE;
842e8dbd92cSJens Wiklander 
843e8dbd92cSJens Wiklander 	switch (user_type) {
844e8dbd92cSJens Wiklander 	case PKCS11_CKU_SO:
845e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
846e8dbd92cSJens Wiklander 			      &session->token->db_main->so_pin_salt,
847e8dbd92cSJens Wiklander 			      session->token->db_main->so_pin_hash);
848e8dbd92cSJens Wiklander 		if (rc)
849e8dbd92cSJens Wiklander 			return rc;
850e8dbd92cSJens Wiklander 		session->token->db_main->so_pin_count = 0;
851e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_SO_PIN_COUNT_LOW |
852e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_FINAL_TRY |
853e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_LOCKED |
854e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_TO_BE_CHANGED;
855e8dbd92cSJens Wiklander 		break;
856e8dbd92cSJens Wiklander 	case PKCS11_CKU_USER:
857e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
858e8dbd92cSJens Wiklander 			      &session->token->db_main->user_pin_salt,
859e8dbd92cSJens Wiklander 			      session->token->db_main->user_pin_hash);
860e8dbd92cSJens Wiklander 		if (rc)
861e8dbd92cSJens Wiklander 			return rc;
862e8dbd92cSJens Wiklander 		session->token->db_main->user_pin_count = 0;
863e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_USER_PIN_COUNT_LOW |
864e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_FINAL_TRY |
865e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_LOCKED |
866e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_TO_BE_CHANGED;
867e8dbd92cSJens Wiklander 		flags_set = PKCS11_CKFT_USER_PIN_INITIALIZED;
868e8dbd92cSJens Wiklander 		break;
869e8dbd92cSJens Wiklander 	default:
870e8dbd92cSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
871e8dbd92cSJens Wiklander 	}
872e8dbd92cSJens Wiklander 
873e8dbd92cSJens Wiklander 	session->token->db_main->flags &= ~flags_clear;
874e8dbd92cSJens Wiklander 	session->token->db_main->flags |= flags_set;
875e8dbd92cSJens Wiklander 
876e8dbd92cSJens Wiklander 	update_persistent_db(session->token);
877e8dbd92cSJens Wiklander 
878e8dbd92cSJens Wiklander 	return PKCS11_CKR_OK;
879e8dbd92cSJens Wiklander }
880e8dbd92cSJens Wiklander 
881e8dbd92cSJens Wiklander uint32_t entry_ck_init_pin(struct pkcs11_client *client,
882e8dbd92cSJens Wiklander 			   uint32_t ptypes, TEE_Param *params)
883e8dbd92cSJens Wiklander {
884e8dbd92cSJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
885e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
886e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
887e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE);
888e8dbd92cSJens Wiklander 	struct pkcs11_session *session = NULL;
889e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
890e8dbd92cSJens Wiklander 	struct serialargs ctrlargs = { };
891e8dbd92cSJens Wiklander 	uint32_t session_handle = 0;
892e8dbd92cSJens Wiklander 	TEE_Param *ctrl = params;
893e8dbd92cSJens Wiklander 	uint32_t pin_size = 0;
894e8dbd92cSJens Wiklander 	void *pin = NULL;
895e8dbd92cSJens Wiklander 
896e8dbd92cSJens Wiklander 	if (!client || ptypes != exp_pt)
897e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
898e8dbd92cSJens Wiklander 
899e8dbd92cSJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
900e8dbd92cSJens Wiklander 
901e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
902e8dbd92cSJens Wiklander 	if (rc)
903e8dbd92cSJens Wiklander 		return rc;
904e8dbd92cSJens Wiklander 
905e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
906e8dbd92cSJens Wiklander 	if (rc)
907e8dbd92cSJens Wiklander 		return rc;
908e8dbd92cSJens Wiklander 
909e8dbd92cSJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
910e8dbd92cSJens Wiklander 	if (rc)
911e8dbd92cSJens Wiklander 		return rc;
912e8dbd92cSJens Wiklander 
913e8dbd92cSJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
914e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
915e8dbd92cSJens Wiklander 
916e8dbd92cSJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
917e8dbd92cSJens Wiklander 	if (!session)
918e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
919e8dbd92cSJens Wiklander 
920e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_so(session))
921e8dbd92cSJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
922e8dbd92cSJens Wiklander 
923e8dbd92cSJens Wiklander 	assert(session->token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
924e8dbd92cSJens Wiklander 
925e8dbd92cSJens Wiklander 	IMSG("PKCS11 session %"PRIu32": init PIN", session_handle);
926e8dbd92cSJens Wiklander 
927e8dbd92cSJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
928e8dbd92cSJens Wiklander }
9291dbb91e7SJens Wiklander 
9301dbb91e7SJens Wiklander static uint32_t check_so_pin(struct pkcs11_session *session,
9311dbb91e7SJens Wiklander 			     uint8_t *pin, size_t pin_size)
9321dbb91e7SJens Wiklander {
9331dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
9341dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
9351dbb91e7SJens Wiklander 
9361dbb91e7SJens Wiklander 	assert(token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
9371dbb91e7SJens Wiklander 
9381dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
9391dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
9401dbb91e7SJens Wiklander 
9411dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
9421dbb91e7SJens Wiklander 			token->db_main->so_pin_salt,
9431dbb91e7SJens Wiklander 			token->db_main->so_pin_hash);
9441dbb91e7SJens Wiklander 	if (rc) {
9451dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
9461dbb91e7SJens Wiklander 
9471dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
9481dbb91e7SJens Wiklander 			return rc;
9491dbb91e7SJens Wiklander 
9501dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
9511dbb91e7SJens Wiklander 		token->db_main->so_pin_count++;
9521dbb91e7SJens Wiklander 
9531dbb91e7SJens Wiklander 		pin_count = token->db_main->so_pin_count;
9541dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
9551dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
9561dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
9571dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
9581dbb91e7SJens Wiklander 
9591dbb91e7SJens Wiklander 		update_persistent_db(token);
9601dbb91e7SJens Wiklander 
9611dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
9621dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
9631dbb91e7SJens Wiklander 
9641dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
9651dbb91e7SJens Wiklander 	}
9661dbb91e7SJens Wiklander 
9671dbb91e7SJens Wiklander 	if (token->db_main->so_pin_count) {
9681dbb91e7SJens Wiklander 		token->db_main->so_pin_count = 0;
9691dbb91e7SJens Wiklander 
9701dbb91e7SJens Wiklander 		update_persistent_db(token);
9711dbb91e7SJens Wiklander 	}
9721dbb91e7SJens Wiklander 
9731dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_SO_PIN_COUNT_LOW |
9741dbb91e7SJens Wiklander 				     PKCS11_CKFT_SO_PIN_FINAL_TRY)) {
9751dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
9761dbb91e7SJens Wiklander 					   PKCS11_CKFT_SO_PIN_FINAL_TRY);
9771dbb91e7SJens Wiklander 
9781dbb91e7SJens Wiklander 		update_persistent_db(token);
9791dbb91e7SJens Wiklander 	}
9801dbb91e7SJens Wiklander 
9811dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
9821dbb91e7SJens Wiklander }
9831dbb91e7SJens Wiklander 
9841dbb91e7SJens Wiklander static uint32_t check_user_pin(struct pkcs11_session *session,
9851dbb91e7SJens Wiklander 			       uint8_t *pin, size_t pin_size)
9861dbb91e7SJens Wiklander {
9871dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
9881dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
9891dbb91e7SJens Wiklander 
9901dbb91e7SJens Wiklander 	if (!token->db_main->user_pin_salt)
9911dbb91e7SJens Wiklander 		return PKCS11_CKR_USER_PIN_NOT_INITIALIZED;
9921dbb91e7SJens Wiklander 
9931dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
9941dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
9951dbb91e7SJens Wiklander 
9961dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_USER, pin, pin_size,
9971dbb91e7SJens Wiklander 			token->db_main->user_pin_salt,
9981dbb91e7SJens Wiklander 			token->db_main->user_pin_hash);
9991dbb91e7SJens Wiklander 	if (rc) {
10001dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
10011dbb91e7SJens Wiklander 
10021dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
10031dbb91e7SJens Wiklander 			return rc;
10041dbb91e7SJens Wiklander 
10051dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_USER_PIN_COUNT_LOW;
10061dbb91e7SJens Wiklander 		token->db_main->user_pin_count++;
10071dbb91e7SJens Wiklander 
10081dbb91e7SJens Wiklander 		pin_count = token->db_main->user_pin_count;
10091dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX - 1)
10101dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_FINAL_TRY;
10111dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX)
10121dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_LOCKED;
10131dbb91e7SJens Wiklander 
10141dbb91e7SJens Wiklander 		update_persistent_db(token);
10151dbb91e7SJens Wiklander 
10161dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
10171dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
10181dbb91e7SJens Wiklander 
10191dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
10201dbb91e7SJens Wiklander 	}
10211dbb91e7SJens Wiklander 
10221dbb91e7SJens Wiklander 	if (token->db_main->user_pin_count) {
10231dbb91e7SJens Wiklander 		token->db_main->user_pin_count = 0;
10241dbb91e7SJens Wiklander 
10251dbb91e7SJens Wiklander 		update_persistent_db(token);
10261dbb91e7SJens Wiklander 	}
10271dbb91e7SJens Wiklander 
10281dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_USER_PIN_COUNT_LOW |
10291dbb91e7SJens Wiklander 				     PKCS11_CKFT_USER_PIN_FINAL_TRY)) {
10301dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_COUNT_LOW |
10311dbb91e7SJens Wiklander 					   PKCS11_CKFT_USER_PIN_FINAL_TRY);
10321dbb91e7SJens Wiklander 
10331dbb91e7SJens Wiklander 		update_persistent_db(token);
10341dbb91e7SJens Wiklander 	}
10351dbb91e7SJens Wiklander 
10361dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
10371dbb91e7SJens Wiklander }
10381dbb91e7SJens Wiklander 
10391dbb91e7SJens Wiklander uint32_t entry_ck_set_pin(struct pkcs11_client *client,
10401dbb91e7SJens Wiklander 			  uint32_t ptypes, TEE_Param *params)
10411dbb91e7SJens Wiklander {
10421dbb91e7SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
10431dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
10441dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
10451dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE);
10461dbb91e7SJens Wiklander 	struct pkcs11_session *session = NULL;
10471dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
10481dbb91e7SJens Wiklander 	struct serialargs ctrlargs = { };
10491dbb91e7SJens Wiklander 	uint32_t session_handle = 0;
10501dbb91e7SJens Wiklander 	uint32_t old_pin_size = 0;
10511dbb91e7SJens Wiklander 	TEE_Param *ctrl = params;
10521dbb91e7SJens Wiklander 	uint32_t pin_size = 0;
10531dbb91e7SJens Wiklander 	void *old_pin = NULL;
10541dbb91e7SJens Wiklander 	void *pin = NULL;
10551dbb91e7SJens Wiklander 
10561dbb91e7SJens Wiklander 	if (!client || ptypes != exp_pt)
10571dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
10581dbb91e7SJens Wiklander 
10591dbb91e7SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
10601dbb91e7SJens Wiklander 
10611dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
10621dbb91e7SJens Wiklander 	if (rc)
10631dbb91e7SJens Wiklander 		return rc;
10641dbb91e7SJens Wiklander 
10651dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &old_pin_size, sizeof(uint32_t));
10661dbb91e7SJens Wiklander 	if (rc)
10671dbb91e7SJens Wiklander 		return rc;
10681dbb91e7SJens Wiklander 
10691dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
10701dbb91e7SJens Wiklander 	if (rc)
10711dbb91e7SJens Wiklander 		return rc;
10721dbb91e7SJens Wiklander 
10731dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &old_pin, old_pin_size);
10741dbb91e7SJens Wiklander 	if (rc)
10751dbb91e7SJens Wiklander 		return rc;
10761dbb91e7SJens Wiklander 
10771dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
10781dbb91e7SJens Wiklander 	if (rc)
10791dbb91e7SJens Wiklander 		return rc;
10801dbb91e7SJens Wiklander 
10811dbb91e7SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
10821dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
10831dbb91e7SJens Wiklander 
10841dbb91e7SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
10851dbb91e7SJens Wiklander 	if (!session)
10861dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
10871dbb91e7SJens Wiklander 
10881dbb91e7SJens Wiklander 	if (!pkcs11_session_is_read_write(session))
10891dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
10901dbb91e7SJens Wiklander 
10911dbb91e7SJens Wiklander 	if (pkcs11_session_is_so(session)) {
10921dbb91e7SJens Wiklander 		if (!(session->token->db_main->flags &
10931dbb91e7SJens Wiklander 		      PKCS11_CKFT_TOKEN_INITIALIZED))
10941dbb91e7SJens Wiklander 			return PKCS11_CKR_GENERAL_ERROR;
10951dbb91e7SJens Wiklander 
10961dbb91e7SJens Wiklander 		rc = check_so_pin(session, old_pin, old_pin_size);
10971dbb91e7SJens Wiklander 		if (rc)
10981dbb91e7SJens Wiklander 			return rc;
10991dbb91e7SJens Wiklander 
11001dbb91e7SJens Wiklander 		IMSG("PKCS11 session %"PRIu32": set PIN", session_handle);
11011dbb91e7SJens Wiklander 
11021dbb91e7SJens Wiklander 		return set_pin(session, pin, pin_size, PKCS11_CKU_SO);
11031dbb91e7SJens Wiklander 	}
11041dbb91e7SJens Wiklander 
11051dbb91e7SJens Wiklander 	if (!(session->token->db_main->flags &
11061dbb91e7SJens Wiklander 	      PKCS11_CKFT_USER_PIN_INITIALIZED))
11071dbb91e7SJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
11081dbb91e7SJens Wiklander 
11091dbb91e7SJens Wiklander 	rc = check_user_pin(session, old_pin, old_pin_size);
11101dbb91e7SJens Wiklander 	if (rc)
11111dbb91e7SJens Wiklander 		return rc;
11121dbb91e7SJens Wiklander 
11131dbb91e7SJens Wiklander 	IMSG("PKCS11 session %"PRIu32": set PIN", session_handle);
11141dbb91e7SJens Wiklander 
11151dbb91e7SJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
11161dbb91e7SJens Wiklander }
1117f7cc36c0SJens Wiklander 
1118f7cc36c0SJens Wiklander static void session_login_user(struct pkcs11_session *session)
1119f7cc36c0SJens Wiklander {
1120f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1121f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1122f7cc36c0SJens Wiklander 
1123f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1124f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1125f7cc36c0SJens Wiklander 			continue;
1126f7cc36c0SJens Wiklander 
1127f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1128f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_USER_FUNCTIONS;
1129f7cc36c0SJens Wiklander 		else
1130f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_USER_FUNCTIONS;
1131f7cc36c0SJens Wiklander 	}
1132f7cc36c0SJens Wiklander }
1133f7cc36c0SJens Wiklander 
1134f7cc36c0SJens Wiklander static void session_login_so(struct pkcs11_session *session)
1135f7cc36c0SJens Wiklander {
1136f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1137f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1138f7cc36c0SJens Wiklander 
1139f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1140f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1141f7cc36c0SJens Wiklander 			continue;
1142f7cc36c0SJens Wiklander 
1143f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1144f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_SO_FUNCTIONS;
1145f7cc36c0SJens Wiklander 		else
1146f7cc36c0SJens Wiklander 			TEE_Panic(0);
1147f7cc36c0SJens Wiklander 	}
1148f7cc36c0SJens Wiklander }
1149f7cc36c0SJens Wiklander 
1150f7cc36c0SJens Wiklander static void session_logout(struct pkcs11_session *session)
1151f7cc36c0SJens Wiklander {
1152f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1153f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1154f7cc36c0SJens Wiklander 
1155f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1156f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1157f7cc36c0SJens Wiklander 			continue;
1158f7cc36c0SJens Wiklander 
1159f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1160f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_PUBLIC_SESSION;
1161f7cc36c0SJens Wiklander 		else
1162f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_PUBLIC_SESSION;
1163f7cc36c0SJens Wiklander 	}
1164f7cc36c0SJens Wiklander }
1165f7cc36c0SJens Wiklander 
1166f7cc36c0SJens Wiklander uint32_t entry_ck_login(struct pkcs11_client *client,
1167f7cc36c0SJens Wiklander 			uint32_t ptypes, TEE_Param *params)
1168f7cc36c0SJens Wiklander {
1169f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1170f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1171f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1172f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1173f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1174f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1175f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1176f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1177f7cc36c0SJens Wiklander 	uint32_t session_handle = 0;
1178f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1179f7cc36c0SJens Wiklander 	uint32_t user_type = 0;
1180f7cc36c0SJens Wiklander 	uint32_t pin_size = 0;
1181f7cc36c0SJens Wiklander 	void *pin = NULL;
1182f7cc36c0SJens Wiklander 
1183f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1184f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1185f7cc36c0SJens Wiklander 
1186f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1187f7cc36c0SJens Wiklander 
1188f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
1189f7cc36c0SJens Wiklander 	if (rc)
1190f7cc36c0SJens Wiklander 		return rc;
1191f7cc36c0SJens Wiklander 
1192f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &user_type, sizeof(uint32_t));
1193f7cc36c0SJens Wiklander 	if (rc)
1194f7cc36c0SJens Wiklander 		return rc;
1195f7cc36c0SJens Wiklander 
1196f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
1197f7cc36c0SJens Wiklander 	if (rc)
1198f7cc36c0SJens Wiklander 		return rc;
1199f7cc36c0SJens Wiklander 
1200f7cc36c0SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
1201f7cc36c0SJens Wiklander 	if (rc)
1202f7cc36c0SJens Wiklander 		return rc;
1203f7cc36c0SJens Wiklander 
1204f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1205f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1206f7cc36c0SJens Wiklander 
1207f7cc36c0SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
1208f7cc36c0SJens Wiklander 	if (!session)
1209f7cc36c0SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
1210f7cc36c0SJens Wiklander 
1211f7cc36c0SJens Wiklander 	switch (user_type) {
1212f7cc36c0SJens Wiklander 	case PKCS11_CKU_SO:
1213f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1214f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1215f7cc36c0SJens Wiklander 
1216f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1217f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1218f7cc36c0SJens Wiklander 
1219f7cc36c0SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
1220f7cc36c0SJens Wiklander 			if (sess->token == session->token &&
1221f7cc36c0SJens Wiklander 			    !pkcs11_session_is_read_write(sess))
1222f7cc36c0SJens Wiklander 				return PKCS11_CKR_SESSION_READ_ONLY_EXISTS;
1223f7cc36c0SJens Wiklander 
1224f7cc36c0SJens Wiklander 		/*
1225f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1226f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1227f7cc36c0SJens Wiklander 		 *
1228f7cc36c0SJens Wiklander 		 * The spec says:
1229f7cc36c0SJens Wiklander 		 * CKR_USER_TOO_MANY_TYPES: An attempt was made to have
1230f7cc36c0SJens Wiklander 		 * more distinct users simultaneously logged into the token
1231f7cc36c0SJens Wiklander 		 * than the token and/or library permits. For example, if
1232f7cc36c0SJens Wiklander 		 * some application has an open SO session, and another
1233f7cc36c0SJens Wiklander 		 * application attempts to log the normal user into a
1234f7cc36c0SJens Wiklander 		 * session, the attempt may return this error. It is not
1235f7cc36c0SJens Wiklander 		 * required to, however. Only if the simultaneous distinct
1236f7cc36c0SJens Wiklander 		 * users cannot be supported does C_Login have to return
1237f7cc36c0SJens Wiklander 		 * this value. Note that this error code generalizes to
1238f7cc36c0SJens Wiklander 		 * true multi-user tokens.
1239f7cc36c0SJens Wiklander 		 *
1240f7cc36c0SJens Wiklander 		 * So it's permitted to have another user or SO logged in
1241f7cc36c0SJens Wiklander 		 * from another client.
1242f7cc36c0SJens Wiklander 		 */
1243f7cc36c0SJens Wiklander 
1244f7cc36c0SJens Wiklander 		rc = check_so_pin(session, pin, pin_size);
1245f7cc36c0SJens Wiklander 		if (!rc)
1246f7cc36c0SJens Wiklander 			session_login_so(session);
1247f7cc36c0SJens Wiklander 
1248f7cc36c0SJens Wiklander 		break;
1249f7cc36c0SJens Wiklander 
1250f7cc36c0SJens Wiklander 	case PKCS11_CKU_USER:
1251f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1252f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1253f7cc36c0SJens Wiklander 
1254f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1255f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1256f7cc36c0SJens Wiklander 
1257f7cc36c0SJens Wiklander 		/*
1258f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1259f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1260f7cc36c0SJens Wiklander 		 * See comment on CKR_USER_TOO_MANY_TYPES above.
1261f7cc36c0SJens Wiklander 		 */
1262f7cc36c0SJens Wiklander 
1263f7cc36c0SJens Wiklander 		rc = check_user_pin(session, pin, pin_size);
1264f7cc36c0SJens Wiklander 		if (!rc)
1265f7cc36c0SJens Wiklander 			session_login_user(session);
1266f7cc36c0SJens Wiklander 
1267f7cc36c0SJens Wiklander 		break;
1268f7cc36c0SJens Wiklander 
1269f7cc36c0SJens Wiklander 	case PKCS11_CKU_CONTEXT_SPECIFIC:
1270f7cc36c0SJens Wiklander 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
1271f7cc36c0SJens Wiklander 
1272f7cc36c0SJens Wiklander 	default:
1273f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_TYPE_INVALID;
1274f7cc36c0SJens Wiklander 	}
1275f7cc36c0SJens Wiklander 
1276f7cc36c0SJens Wiklander 	if (!rc)
1277f7cc36c0SJens Wiklander 		IMSG("PKCS11 session %"PRIu32": login", session_handle);
1278f7cc36c0SJens Wiklander 
1279f7cc36c0SJens Wiklander 	return rc;
1280f7cc36c0SJens Wiklander }
1281f7cc36c0SJens Wiklander 
1282f7cc36c0SJens Wiklander uint32_t entry_ck_logout(struct pkcs11_client *client,
1283f7cc36c0SJens Wiklander 			 uint32_t ptypes, TEE_Param *params)
1284f7cc36c0SJens Wiklander {
1285f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1286f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1287f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1288f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1289f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1290f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1291f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1292f7cc36c0SJens Wiklander 	uint32_t session_handle = 0;
1293f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1294f7cc36c0SJens Wiklander 
1295f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1296f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1297f7cc36c0SJens Wiklander 
1298f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1299f7cc36c0SJens Wiklander 
1300f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
1301f7cc36c0SJens Wiklander 	if (rc)
1302f7cc36c0SJens Wiklander 		return rc;
1303f7cc36c0SJens Wiklander 
1304f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1305f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1306f7cc36c0SJens Wiklander 
1307f7cc36c0SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
1308f7cc36c0SJens Wiklander 	if (!session)
1309f7cc36c0SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
1310f7cc36c0SJens Wiklander 
1311f7cc36c0SJens Wiklander 	if (pkcs11_session_is_public(session))
1312f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
1313f7cc36c0SJens Wiklander 
1314f7cc36c0SJens Wiklander 	session_logout(session);
1315f7cc36c0SJens Wiklander 
1316f7cc36c0SJens Wiklander 	IMSG("PKCS11 session %"PRIu32": logout", session_handle);
1317f7cc36c0SJens Wiklander 
1318f7cc36c0SJens Wiklander 	return PKCS11_CKR_OK;
1319f7cc36c0SJens Wiklander }
1320