xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision d628ebd9b0a9fd05355f934d89a28bc2154713df)
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>
9*d628ebd9SEtienne Carriere #include <printk.h>
10c84ccd0aSEtienne Carriere #include <string.h>
11c84ccd0aSEtienne Carriere #include <string_ext.h>
12c84ccd0aSEtienne Carriere #include <sys/queue.h>
13c84ccd0aSEtienne Carriere #include <tee_api_types.h>
14c84ccd0aSEtienne Carriere #include <tee_internal_api_extensions.h>
15c84ccd0aSEtienne Carriere #include <util.h>
16c84ccd0aSEtienne Carriere 
17c84ccd0aSEtienne Carriere #include "pkcs11_helpers.h"
18ee49d9f2SEtienne Carriere #include "pkcs11_token.h"
1922ac6984SEtienne Carriere #include "serializer.h"
20c84ccd0aSEtienne Carriere 
21c84ccd0aSEtienne Carriere /* Provide 3 slots/tokens, ID is token index */
22c84ccd0aSEtienne Carriere #ifndef CFG_PKCS11_TA_TOKEN_COUNT
23c84ccd0aSEtienne Carriere #define TOKEN_COUNT		3
24c84ccd0aSEtienne Carriere #else
25c84ccd0aSEtienne Carriere #define TOKEN_COUNT		CFG_PKCS11_TA_TOKEN_COUNT
26c84ccd0aSEtienne Carriere #endif
27c84ccd0aSEtienne Carriere 
28e084583eSEtienne Carriere /*
29e084583eSEtienne Carriere  * Structure tracking client applications
30e084583eSEtienne Carriere  *
31e084583eSEtienne Carriere  * @link - chained list of registered client applications
32e084583eSEtienne Carriere  * @sessions - list of the PKCS11 sessions opened by the client application
33e084583eSEtienne Carriere  */
34e084583eSEtienne Carriere struct pkcs11_client {
35e084583eSEtienne Carriere 	TAILQ_ENTRY(pkcs11_client) link;
36e084583eSEtienne Carriere 	struct session_list session_list;
37e084583eSEtienne Carriere 	struct handle_db session_handle_db;
38e084583eSEtienne Carriere };
39e084583eSEtienne Carriere 
40c84ccd0aSEtienne Carriere /* Static allocation of tokens runtime instances (reset to 0 at load) */
41c84ccd0aSEtienne Carriere struct ck_token ck_token[TOKEN_COUNT];
42c84ccd0aSEtienne Carriere 
43e084583eSEtienne Carriere static struct client_list pkcs11_client_list =
44e084583eSEtienne Carriere 	TAILQ_HEAD_INITIALIZER(pkcs11_client_list);
45e084583eSEtienne Carriere 
466e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session);
476e4f8f17SEtienne Carriere 
48c84ccd0aSEtienne Carriere struct ck_token *get_token(unsigned int token_id)
49c84ccd0aSEtienne Carriere {
50d38f9635SEtienne Carriere 	if (token_id < TOKEN_COUNT)
51d38f9635SEtienne Carriere 		return &ck_token[confine_array_index(token_id, TOKEN_COUNT)];
52c84ccd0aSEtienne Carriere 
53d38f9635SEtienne Carriere 	return NULL;
54c84ccd0aSEtienne Carriere }
55c84ccd0aSEtienne Carriere 
56c84ccd0aSEtienne Carriere unsigned int get_token_id(struct ck_token *token)
57c84ccd0aSEtienne Carriere {
58c84ccd0aSEtienne Carriere 	ptrdiff_t id = token - ck_token;
59c84ccd0aSEtienne Carriere 
60c84ccd0aSEtienne Carriere 	assert(id >= 0 && id < TOKEN_COUNT);
61c84ccd0aSEtienne Carriere 	return id;
62c84ccd0aSEtienne Carriere }
63c84ccd0aSEtienne Carriere 
64e084583eSEtienne Carriere struct pkcs11_client *tee_session2client(void *tee_session)
65e084583eSEtienne Carriere {
66e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
67e084583eSEtienne Carriere 
68e084583eSEtienne Carriere 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
69e084583eSEtienne Carriere 		if (client == tee_session)
70e084583eSEtienne Carriere 			break;
71e084583eSEtienne Carriere 
72e084583eSEtienne Carriere 	return client;
73e084583eSEtienne Carriere }
74e084583eSEtienne Carriere 
756e4f8f17SEtienne Carriere struct pkcs11_session *pkcs11_handle2session(uint32_t handle,
766e4f8f17SEtienne Carriere 					     struct pkcs11_client *client)
776e4f8f17SEtienne Carriere {
786e4f8f17SEtienne Carriere 	return handle_lookup(&client->session_handle_db, handle);
796e4f8f17SEtienne Carriere }
806e4f8f17SEtienne Carriere 
81e084583eSEtienne Carriere struct pkcs11_client *register_client(void)
82e084583eSEtienne Carriere {
83e084583eSEtienne Carriere 	struct pkcs11_client *client = NULL;
84e084583eSEtienne Carriere 
85e084583eSEtienne Carriere 	client = TEE_Malloc(sizeof(*client), TEE_MALLOC_FILL_ZERO);
86e084583eSEtienne Carriere 	if (!client)
87e084583eSEtienne Carriere 		return NULL;
88e084583eSEtienne Carriere 
89e084583eSEtienne Carriere 	TAILQ_INSERT_HEAD(&pkcs11_client_list, client, link);
90e084583eSEtienne Carriere 	TAILQ_INIT(&client->session_list);
91e084583eSEtienne Carriere 	handle_db_init(&client->session_handle_db);
92e084583eSEtienne Carriere 
93e084583eSEtienne Carriere 	return client;
94e084583eSEtienne Carriere }
95e084583eSEtienne Carriere 
96e084583eSEtienne Carriere void unregister_client(struct pkcs11_client *client)
97e084583eSEtienne Carriere {
986e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
996e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
1006e4f8f17SEtienne Carriere 
101e084583eSEtienne Carriere 	if (!client) {
102e084583eSEtienne Carriere 		EMSG("Invalid TEE session handle");
103e084583eSEtienne Carriere 		return;
104e084583eSEtienne Carriere 	}
105e084583eSEtienne Carriere 
1066e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
1076e4f8f17SEtienne Carriere 		close_ck_session(session);
1086e4f8f17SEtienne Carriere 
109e084583eSEtienne Carriere 	TAILQ_REMOVE(&pkcs11_client_list, client, link);
110e084583eSEtienne Carriere 	handle_db_destroy(&client->session_handle_db);
111e084583eSEtienne Carriere 	TEE_Free(client);
112e084583eSEtienne Carriere }
113e084583eSEtienne Carriere 
114c84ccd0aSEtienne Carriere static TEE_Result pkcs11_token_init(unsigned int id)
115c84ccd0aSEtienne Carriere {
116c84ccd0aSEtienne Carriere 	struct ck_token *token = init_persistent_db(id);
117c84ccd0aSEtienne Carriere 
118c84ccd0aSEtienne Carriere 	if (!token)
119c84ccd0aSEtienne Carriere 		return TEE_ERROR_SECURITY;
120c84ccd0aSEtienne Carriere 
121c84ccd0aSEtienne Carriere 	if (token->state == PKCS11_TOKEN_RESET) {
122c84ccd0aSEtienne Carriere 		/* As per PKCS#11 spec, token resets to read/write state */
123c84ccd0aSEtienne Carriere 		token->state = PKCS11_TOKEN_READ_WRITE;
124c84ccd0aSEtienne Carriere 		token->session_count = 0;
125c84ccd0aSEtienne Carriere 		token->rw_session_count = 0;
126c84ccd0aSEtienne Carriere 	}
127c84ccd0aSEtienne Carriere 
128c84ccd0aSEtienne Carriere 	return TEE_SUCCESS;
129c84ccd0aSEtienne Carriere }
130c84ccd0aSEtienne Carriere 
131c84ccd0aSEtienne Carriere TEE_Result pkcs11_init(void)
132c84ccd0aSEtienne Carriere {
133c84ccd0aSEtienne Carriere 	unsigned int id = 0;
134c84ccd0aSEtienne Carriere 	TEE_Result ret = TEE_ERROR_GENERIC;
135c84ccd0aSEtienne Carriere 
136c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++) {
137c84ccd0aSEtienne Carriere 		ret = pkcs11_token_init(id);
138c84ccd0aSEtienne Carriere 		if (ret)
139e084583eSEtienne Carriere 			break;
140c84ccd0aSEtienne Carriere 	}
141c84ccd0aSEtienne Carriere 
142c84ccd0aSEtienne Carriere 	return ret;
143c84ccd0aSEtienne Carriere }
144c84ccd0aSEtienne Carriere 
145c84ccd0aSEtienne Carriere void pkcs11_deinit(void)
146c84ccd0aSEtienne Carriere {
147c84ccd0aSEtienne Carriere 	unsigned int id = 0;
148c84ccd0aSEtienne Carriere 
149c84ccd0aSEtienne Carriere 	for (id = 0; id < TOKEN_COUNT; id++)
150c84ccd0aSEtienne Carriere 		close_persistent_db(get_token(id));
151c84ccd0aSEtienne Carriere }
15222ac6984SEtienne Carriere 
15322ac6984SEtienne Carriere uint32_t entry_ck_slot_list(uint32_t ptypes, TEE_Param *params)
15422ac6984SEtienne Carriere {
15522ac6984SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
15622ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
15722ac6984SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
15822ac6984SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
15922ac6984SEtienne Carriere 	TEE_Param *out = &params[2];
16022ac6984SEtienne Carriere 	uint32_t token_id = 0;
16122ac6984SEtienne Carriere 	const size_t out_size = sizeof(token_id) * TOKEN_COUNT;
16222ac6984SEtienne Carriere 	uint8_t *id = NULL;
16322ac6984SEtienne Carriere 
16422ac6984SEtienne Carriere 	if (ptypes != exp_pt ||
16522ac6984SEtienne Carriere 	    params[0].memref.size != TEE_PARAM0_SIZE_MIN)
16622ac6984SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
16722ac6984SEtienne Carriere 
16822ac6984SEtienne Carriere 	if (out->memref.size < out_size) {
16922ac6984SEtienne Carriere 		out->memref.size = out_size;
17022ac6984SEtienne Carriere 
17122ac6984SEtienne Carriere 		if (out->memref.buffer)
17222ac6984SEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
17322ac6984SEtienne Carriere 		else
17422ac6984SEtienne Carriere 			return PKCS11_CKR_OK;
17522ac6984SEtienne Carriere 	}
17622ac6984SEtienne Carriere 
17722ac6984SEtienne Carriere 	for (token_id = 0, id = out->memref.buffer; token_id < TOKEN_COUNT;
17822ac6984SEtienne Carriere 	     token_id++, id += sizeof(token_id))
17922ac6984SEtienne Carriere 		TEE_MemMove(id, &token_id, sizeof(token_id));
18022ac6984SEtienne Carriere 
18122ac6984SEtienne Carriere 	out->memref.size = out_size;
18222ac6984SEtienne Carriere 
18322ac6984SEtienne Carriere 	return PKCS11_CKR_OK;
18422ac6984SEtienne Carriere }
185ce94efefSEtienne Carriere 
186b3ac5035SEtienne Carriere static void pad_str(uint8_t *str, size_t size)
187b3ac5035SEtienne Carriere {
188b3ac5035SEtienne Carriere 	int n = strnlen((char *)str, size);
189b3ac5035SEtienne Carriere 
190b3ac5035SEtienne Carriere 	TEE_MemFill(str + n, ' ', size - n);
191b3ac5035SEtienne Carriere }
192b3ac5035SEtienne Carriere 
193*d628ebd9SEtienne Carriere static void set_token_description(struct pkcs11_slot_info *info)
194*d628ebd9SEtienne Carriere {
195*d628ebd9SEtienne Carriere 	char desc[sizeof(info->slot_description) + 1] = { 0 };
196*d628ebd9SEtienne Carriere 	TEE_UUID dev_id = { };
197*d628ebd9SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
198*d628ebd9SEtienne Carriere 	int n = 0;
199*d628ebd9SEtienne Carriere 
200*d628ebd9SEtienne Carriere 	res = TEE_GetPropertyAsUUID(TEE_PROPSET_TEE_IMPLEMENTATION,
201*d628ebd9SEtienne Carriere 				    "gpd.tee.deviceID", &dev_id);
202*d628ebd9SEtienne Carriere 	if (res == TEE_SUCCESS) {
203*d628ebd9SEtienne Carriere 		n = snprintk(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
204*d628ebd9SEtienne Carriere 			     " - TEE UUID %pUl", (void *)&dev_id);
205*d628ebd9SEtienne Carriere 	} else {
206*d628ebd9SEtienne Carriere 		n = snprintf(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
207*d628ebd9SEtienne Carriere 			     " - No TEE UUID");
208*d628ebd9SEtienne Carriere 	}
209*d628ebd9SEtienne Carriere 	if (n < 0 || n >= (int)sizeof(desc))
210*d628ebd9SEtienne Carriere 		TEE_Panic(0);
211*d628ebd9SEtienne Carriere 
212*d628ebd9SEtienne Carriere 	TEE_MemMove(info->slot_description, desc, n);
213*d628ebd9SEtienne Carriere 	pad_str(info->slot_description, sizeof(info->slot_description));
214*d628ebd9SEtienne Carriere }
215*d628ebd9SEtienne Carriere 
216ce94efefSEtienne Carriere uint32_t entry_ck_slot_info(uint32_t ptypes, TEE_Param *params)
217ce94efefSEtienne Carriere {
218ce94efefSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
219ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
220ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
221ce94efefSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
222ce94efefSEtienne Carriere 	TEE_Param *ctrl = &params[0];
223ce94efefSEtienne Carriere 	TEE_Param *out = &params[2];
224ce94efefSEtienne Carriere 	uint32_t rv = 0;
225ce94efefSEtienne Carriere 	struct serialargs ctrlargs = { };
226ce94efefSEtienne Carriere 	uint32_t token_id = 0;
227ce94efefSEtienne Carriere 	struct pkcs11_slot_info info = {
228ce94efefSEtienne Carriere 		.slot_description = PKCS11_SLOT_DESCRIPTION,
229ce94efefSEtienne Carriere 		.manufacturer_id = PKCS11_SLOT_MANUFACTURER,
230ce94efefSEtienne Carriere 		.flags = PKCS11_CKFS_TOKEN_PRESENT,
231ce94efefSEtienne Carriere 		.hardware_version = PKCS11_SLOT_HW_VERSION,
232ce94efefSEtienne Carriere 		.firmware_version = PKCS11_SLOT_FW_VERSION,
233ce94efefSEtienne Carriere 	};
234ce94efefSEtienne Carriere 
235ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_DESCRIPTION) <=
236ce94efefSEtienne Carriere 			    sizeof(info.slot_description));
237ce94efefSEtienne Carriere 	COMPILE_TIME_ASSERT(sizeof(PKCS11_SLOT_MANUFACTURER) <=
238ce94efefSEtienne Carriere 			    sizeof(info.manufacturer_id));
239ce94efefSEtienne Carriere 
240ce94efefSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
241ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
242ce94efefSEtienne Carriere 
243ce94efefSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
244ce94efefSEtienne Carriere 
245ce94efefSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
246ce94efefSEtienne Carriere 	if (rv)
247ce94efefSEtienne Carriere 		return rv;
248ce94efefSEtienne Carriere 
249ce94efefSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
250ce94efefSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
251ce94efefSEtienne Carriere 
25229b0949aSEtienne Carriere 	if (!get_token(token_id))
253ce94efefSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
254ce94efefSEtienne Carriere 
255*d628ebd9SEtienne Carriere 	set_token_description(&info);
256*d628ebd9SEtienne Carriere 
257b3ac5035SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
258ce94efefSEtienne Carriere 
259ce94efefSEtienne Carriere 	out->memref.size = sizeof(info);
260ce94efefSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, out->memref.size);
261ce94efefSEtienne Carriere 
262ce94efefSEtienne Carriere 	return PKCS11_CKR_OK;
263ce94efefSEtienne Carriere }
264030e7392SEtienne Carriere 
265030e7392SEtienne Carriere uint32_t entry_ck_token_info(uint32_t ptypes, TEE_Param *params)
266030e7392SEtienne Carriere {
267030e7392SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
268030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
269030e7392SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
270030e7392SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
271030e7392SEtienne Carriere 	TEE_Param *ctrl = &params[0];
272030e7392SEtienne Carriere 	TEE_Param *out = &params[2];
273030e7392SEtienne Carriere 	uint32_t rv = 0;
274030e7392SEtienne Carriere 	struct serialargs ctrlargs = { };
275030e7392SEtienne Carriere 	uint32_t token_id = 0;
276030e7392SEtienne Carriere 	struct ck_token *token = NULL;
277030e7392SEtienne Carriere 	struct pkcs11_token_info info = {
278030e7392SEtienne Carriere 		.manufacturer_id = PKCS11_TOKEN_MANUFACTURER,
279030e7392SEtienne Carriere 		.model = PKCS11_TOKEN_MODEL,
280030e7392SEtienne Carriere 		.serial_number = PKCS11_TOKEN_SERIAL_NUMBER,
281030e7392SEtienne Carriere 		.max_session_count = UINT32_MAX,
282030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
283030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
284030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
285030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
286030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
287030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
288030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
289030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
290030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
291030e7392SEtienne Carriere 	};
292030e7392SEtienne Carriere 
293030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
294030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
295030e7392SEtienne Carriere 
296030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
297030e7392SEtienne Carriere 
298030e7392SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
299030e7392SEtienne Carriere 	if (rv)
300030e7392SEtienne Carriere 		return rv;
301030e7392SEtienne Carriere 
302030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
303030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
304030e7392SEtienne Carriere 
305030e7392SEtienne Carriere 	token = get_token(token_id);
306030e7392SEtienne Carriere 	if (!token)
307030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
308030e7392SEtienne Carriere 
309030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
310030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
311030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
312030e7392SEtienne Carriere 
313030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
314030e7392SEtienne Carriere 
315030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
316030e7392SEtienne Carriere 	info.session_count = token->session_count;
317030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
318030e7392SEtienne Carriere 
319030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
320030e7392SEtienne Carriere 
321030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
322030e7392SEtienne Carriere }
3236f74919dSEtienne Carriere 
3246f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
3256f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
3266f74919dSEtienne Carriere 					   size_t count __maybe_unused)
3276f74919dSEtienne Carriere {
3286f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
3296f74919dSEtienne Carriere 
3306f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
3316f74919dSEtienne Carriere 		return;
3326f74919dSEtienne Carriere 
3336f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
3346f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
3356f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
3366f74919dSEtienne Carriere }
3376f74919dSEtienne Carriere 
3386f74919dSEtienne Carriere uint32_t entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
3396f74919dSEtienne Carriere {
3406f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3416f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3426f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3436f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3446f74919dSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3456f74919dSEtienne Carriere 	TEE_Param *out = &params[2];
3466f74919dSEtienne Carriere 	uint32_t rv = 0;
3476f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
3486f74919dSEtienne Carriere 	uint32_t token_id = 0;
3496f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
3506f74919dSEtienne Carriere 	size_t count = 0;
3516f74919dSEtienne Carriere 	uint32_t *array = NULL;
3526f74919dSEtienne Carriere 
3536f74919dSEtienne Carriere 	if (ptypes != exp_pt)
3546f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3556f74919dSEtienne Carriere 
3566f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
3576f74919dSEtienne Carriere 
3586f74919dSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3596f74919dSEtienne Carriere 	if (rv)
3606f74919dSEtienne Carriere 		return rv;
3616f74919dSEtienne Carriere 
3626f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
3636f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3646f74919dSEtienne Carriere 
3656f74919dSEtienne Carriere 	token = get_token(token_id);
3666f74919dSEtienne Carriere 	if (!token)
3676f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
3686f74919dSEtienne Carriere 
3696f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
3706f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
3716f74919dSEtienne Carriere 
3726f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
3736f74919dSEtienne Carriere 		assert(!array);
3746f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
3756459f267SEtienne Carriere 		if (out->memref.buffer)
3766f74919dSEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
3776459f267SEtienne Carriere 		else
3786459f267SEtienne Carriere 			return PKCS11_CKR_OK;
3796f74919dSEtienne Carriere 	}
3806f74919dSEtienne Carriere 
3816f74919dSEtienne Carriere 	if (!array)
3826f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
3836f74919dSEtienne Carriere 
3846f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
3856f74919dSEtienne Carriere 
3866f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
3876f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
3886f74919dSEtienne Carriere 
3896f74919dSEtienne Carriere 	TEE_Free(array);
3906f74919dSEtienne Carriere 
3916f74919dSEtienne Carriere 	return rv;
3926f74919dSEtienne Carriere }
3931d3ebedbSEtienne Carriere 
3941d3ebedbSEtienne Carriere static void supported_mechanism_key_size(uint32_t proc_id,
3951d3ebedbSEtienne Carriere 					 uint32_t *max_key_size,
3961d3ebedbSEtienne Carriere 					 uint32_t *min_key_size)
3971d3ebedbSEtienne Carriere {
3981d3ebedbSEtienne Carriere 	switch (proc_id) {
3991d3ebedbSEtienne Carriere 	/* Will be filled once TA supports mechanisms */
4001d3ebedbSEtienne Carriere 	default:
4011d3ebedbSEtienne Carriere 		*min_key_size = 0;
4021d3ebedbSEtienne Carriere 		*max_key_size = 0;
4031d3ebedbSEtienne Carriere 		break;
4041d3ebedbSEtienne Carriere 	}
4051d3ebedbSEtienne Carriere }
4061d3ebedbSEtienne Carriere 
4071d3ebedbSEtienne Carriere uint32_t entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
4081d3ebedbSEtienne Carriere {
4091d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4101d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4111d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4121d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
4131d3ebedbSEtienne Carriere 	TEE_Param *ctrl = &params[0];
4141d3ebedbSEtienne Carriere 	TEE_Param *out = &params[2];
4151d3ebedbSEtienne Carriere 	uint32_t rv = 0;
4161d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
4171d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
4181d3ebedbSEtienne Carriere 	uint32_t type = 0;
4191d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
4201d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
4211d3ebedbSEtienne Carriere 
4221d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
4231d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4241d3ebedbSEtienne Carriere 
4251d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
4261d3ebedbSEtienne Carriere 
4271d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
4281d3ebedbSEtienne Carriere 	if (rv)
4291d3ebedbSEtienne Carriere 		return rv;
4301d3ebedbSEtienne Carriere 
4311d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
4321d3ebedbSEtienne Carriere 	if (rv)
4331d3ebedbSEtienne Carriere 		return rv;
4341d3ebedbSEtienne Carriere 
4351d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
4361d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4371d3ebedbSEtienne Carriere 
4381d3ebedbSEtienne Carriere 	token = get_token(token_id);
4391d3ebedbSEtienne Carriere 	if (!token)
4401d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4411d3ebedbSEtienne Carriere 
4421d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
4431d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
4441d3ebedbSEtienne Carriere 
4451d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
4461d3ebedbSEtienne Carriere 
4471d3ebedbSEtienne Carriere 	supported_mechanism_key_size(type, &info.min_key_size,
4481d3ebedbSEtienne Carriere 				     &info.max_key_size);
4491d3ebedbSEtienne Carriere 
4501d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
4511d3ebedbSEtienne Carriere 
4521d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
4531d3ebedbSEtienne Carriere 	     token_id, type);
4541d3ebedbSEtienne Carriere 
4551d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
4561d3ebedbSEtienne Carriere }
4576e4f8f17SEtienne Carriere 
4586e4f8f17SEtienne Carriere /* Select the ReadOnly or ReadWrite state for session login state */
4596e4f8f17SEtienne Carriere static void set_session_state(struct pkcs11_client *client,
4606e4f8f17SEtienne Carriere 			      struct pkcs11_session *session, bool readonly)
4616e4f8f17SEtienne Carriere {
4626e4f8f17SEtienne Carriere 	struct pkcs11_session *sess = NULL;
4636e4f8f17SEtienne Carriere 	enum pkcs11_session_state state = PKCS11_CKS_RO_PUBLIC_SESSION;
4646e4f8f17SEtienne Carriere 
4656e4f8f17SEtienne Carriere 	/* Default to public session if no session already registered */
4666e4f8f17SEtienne Carriere 	if (readonly)
4676e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RO_PUBLIC_SESSION;
4686e4f8f17SEtienne Carriere 	else
4696e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RW_PUBLIC_SESSION;
4706e4f8f17SEtienne Carriere 
4716e4f8f17SEtienne Carriere 	/*
4726e4f8f17SEtienne Carriere 	 * No need to check all client sessions, the first found in
4736e4f8f17SEtienne Carriere 	 * target token gives client login configuration.
4746e4f8f17SEtienne Carriere 	 */
4756e4f8f17SEtienne Carriere 	TAILQ_FOREACH(sess, &client->session_list, link) {
4766e4f8f17SEtienne Carriere 		assert(sess != session);
4776e4f8f17SEtienne Carriere 
4786e4f8f17SEtienne Carriere 		if (sess->token == session->token) {
4796e4f8f17SEtienne Carriere 			switch (sess->state) {
4806e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_PUBLIC_SESSION:
4816e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_PUBLIC_SESSION:
4826e4f8f17SEtienne Carriere 				if (readonly)
4836e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_PUBLIC_SESSION;
4846e4f8f17SEtienne Carriere 				else
4856e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_PUBLIC_SESSION;
4866e4f8f17SEtienne Carriere 				break;
4876e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_USER_FUNCTIONS:
4886e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_USER_FUNCTIONS:
4896e4f8f17SEtienne Carriere 				if (readonly)
4906e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_USER_FUNCTIONS;
4916e4f8f17SEtienne Carriere 				else
4926e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_USER_FUNCTIONS;
4936e4f8f17SEtienne Carriere 				break;
4946e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_SO_FUNCTIONS:
4956e4f8f17SEtienne Carriere 				if (readonly)
4966e4f8f17SEtienne Carriere 					TEE_Panic(0);
4976e4f8f17SEtienne Carriere 				else
4986e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_SO_FUNCTIONS;
4996e4f8f17SEtienne Carriere 				break;
5006e4f8f17SEtienne Carriere 			default:
5016e4f8f17SEtienne Carriere 				TEE_Panic(0);
5026e4f8f17SEtienne Carriere 			}
5036e4f8f17SEtienne Carriere 			break;
5046e4f8f17SEtienne Carriere 		}
5056e4f8f17SEtienne Carriere 	}
5066e4f8f17SEtienne Carriere 
5076e4f8f17SEtienne Carriere 	session->state = state;
5086e4f8f17SEtienne Carriere }
5096e4f8f17SEtienne Carriere 
5106e4f8f17SEtienne Carriere uint32_t entry_ck_open_session(struct pkcs11_client *client,
5116e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
5126e4f8f17SEtienne Carriere {
5136e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
5146e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
5156e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
5166e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
5176e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
5186e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
5196e4f8f17SEtienne Carriere 	uint32_t rv = 0;
5206e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
5216e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
5226e4f8f17SEtienne Carriere 	uint32_t flags = 0;
5236e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
5246e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
5256e4f8f17SEtienne Carriere 	bool readonly = false;
5266e4f8f17SEtienne Carriere 
5276e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt ||
5286e4f8f17SEtienne Carriere 	    out->memref.size != sizeof(session->handle))
5296e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5306e4f8f17SEtienne Carriere 
5316e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
5326e4f8f17SEtienne Carriere 
5336e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
5346e4f8f17SEtienne Carriere 	if (rv)
5356e4f8f17SEtienne Carriere 		return rv;
5366e4f8f17SEtienne Carriere 
5376e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &flags, sizeof(flags));
5386e4f8f17SEtienne Carriere 	if (rv)
5396e4f8f17SEtienne Carriere 		return rv;
5406e4f8f17SEtienne Carriere 
5416e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
5426e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5436e4f8f17SEtienne Carriere 
5446e4f8f17SEtienne Carriere 	token = get_token(token_id);
5456e4f8f17SEtienne Carriere 	if (!token)
5466e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
5476e4f8f17SEtienne Carriere 
5486e4f8f17SEtienne Carriere 	/* Sanitize session flags */
5496e4f8f17SEtienne Carriere 	if (!(flags & PKCS11_CKFSS_SERIAL_SESSION) ||
5506e4f8f17SEtienne Carriere 	    (flags & ~(PKCS11_CKFSS_RW_SESSION |
5516e4f8f17SEtienne Carriere 		       PKCS11_CKFSS_SERIAL_SESSION)))
5526e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5536e4f8f17SEtienne Carriere 
5546e4f8f17SEtienne Carriere 	readonly = !(flags & PKCS11_CKFSS_RW_SESSION);
5556e4f8f17SEtienne Carriere 
5566e4f8f17SEtienne Carriere 	if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY)
5576e4f8f17SEtienne Carriere 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
5586e4f8f17SEtienne Carriere 
5596e4f8f17SEtienne Carriere 	if (readonly) {
5606e4f8f17SEtienne Carriere 		/* Specifically reject read-only session under SO login */
5616e4f8f17SEtienne Carriere 		TAILQ_FOREACH(session, &client->session_list, link)
5626e4f8f17SEtienne Carriere 			if (pkcs11_session_is_so(session))
5636e4f8f17SEtienne Carriere 				return PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS;
5646e4f8f17SEtienne Carriere 	}
5656e4f8f17SEtienne Carriere 
5666e4f8f17SEtienne Carriere 	session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO);
5676e4f8f17SEtienne Carriere 	if (!session)
5686e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5696e4f8f17SEtienne Carriere 
5706e4f8f17SEtienne Carriere 	session->handle = handle_get(&client->session_handle_db, session);
5716e4f8f17SEtienne Carriere 	if (!session->handle) {
5726e4f8f17SEtienne Carriere 		TEE_Free(session);
5736e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5746e4f8f17SEtienne Carriere 	}
5756e4f8f17SEtienne Carriere 
5766e4f8f17SEtienne Carriere 	session->token = token;
5776e4f8f17SEtienne Carriere 	session->client = client;
5786e4f8f17SEtienne Carriere 
5796e4f8f17SEtienne Carriere 	set_session_state(client, session, readonly);
5806e4f8f17SEtienne Carriere 
5816e4f8f17SEtienne Carriere 	TAILQ_INSERT_HEAD(&client->session_list, session, link);
5826e4f8f17SEtienne Carriere 
5836e4f8f17SEtienne Carriere 	session->token->session_count++;
5846e4f8f17SEtienne Carriere 	if (!readonly)
5856e4f8f17SEtienne Carriere 		session->token->rw_session_count++;
5866e4f8f17SEtienne Carriere 
5876e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &session->handle,
5886e4f8f17SEtienne Carriere 		    sizeof(session->handle));
5896e4f8f17SEtienne Carriere 
5906e4f8f17SEtienne Carriere 	DMSG("Open PKCS11 session %"PRIu32, session->handle);
5916e4f8f17SEtienne Carriere 
5926e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
5936e4f8f17SEtienne Carriere }
5946e4f8f17SEtienne Carriere 
5956e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session)
5966e4f8f17SEtienne Carriere {
5976e4f8f17SEtienne Carriere 	TAILQ_REMOVE(&session->client->session_list, session, link);
5986e4f8f17SEtienne Carriere 	handle_put(&session->client->session_handle_db, session->handle);
5996e4f8f17SEtienne Carriere 
6006e4f8f17SEtienne Carriere 	session->token->session_count--;
6016e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
6026e4f8f17SEtienne Carriere 		session->token->rw_session_count--;
6036e4f8f17SEtienne Carriere 
6046e4f8f17SEtienne Carriere 	TEE_Free(session);
6056e4f8f17SEtienne Carriere 
6066e4f8f17SEtienne Carriere 	DMSG("Close PKCS11 session %"PRIu32, session->handle);
6076e4f8f17SEtienne Carriere }
6086e4f8f17SEtienne Carriere 
6096e4f8f17SEtienne Carriere uint32_t entry_ck_close_session(struct pkcs11_client *client,
6106e4f8f17SEtienne Carriere 				uint32_t ptypes, TEE_Param *params)
6116e4f8f17SEtienne Carriere {
6126e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6136e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6146e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6156e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6166e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6176e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6186e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6196e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
6206e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6216e4f8f17SEtienne Carriere 
6226e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6236e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6246e4f8f17SEtienne Carriere 
6256e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6266e4f8f17SEtienne Carriere 
6276e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
6286e4f8f17SEtienne Carriere 	if (rv)
6296e4f8f17SEtienne Carriere 		return rv;
6306e4f8f17SEtienne Carriere 
6316e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6326e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6336e4f8f17SEtienne Carriere 
6346e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
6356e4f8f17SEtienne Carriere 	if (!session)
6366e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
6376e4f8f17SEtienne Carriere 
6386e4f8f17SEtienne Carriere 	close_ck_session(session);
6396e4f8f17SEtienne Carriere 
6406e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6416e4f8f17SEtienne Carriere }
6426e4f8f17SEtienne Carriere 
6436e4f8f17SEtienne Carriere uint32_t entry_ck_close_all_sessions(struct pkcs11_client *client,
6446e4f8f17SEtienne Carriere 				     uint32_t ptypes, TEE_Param *params)
6456e4f8f17SEtienne Carriere {
6466e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6476e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6486e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6496e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6506e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6516e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6526e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6536e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
6546e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
6556e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6566e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
6576e4f8f17SEtienne Carriere 
6586e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6596e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6606e4f8f17SEtienne Carriere 
6616e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6626e4f8f17SEtienne Carriere 
6636e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
6646e4f8f17SEtienne Carriere 	if (rv)
6656e4f8f17SEtienne Carriere 		return rv;
6666e4f8f17SEtienne Carriere 
6676e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6686e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6696e4f8f17SEtienne Carriere 
6706e4f8f17SEtienne Carriere 	token = get_token(token_id);
6716e4f8f17SEtienne Carriere 	if (!token)
6726e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
6736e4f8f17SEtienne Carriere 
6746e4f8f17SEtienne Carriere 	DMSG("Close all sessions for PKCS11 token %"PRIu32, token_id);
6756e4f8f17SEtienne Carriere 
6766e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
6776e4f8f17SEtienne Carriere 		if (session->token == token)
6786e4f8f17SEtienne Carriere 			close_ck_session(session);
6796e4f8f17SEtienne Carriere 
6806e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6816e4f8f17SEtienne Carriere }
6826e4f8f17SEtienne Carriere 
6836e4f8f17SEtienne Carriere uint32_t entry_ck_session_info(struct pkcs11_client *client,
6846e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
6856e4f8f17SEtienne Carriere {
6866e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6876e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6886e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
6896e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6906e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6916e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
6926e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6936e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6946e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
6956e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6966e4f8f17SEtienne Carriere 	struct pkcs11_session_info info = {
6976e4f8f17SEtienne Carriere 		.flags = PKCS11_CKFSS_SERIAL_SESSION,
6986e4f8f17SEtienne Carriere 	};
6996e4f8f17SEtienne Carriere 
7006e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt || out->memref.size != sizeof(info))
7016e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7026e4f8f17SEtienne Carriere 
7036e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
7046e4f8f17SEtienne Carriere 
7056e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
7066e4f8f17SEtienne Carriere 	if (rv)
7076e4f8f17SEtienne Carriere 		return rv;
7086e4f8f17SEtienne Carriere 
7096e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
7106e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7116e4f8f17SEtienne Carriere 
7126e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
7136e4f8f17SEtienne Carriere 	if (!session)
7146e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
7156e4f8f17SEtienne Carriere 
7166e4f8f17SEtienne Carriere 	info.slot_id = get_token_id(session->token);
7176e4f8f17SEtienne Carriere 	info.state = session->state;
7186e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
7196e4f8f17SEtienne Carriere 		info.flags |= PKCS11_CKFSS_RW_SESSION;
7206e4f8f17SEtienne Carriere 
7216e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
7226e4f8f17SEtienne Carriere 
7236e4f8f17SEtienne Carriere 	DMSG("Get find on PKCS11 session %"PRIu32, session->handle);
7246e4f8f17SEtienne Carriere 
7256e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7266e4f8f17SEtienne Carriere }
727f485be04SJens Wiklander 
728f485be04SJens Wiklander uint32_t entry_ck_token_initialize(uint32_t ptypes, TEE_Param *params)
729f485be04SJens Wiklander {
730f485be04SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
731f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
732f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
733f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE);
734f485be04SJens Wiklander 	char label[PKCS11_TOKEN_LABEL_SIZE] = { 0 };
735f485be04SJens Wiklander 	struct pkcs11_client *client = NULL;
736f485be04SJens Wiklander 	struct pkcs11_session *sess = NULL;
737f485be04SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
738f485be04SJens Wiklander 	struct serialargs ctrlargs = { };
739f485be04SJens Wiklander 	struct ck_token *token = NULL;
740f485be04SJens Wiklander 	TEE_Param *ctrl = params;
741f485be04SJens Wiklander 	uint32_t token_id = 0;
742f485be04SJens Wiklander 	uint32_t pin_size = 0;
743f485be04SJens Wiklander 	void *pin = NULL;
744f485be04SJens Wiklander 
745f485be04SJens Wiklander 	if (ptypes != exp_pt)
746f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
747f485be04SJens Wiklander 
748f485be04SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
749f485be04SJens Wiklander 
750f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
751f485be04SJens Wiklander 	if (rc)
752f485be04SJens Wiklander 		return rc;
753f485be04SJens Wiklander 
754f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
755f485be04SJens Wiklander 	if (rc)
756f485be04SJens Wiklander 		return rc;
757f485be04SJens Wiklander 
758f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &label, PKCS11_TOKEN_LABEL_SIZE);
759f485be04SJens Wiklander 	if (rc)
760f485be04SJens Wiklander 		return rc;
761f485be04SJens Wiklander 
762f485be04SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
763f485be04SJens Wiklander 	if (rc)
764f485be04SJens Wiklander 		return rc;
765f485be04SJens Wiklander 
766f485be04SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
767f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
768f485be04SJens Wiklander 
769f485be04SJens Wiklander 	token = get_token(token_id);
770f485be04SJens Wiklander 	if (!token)
771f485be04SJens Wiklander 		return PKCS11_CKR_SLOT_ID_INVALID;
772f485be04SJens Wiklander 
773f485be04SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) {
774f485be04SJens Wiklander 		IMSG("Token %"PRIu32": SO PIN locked", token_id);
775f485be04SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
776f485be04SJens Wiklander 	}
777f485be04SJens Wiklander 
778f485be04SJens Wiklander 	/* Check there's no open session on this token */
779f485be04SJens Wiklander 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
780f485be04SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
781f485be04SJens Wiklander 			if (sess->token == token)
782f485be04SJens Wiklander 				return PKCS11_CKR_SESSION_EXISTS;
783f485be04SJens Wiklander 
784f485be04SJens Wiklander 	if (!token->db_main->so_pin_salt) {
785f485be04SJens Wiklander 		/*
786f485be04SJens Wiklander 		 * The spec doesn't permit returning
787f485be04SJens Wiklander 		 * PKCS11_CKR_PIN_LEN_RANGE for this function, take another
788f485be04SJens Wiklander 		 * error code.
789f485be04SJens Wiklander 		 */
790f485be04SJens Wiklander 		if (pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
791f485be04SJens Wiklander 		    pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
792f485be04SJens Wiklander 			return PKCS11_CKR_ARGUMENTS_BAD;
793f485be04SJens Wiklander 
794f485be04SJens Wiklander 		rc = hash_pin(PKCS11_CKU_SO, pin, pin_size,
795f485be04SJens Wiklander 			      &token->db_main->so_pin_salt,
796f485be04SJens Wiklander 			      token->db_main->so_pin_hash);
797f485be04SJens Wiklander 		if (rc)
798f485be04SJens Wiklander 			return rc;
799f485be04SJens Wiklander 
800f485be04SJens Wiklander 		update_persistent_db(token);
801f485be04SJens Wiklander 
802f485be04SJens Wiklander 		goto inited;
803f485be04SJens Wiklander 	}
804f485be04SJens Wiklander 
805f485be04SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
806f485be04SJens Wiklander 			token->db_main->so_pin_salt,
807f485be04SJens Wiklander 			token->db_main->so_pin_hash);
808f485be04SJens Wiklander 	if (rc) {
809f485be04SJens Wiklander 		unsigned int pin_count = 0;
810f485be04SJens Wiklander 
811f485be04SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
812f485be04SJens Wiklander 			return rc;
813f485be04SJens Wiklander 
814f485be04SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
815f485be04SJens Wiklander 		token->db_main->so_pin_count++;
816f485be04SJens Wiklander 
817f485be04SJens Wiklander 		pin_count = token->db_main->so_pin_count;
818f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
819f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
820f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
821f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
822f485be04SJens Wiklander 
823f485be04SJens Wiklander 		update_persistent_db(token);
824f485be04SJens Wiklander 
825f485be04SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
826f485be04SJens Wiklander 	}
827f485be04SJens Wiklander 
828f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
829f485be04SJens Wiklander 				   PKCS11_CKFT_SO_PIN_FINAL_TRY);
830f485be04SJens Wiklander 	token->db_main->so_pin_count = 0;
831f485be04SJens Wiklander 
832f485be04SJens Wiklander inited:
833f485be04SJens Wiklander 	TEE_MemMove(token->db_main->label, label, PKCS11_TOKEN_LABEL_SIZE);
834f485be04SJens Wiklander 	token->db_main->flags |= PKCS11_CKFT_TOKEN_INITIALIZED;
835f485be04SJens Wiklander 	/* Reset user PIN */
836f485be04SJens Wiklander 	token->db_main->user_pin_salt = 0;
837f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_INITIALIZED |
838f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_COUNT_LOW |
839f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_FINAL_TRY |
840f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_LOCKED |
841f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_TO_BE_CHANGED);
842f485be04SJens Wiklander 
843f485be04SJens Wiklander 	update_persistent_db(token);
844f485be04SJens Wiklander 
845f485be04SJens Wiklander 	IMSG("PKCS11 token %"PRIu32": initialized", token_id);
846f485be04SJens Wiklander 
847f485be04SJens Wiklander 	return PKCS11_CKR_OK;
848f485be04SJens Wiklander }
849e8dbd92cSJens Wiklander 
850e8dbd92cSJens Wiklander static enum pkcs11_rc set_pin(struct pkcs11_session *session,
851e8dbd92cSJens Wiklander 			      uint8_t *new_pin, size_t new_pin_size,
852e8dbd92cSJens Wiklander 			      enum pkcs11_user_type user_type)
853e8dbd92cSJens Wiklander {
854e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
855e8dbd92cSJens Wiklander 	uint32_t flags_clear = 0;
856e8dbd92cSJens Wiklander 	uint32_t flags_set = 0;
857e8dbd92cSJens Wiklander 
858e8dbd92cSJens Wiklander 	if (session->token->db_main->flags & PKCS11_CKFT_WRITE_PROTECTED)
859e8dbd92cSJens Wiklander 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
860e8dbd92cSJens Wiklander 
861e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_read_write(session))
862e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
863e8dbd92cSJens Wiklander 
864e8dbd92cSJens Wiklander 	if (new_pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
865e8dbd92cSJens Wiklander 	    new_pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
866e8dbd92cSJens Wiklander 		return PKCS11_CKR_PIN_LEN_RANGE;
867e8dbd92cSJens Wiklander 
868e8dbd92cSJens Wiklander 	switch (user_type) {
869e8dbd92cSJens Wiklander 	case PKCS11_CKU_SO:
870e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
871e8dbd92cSJens Wiklander 			      &session->token->db_main->so_pin_salt,
872e8dbd92cSJens Wiklander 			      session->token->db_main->so_pin_hash);
873e8dbd92cSJens Wiklander 		if (rc)
874e8dbd92cSJens Wiklander 			return rc;
875e8dbd92cSJens Wiklander 		session->token->db_main->so_pin_count = 0;
876e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_SO_PIN_COUNT_LOW |
877e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_FINAL_TRY |
878e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_LOCKED |
879e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_TO_BE_CHANGED;
880e8dbd92cSJens Wiklander 		break;
881e8dbd92cSJens Wiklander 	case PKCS11_CKU_USER:
882e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
883e8dbd92cSJens Wiklander 			      &session->token->db_main->user_pin_salt,
884e8dbd92cSJens Wiklander 			      session->token->db_main->user_pin_hash);
885e8dbd92cSJens Wiklander 		if (rc)
886e8dbd92cSJens Wiklander 			return rc;
887e8dbd92cSJens Wiklander 		session->token->db_main->user_pin_count = 0;
888e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_USER_PIN_COUNT_LOW |
889e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_FINAL_TRY |
890e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_LOCKED |
891e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_TO_BE_CHANGED;
892e8dbd92cSJens Wiklander 		flags_set = PKCS11_CKFT_USER_PIN_INITIALIZED;
893e8dbd92cSJens Wiklander 		break;
894e8dbd92cSJens Wiklander 	default:
895e8dbd92cSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
896e8dbd92cSJens Wiklander 	}
897e8dbd92cSJens Wiklander 
898e8dbd92cSJens Wiklander 	session->token->db_main->flags &= ~flags_clear;
899e8dbd92cSJens Wiklander 	session->token->db_main->flags |= flags_set;
900e8dbd92cSJens Wiklander 
901e8dbd92cSJens Wiklander 	update_persistent_db(session->token);
902e8dbd92cSJens Wiklander 
903e8dbd92cSJens Wiklander 	return PKCS11_CKR_OK;
904e8dbd92cSJens Wiklander }
905e8dbd92cSJens Wiklander 
906e8dbd92cSJens Wiklander uint32_t entry_ck_init_pin(struct pkcs11_client *client,
907e8dbd92cSJens Wiklander 			   uint32_t ptypes, TEE_Param *params)
908e8dbd92cSJens Wiklander {
909e8dbd92cSJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
910e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
911e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
912e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE);
913e8dbd92cSJens Wiklander 	struct pkcs11_session *session = NULL;
914e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
915e8dbd92cSJens Wiklander 	struct serialargs ctrlargs = { };
916e8dbd92cSJens Wiklander 	uint32_t session_handle = 0;
917e8dbd92cSJens Wiklander 	TEE_Param *ctrl = params;
918e8dbd92cSJens Wiklander 	uint32_t pin_size = 0;
919e8dbd92cSJens Wiklander 	void *pin = NULL;
920e8dbd92cSJens Wiklander 
921e8dbd92cSJens Wiklander 	if (!client || ptypes != exp_pt)
922e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
923e8dbd92cSJens Wiklander 
924e8dbd92cSJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
925e8dbd92cSJens Wiklander 
926e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
927e8dbd92cSJens Wiklander 	if (rc)
928e8dbd92cSJens Wiklander 		return rc;
929e8dbd92cSJens Wiklander 
930e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
931e8dbd92cSJens Wiklander 	if (rc)
932e8dbd92cSJens Wiklander 		return rc;
933e8dbd92cSJens Wiklander 
934e8dbd92cSJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
935e8dbd92cSJens Wiklander 	if (rc)
936e8dbd92cSJens Wiklander 		return rc;
937e8dbd92cSJens Wiklander 
938e8dbd92cSJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
939e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
940e8dbd92cSJens Wiklander 
941e8dbd92cSJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
942e8dbd92cSJens Wiklander 	if (!session)
943e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
944e8dbd92cSJens Wiklander 
945e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_so(session))
946e8dbd92cSJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
947e8dbd92cSJens Wiklander 
948e8dbd92cSJens Wiklander 	assert(session->token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
949e8dbd92cSJens Wiklander 
950e8dbd92cSJens Wiklander 	IMSG("PKCS11 session %"PRIu32": init PIN", session_handle);
951e8dbd92cSJens Wiklander 
952e8dbd92cSJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
953e8dbd92cSJens Wiklander }
9541dbb91e7SJens Wiklander 
9551dbb91e7SJens Wiklander static uint32_t check_so_pin(struct pkcs11_session *session,
9561dbb91e7SJens Wiklander 			     uint8_t *pin, size_t pin_size)
9571dbb91e7SJens Wiklander {
9581dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
9591dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
9601dbb91e7SJens Wiklander 
9611dbb91e7SJens Wiklander 	assert(token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
9621dbb91e7SJens Wiklander 
9631dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
9641dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
9651dbb91e7SJens Wiklander 
9661dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
9671dbb91e7SJens Wiklander 			token->db_main->so_pin_salt,
9681dbb91e7SJens Wiklander 			token->db_main->so_pin_hash);
9691dbb91e7SJens Wiklander 	if (rc) {
9701dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
9711dbb91e7SJens Wiklander 
9721dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
9731dbb91e7SJens Wiklander 			return rc;
9741dbb91e7SJens Wiklander 
9751dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
9761dbb91e7SJens Wiklander 		token->db_main->so_pin_count++;
9771dbb91e7SJens Wiklander 
9781dbb91e7SJens Wiklander 		pin_count = token->db_main->so_pin_count;
9791dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
9801dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
9811dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
9821dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
9831dbb91e7SJens Wiklander 
9841dbb91e7SJens Wiklander 		update_persistent_db(token);
9851dbb91e7SJens Wiklander 
9861dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
9871dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
9881dbb91e7SJens Wiklander 
9891dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
9901dbb91e7SJens Wiklander 	}
9911dbb91e7SJens Wiklander 
9921dbb91e7SJens Wiklander 	if (token->db_main->so_pin_count) {
9931dbb91e7SJens Wiklander 		token->db_main->so_pin_count = 0;
9941dbb91e7SJens Wiklander 
9951dbb91e7SJens Wiklander 		update_persistent_db(token);
9961dbb91e7SJens Wiklander 	}
9971dbb91e7SJens Wiklander 
9981dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_SO_PIN_COUNT_LOW |
9991dbb91e7SJens Wiklander 				     PKCS11_CKFT_SO_PIN_FINAL_TRY)) {
10001dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
10011dbb91e7SJens Wiklander 					   PKCS11_CKFT_SO_PIN_FINAL_TRY);
10021dbb91e7SJens Wiklander 
10031dbb91e7SJens Wiklander 		update_persistent_db(token);
10041dbb91e7SJens Wiklander 	}
10051dbb91e7SJens Wiklander 
10061dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
10071dbb91e7SJens Wiklander }
10081dbb91e7SJens Wiklander 
10091dbb91e7SJens Wiklander static uint32_t check_user_pin(struct pkcs11_session *session,
10101dbb91e7SJens Wiklander 			       uint8_t *pin, size_t pin_size)
10111dbb91e7SJens Wiklander {
10121dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
10131dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
10141dbb91e7SJens Wiklander 
10151dbb91e7SJens Wiklander 	if (!token->db_main->user_pin_salt)
10161dbb91e7SJens Wiklander 		return PKCS11_CKR_USER_PIN_NOT_INITIALIZED;
10171dbb91e7SJens Wiklander 
10181dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
10191dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
10201dbb91e7SJens Wiklander 
10211dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_USER, pin, pin_size,
10221dbb91e7SJens Wiklander 			token->db_main->user_pin_salt,
10231dbb91e7SJens Wiklander 			token->db_main->user_pin_hash);
10241dbb91e7SJens Wiklander 	if (rc) {
10251dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
10261dbb91e7SJens Wiklander 
10271dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
10281dbb91e7SJens Wiklander 			return rc;
10291dbb91e7SJens Wiklander 
10301dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_USER_PIN_COUNT_LOW;
10311dbb91e7SJens Wiklander 		token->db_main->user_pin_count++;
10321dbb91e7SJens Wiklander 
10331dbb91e7SJens Wiklander 		pin_count = token->db_main->user_pin_count;
10341dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX - 1)
10351dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_FINAL_TRY;
10361dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX)
10371dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_LOCKED;
10381dbb91e7SJens Wiklander 
10391dbb91e7SJens Wiklander 		update_persistent_db(token);
10401dbb91e7SJens Wiklander 
10411dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
10421dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
10431dbb91e7SJens Wiklander 
10441dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
10451dbb91e7SJens Wiklander 	}
10461dbb91e7SJens Wiklander 
10471dbb91e7SJens Wiklander 	if (token->db_main->user_pin_count) {
10481dbb91e7SJens Wiklander 		token->db_main->user_pin_count = 0;
10491dbb91e7SJens Wiklander 
10501dbb91e7SJens Wiklander 		update_persistent_db(token);
10511dbb91e7SJens Wiklander 	}
10521dbb91e7SJens Wiklander 
10531dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_USER_PIN_COUNT_LOW |
10541dbb91e7SJens Wiklander 				     PKCS11_CKFT_USER_PIN_FINAL_TRY)) {
10551dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_COUNT_LOW |
10561dbb91e7SJens Wiklander 					   PKCS11_CKFT_USER_PIN_FINAL_TRY);
10571dbb91e7SJens Wiklander 
10581dbb91e7SJens Wiklander 		update_persistent_db(token);
10591dbb91e7SJens Wiklander 	}
10601dbb91e7SJens Wiklander 
10611dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
10621dbb91e7SJens Wiklander }
10631dbb91e7SJens Wiklander 
10641dbb91e7SJens Wiklander uint32_t entry_ck_set_pin(struct pkcs11_client *client,
10651dbb91e7SJens Wiklander 			  uint32_t ptypes, TEE_Param *params)
10661dbb91e7SJens Wiklander {
10671dbb91e7SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
10681dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
10691dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
10701dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE);
10711dbb91e7SJens Wiklander 	struct pkcs11_session *session = NULL;
10721dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
10731dbb91e7SJens Wiklander 	struct serialargs ctrlargs = { };
10741dbb91e7SJens Wiklander 	uint32_t session_handle = 0;
10751dbb91e7SJens Wiklander 	uint32_t old_pin_size = 0;
10761dbb91e7SJens Wiklander 	TEE_Param *ctrl = params;
10771dbb91e7SJens Wiklander 	uint32_t pin_size = 0;
10781dbb91e7SJens Wiklander 	void *old_pin = NULL;
10791dbb91e7SJens Wiklander 	void *pin = NULL;
10801dbb91e7SJens Wiklander 
10811dbb91e7SJens Wiklander 	if (!client || ptypes != exp_pt)
10821dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
10831dbb91e7SJens Wiklander 
10841dbb91e7SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
10851dbb91e7SJens Wiklander 
10861dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
10871dbb91e7SJens Wiklander 	if (rc)
10881dbb91e7SJens Wiklander 		return rc;
10891dbb91e7SJens Wiklander 
10901dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &old_pin_size, sizeof(uint32_t));
10911dbb91e7SJens Wiklander 	if (rc)
10921dbb91e7SJens Wiklander 		return rc;
10931dbb91e7SJens Wiklander 
10941dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
10951dbb91e7SJens Wiklander 	if (rc)
10961dbb91e7SJens Wiklander 		return rc;
10971dbb91e7SJens Wiklander 
10981dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &old_pin, old_pin_size);
10991dbb91e7SJens Wiklander 	if (rc)
11001dbb91e7SJens Wiklander 		return rc;
11011dbb91e7SJens Wiklander 
11021dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
11031dbb91e7SJens Wiklander 	if (rc)
11041dbb91e7SJens Wiklander 		return rc;
11051dbb91e7SJens Wiklander 
11061dbb91e7SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
11071dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
11081dbb91e7SJens Wiklander 
11091dbb91e7SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
11101dbb91e7SJens Wiklander 	if (!session)
11111dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
11121dbb91e7SJens Wiklander 
11131dbb91e7SJens Wiklander 	if (!pkcs11_session_is_read_write(session))
11141dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
11151dbb91e7SJens Wiklander 
11161dbb91e7SJens Wiklander 	if (pkcs11_session_is_so(session)) {
11171dbb91e7SJens Wiklander 		if (!(session->token->db_main->flags &
11181dbb91e7SJens Wiklander 		      PKCS11_CKFT_TOKEN_INITIALIZED))
11191dbb91e7SJens Wiklander 			return PKCS11_CKR_GENERAL_ERROR;
11201dbb91e7SJens Wiklander 
11211dbb91e7SJens Wiklander 		rc = check_so_pin(session, old_pin, old_pin_size);
11221dbb91e7SJens Wiklander 		if (rc)
11231dbb91e7SJens Wiklander 			return rc;
11241dbb91e7SJens Wiklander 
11251dbb91e7SJens Wiklander 		IMSG("PKCS11 session %"PRIu32": set PIN", session_handle);
11261dbb91e7SJens Wiklander 
11271dbb91e7SJens Wiklander 		return set_pin(session, pin, pin_size, PKCS11_CKU_SO);
11281dbb91e7SJens Wiklander 	}
11291dbb91e7SJens Wiklander 
11301dbb91e7SJens Wiklander 	if (!(session->token->db_main->flags &
11311dbb91e7SJens Wiklander 	      PKCS11_CKFT_USER_PIN_INITIALIZED))
11321dbb91e7SJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
11331dbb91e7SJens Wiklander 
11341dbb91e7SJens Wiklander 	rc = check_user_pin(session, old_pin, old_pin_size);
11351dbb91e7SJens Wiklander 	if (rc)
11361dbb91e7SJens Wiklander 		return rc;
11371dbb91e7SJens Wiklander 
11381dbb91e7SJens Wiklander 	IMSG("PKCS11 session %"PRIu32": set PIN", session_handle);
11391dbb91e7SJens Wiklander 
11401dbb91e7SJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
11411dbb91e7SJens Wiklander }
1142f7cc36c0SJens Wiklander 
1143f7cc36c0SJens Wiklander static void session_login_user(struct pkcs11_session *session)
1144f7cc36c0SJens Wiklander {
1145f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1146f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1147f7cc36c0SJens Wiklander 
1148f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1149f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1150f7cc36c0SJens Wiklander 			continue;
1151f7cc36c0SJens Wiklander 
1152f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1153f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_USER_FUNCTIONS;
1154f7cc36c0SJens Wiklander 		else
1155f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_USER_FUNCTIONS;
1156f7cc36c0SJens Wiklander 	}
1157f7cc36c0SJens Wiklander }
1158f7cc36c0SJens Wiklander 
1159f7cc36c0SJens Wiklander static void session_login_so(struct pkcs11_session *session)
1160f7cc36c0SJens Wiklander {
1161f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1162f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1163f7cc36c0SJens Wiklander 
1164f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1165f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1166f7cc36c0SJens Wiklander 			continue;
1167f7cc36c0SJens Wiklander 
1168f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1169f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_SO_FUNCTIONS;
1170f7cc36c0SJens Wiklander 		else
1171f7cc36c0SJens Wiklander 			TEE_Panic(0);
1172f7cc36c0SJens Wiklander 	}
1173f7cc36c0SJens Wiklander }
1174f7cc36c0SJens Wiklander 
1175f7cc36c0SJens Wiklander static void session_logout(struct pkcs11_session *session)
1176f7cc36c0SJens Wiklander {
1177f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1178f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1179f7cc36c0SJens Wiklander 
1180f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1181f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1182f7cc36c0SJens Wiklander 			continue;
1183f7cc36c0SJens Wiklander 
1184f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1185f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_PUBLIC_SESSION;
1186f7cc36c0SJens Wiklander 		else
1187f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_PUBLIC_SESSION;
1188f7cc36c0SJens Wiklander 	}
1189f7cc36c0SJens Wiklander }
1190f7cc36c0SJens Wiklander 
1191f7cc36c0SJens Wiklander uint32_t entry_ck_login(struct pkcs11_client *client,
1192f7cc36c0SJens Wiklander 			uint32_t ptypes, TEE_Param *params)
1193f7cc36c0SJens Wiklander {
1194f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1195f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1196f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1197f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1198f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1199f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1200f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1201f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1202f7cc36c0SJens Wiklander 	uint32_t session_handle = 0;
1203f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1204f7cc36c0SJens Wiklander 	uint32_t user_type = 0;
1205f7cc36c0SJens Wiklander 	uint32_t pin_size = 0;
1206f7cc36c0SJens Wiklander 	void *pin = NULL;
1207f7cc36c0SJens Wiklander 
1208f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1209f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1210f7cc36c0SJens Wiklander 
1211f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1212f7cc36c0SJens Wiklander 
1213f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
1214f7cc36c0SJens Wiklander 	if (rc)
1215f7cc36c0SJens Wiklander 		return rc;
1216f7cc36c0SJens Wiklander 
1217f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &user_type, sizeof(uint32_t));
1218f7cc36c0SJens Wiklander 	if (rc)
1219f7cc36c0SJens Wiklander 		return rc;
1220f7cc36c0SJens Wiklander 
1221f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
1222f7cc36c0SJens Wiklander 	if (rc)
1223f7cc36c0SJens Wiklander 		return rc;
1224f7cc36c0SJens Wiklander 
1225f7cc36c0SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
1226f7cc36c0SJens Wiklander 	if (rc)
1227f7cc36c0SJens Wiklander 		return rc;
1228f7cc36c0SJens Wiklander 
1229f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1230f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1231f7cc36c0SJens Wiklander 
1232f7cc36c0SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
1233f7cc36c0SJens Wiklander 	if (!session)
1234f7cc36c0SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
1235f7cc36c0SJens Wiklander 
1236f7cc36c0SJens Wiklander 	switch (user_type) {
1237f7cc36c0SJens Wiklander 	case PKCS11_CKU_SO:
1238f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1239f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1240f7cc36c0SJens Wiklander 
1241f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1242f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1243f7cc36c0SJens Wiklander 
1244f7cc36c0SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
1245f7cc36c0SJens Wiklander 			if (sess->token == session->token &&
1246f7cc36c0SJens Wiklander 			    !pkcs11_session_is_read_write(sess))
1247f7cc36c0SJens Wiklander 				return PKCS11_CKR_SESSION_READ_ONLY_EXISTS;
1248f7cc36c0SJens Wiklander 
1249f7cc36c0SJens Wiklander 		/*
1250f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1251f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1252f7cc36c0SJens Wiklander 		 *
1253f7cc36c0SJens Wiklander 		 * The spec says:
1254f7cc36c0SJens Wiklander 		 * CKR_USER_TOO_MANY_TYPES: An attempt was made to have
1255f7cc36c0SJens Wiklander 		 * more distinct users simultaneously logged into the token
1256f7cc36c0SJens Wiklander 		 * than the token and/or library permits. For example, if
1257f7cc36c0SJens Wiklander 		 * some application has an open SO session, and another
1258f7cc36c0SJens Wiklander 		 * application attempts to log the normal user into a
1259f7cc36c0SJens Wiklander 		 * session, the attempt may return this error. It is not
1260f7cc36c0SJens Wiklander 		 * required to, however. Only if the simultaneous distinct
1261f7cc36c0SJens Wiklander 		 * users cannot be supported does C_Login have to return
1262f7cc36c0SJens Wiklander 		 * this value. Note that this error code generalizes to
1263f7cc36c0SJens Wiklander 		 * true multi-user tokens.
1264f7cc36c0SJens Wiklander 		 *
1265f7cc36c0SJens Wiklander 		 * So it's permitted to have another user or SO logged in
1266f7cc36c0SJens Wiklander 		 * from another client.
1267f7cc36c0SJens Wiklander 		 */
1268f7cc36c0SJens Wiklander 
1269f7cc36c0SJens Wiklander 		rc = check_so_pin(session, pin, pin_size);
1270f7cc36c0SJens Wiklander 		if (!rc)
1271f7cc36c0SJens Wiklander 			session_login_so(session);
1272f7cc36c0SJens Wiklander 
1273f7cc36c0SJens Wiklander 		break;
1274f7cc36c0SJens Wiklander 
1275f7cc36c0SJens Wiklander 	case PKCS11_CKU_USER:
1276f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1277f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1278f7cc36c0SJens Wiklander 
1279f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1280f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1281f7cc36c0SJens Wiklander 
1282f7cc36c0SJens Wiklander 		/*
1283f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1284f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1285f7cc36c0SJens Wiklander 		 * See comment on CKR_USER_TOO_MANY_TYPES above.
1286f7cc36c0SJens Wiklander 		 */
1287f7cc36c0SJens Wiklander 
1288f7cc36c0SJens Wiklander 		rc = check_user_pin(session, pin, pin_size);
1289f7cc36c0SJens Wiklander 		if (!rc)
1290f7cc36c0SJens Wiklander 			session_login_user(session);
1291f7cc36c0SJens Wiklander 
1292f7cc36c0SJens Wiklander 		break;
1293f7cc36c0SJens Wiklander 
1294f7cc36c0SJens Wiklander 	case PKCS11_CKU_CONTEXT_SPECIFIC:
1295f7cc36c0SJens Wiklander 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
1296f7cc36c0SJens Wiklander 
1297f7cc36c0SJens Wiklander 	default:
1298f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_TYPE_INVALID;
1299f7cc36c0SJens Wiklander 	}
1300f7cc36c0SJens Wiklander 
1301f7cc36c0SJens Wiklander 	if (!rc)
1302f7cc36c0SJens Wiklander 		IMSG("PKCS11 session %"PRIu32": login", session_handle);
1303f7cc36c0SJens Wiklander 
1304f7cc36c0SJens Wiklander 	return rc;
1305f7cc36c0SJens Wiklander }
1306f7cc36c0SJens Wiklander 
1307f7cc36c0SJens Wiklander uint32_t entry_ck_logout(struct pkcs11_client *client,
1308f7cc36c0SJens Wiklander 			 uint32_t ptypes, TEE_Param *params)
1309f7cc36c0SJens Wiklander {
1310f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1311f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1312f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1313f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1314f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1315f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1316f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1317f7cc36c0SJens Wiklander 	uint32_t session_handle = 0;
1318f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1319f7cc36c0SJens Wiklander 
1320f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1321f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1322f7cc36c0SJens Wiklander 
1323f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1324f7cc36c0SJens Wiklander 
1325f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
1326f7cc36c0SJens Wiklander 	if (rc)
1327f7cc36c0SJens Wiklander 		return rc;
1328f7cc36c0SJens Wiklander 
1329f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1330f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1331f7cc36c0SJens Wiklander 
1332f7cc36c0SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
1333f7cc36c0SJens Wiklander 	if (!session)
1334f7cc36c0SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
1335f7cc36c0SJens Wiklander 
1336f7cc36c0SJens Wiklander 	if (pkcs11_session_is_public(session))
1337f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
1338f7cc36c0SJens Wiklander 
1339f7cc36c0SJens Wiklander 	session_logout(session);
1340f7cc36c0SJens Wiklander 
1341f7cc36c0SJens Wiklander 	IMSG("PKCS11 session %"PRIu32": logout", session_handle);
1342f7cc36c0SJens Wiklander 
1343f7cc36c0SJens Wiklander 	return PKCS11_CKR_OK;
1344f7cc36c0SJens Wiklander }
1345