xref: /optee_os/ta/pkcs11/src/pkcs11_token.c (revision 02b4d42ac4f717041ed1ee66a1e7f0d3f640366f)
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>
9d628ebd9SEtienne 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 
193d628ebd9SEtienne Carriere static void set_token_description(struct pkcs11_slot_info *info)
194d628ebd9SEtienne Carriere {
195d628ebd9SEtienne Carriere 	char desc[sizeof(info->slot_description) + 1] = { 0 };
196d628ebd9SEtienne Carriere 	TEE_UUID dev_id = { };
197d628ebd9SEtienne Carriere 	TEE_Result res = TEE_ERROR_GENERIC;
198d628ebd9SEtienne Carriere 	int n = 0;
199d628ebd9SEtienne Carriere 
200d628ebd9SEtienne Carriere 	res = TEE_GetPropertyAsUUID(TEE_PROPSET_TEE_IMPLEMENTATION,
201d628ebd9SEtienne Carriere 				    "gpd.tee.deviceID", &dev_id);
202d628ebd9SEtienne Carriere 	if (res == TEE_SUCCESS) {
203d628ebd9SEtienne Carriere 		n = snprintk(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
204d628ebd9SEtienne Carriere 			     " - TEE UUID %pUl", (void *)&dev_id);
205d628ebd9SEtienne Carriere 	} else {
206d628ebd9SEtienne Carriere 		n = snprintf(desc, sizeof(desc), PKCS11_SLOT_DESCRIPTION
207d628ebd9SEtienne Carriere 			     " - No TEE UUID");
208d628ebd9SEtienne Carriere 	}
209d628ebd9SEtienne Carriere 	if (n < 0 || n >= (int)sizeof(desc))
210d628ebd9SEtienne Carriere 		TEE_Panic(0);
211d628ebd9SEtienne Carriere 
212d628ebd9SEtienne Carriere 	TEE_MemMove(info->slot_description, desc, n);
213d628ebd9SEtienne Carriere 	pad_str(info->slot_description, sizeof(info->slot_description));
214d628ebd9SEtienne Carriere }
215d628ebd9SEtienne 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 
255d628ebd9SEtienne Carriere 	set_token_description(&info);
256d628ebd9SEtienne 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 		.max_session_count = UINT32_MAX,
281030e7392SEtienne Carriere 		.max_rw_session_count = UINT32_MAX,
282030e7392SEtienne Carriere 		.max_pin_len = PKCS11_TOKEN_PIN_SIZE_MAX,
283030e7392SEtienne Carriere 		.min_pin_len = PKCS11_TOKEN_PIN_SIZE_MIN,
284030e7392SEtienne Carriere 		.total_public_memory = UINT32_MAX,
285030e7392SEtienne Carriere 		.free_public_memory = UINT32_MAX,
286030e7392SEtienne Carriere 		.total_private_memory = UINT32_MAX,
287030e7392SEtienne Carriere 		.free_private_memory = UINT32_MAX,
288030e7392SEtienne Carriere 		.hardware_version = PKCS11_TOKEN_HW_VERSION,
289030e7392SEtienne Carriere 		.firmware_version = PKCS11_TOKEN_FW_VERSION,
290030e7392SEtienne Carriere 	};
291*02b4d42aSEtienne Carriere 	char sn[sizeof(info.serial_number) + 1] = { 0 };
292*02b4d42aSEtienne Carriere 	int n = 0;
293030e7392SEtienne Carriere 
294030e7392SEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
295030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
296030e7392SEtienne Carriere 
297030e7392SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
298030e7392SEtienne Carriere 
299030e7392SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
300030e7392SEtienne Carriere 	if (rv)
301030e7392SEtienne Carriere 		return rv;
302030e7392SEtienne Carriere 
303030e7392SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
304030e7392SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
305030e7392SEtienne Carriere 
306030e7392SEtienne Carriere 	token = get_token(token_id);
307030e7392SEtienne Carriere 	if (!token)
308030e7392SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
309030e7392SEtienne Carriere 
310030e7392SEtienne Carriere 	pad_str(info.manufacturer_id, sizeof(info.manufacturer_id));
311030e7392SEtienne Carriere 	pad_str(info.model, sizeof(info.model));
312*02b4d42aSEtienne Carriere 
313*02b4d42aSEtienne Carriere 	n = snprintf(sn, sizeof(sn), "%0*"PRIu32,
314*02b4d42aSEtienne Carriere 		     (int)sizeof(info.serial_number), token_id);
315*02b4d42aSEtienne Carriere 	if (n != (int)sizeof(info.serial_number))
316*02b4d42aSEtienne Carriere 		TEE_Panic(0);
317*02b4d42aSEtienne Carriere 
318*02b4d42aSEtienne Carriere 	TEE_MemMove(info.serial_number, sn, sizeof(info.serial_number));
319030e7392SEtienne Carriere 	pad_str(info.serial_number, sizeof(info.serial_number));
320030e7392SEtienne Carriere 
321030e7392SEtienne Carriere 	TEE_MemMove(info.label, token->db_main->label, sizeof(info.label));
322030e7392SEtienne Carriere 
323030e7392SEtienne Carriere 	info.flags = token->db_main->flags;
324030e7392SEtienne Carriere 	info.session_count = token->session_count;
325030e7392SEtienne Carriere 	info.rw_session_count = token->rw_session_count;
326030e7392SEtienne Carriere 
327030e7392SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
328030e7392SEtienne Carriere 
329030e7392SEtienne Carriere 	return PKCS11_CKR_OK;
330030e7392SEtienne Carriere }
3316f74919dSEtienne Carriere 
3326f74919dSEtienne Carriere static void dmsg_print_supported_mechanism(unsigned int token_id __maybe_unused,
3336f74919dSEtienne Carriere 					   uint32_t *array __maybe_unused,
3346f74919dSEtienne Carriere 					   size_t count __maybe_unused)
3356f74919dSEtienne Carriere {
3366f74919dSEtienne Carriere 	size_t __maybe_unused n = 0;
3376f74919dSEtienne Carriere 
3386f74919dSEtienne Carriere 	if (TRACE_LEVEL < TRACE_DEBUG)
3396f74919dSEtienne Carriere 		return;
3406f74919dSEtienne Carriere 
3416f74919dSEtienne Carriere 	for (n = 0; n < count; n++)
3426f74919dSEtienne Carriere 		DMSG("PKCS11 token %"PRIu32": mechanism 0x%04"PRIx32": %s",
3436f74919dSEtienne Carriere 		     token_id, array[n], id2str_mechanism(array[n]));
3446f74919dSEtienne Carriere }
3456f74919dSEtienne Carriere 
3466f74919dSEtienne Carriere uint32_t entry_ck_token_mecha_ids(uint32_t ptypes, TEE_Param *params)
3476f74919dSEtienne Carriere {
3486f74919dSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
3496f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
3506f74919dSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
3516f74919dSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
3526f74919dSEtienne Carriere 	TEE_Param *ctrl = &params[0];
3536f74919dSEtienne Carriere 	TEE_Param *out = &params[2];
3546f74919dSEtienne Carriere 	uint32_t rv = 0;
3556f74919dSEtienne Carriere 	struct serialargs ctrlargs = { };
3566f74919dSEtienne Carriere 	uint32_t token_id = 0;
3576f74919dSEtienne Carriere 	struct ck_token __maybe_unused *token = NULL;
3586f74919dSEtienne Carriere 	size_t count = 0;
3596f74919dSEtienne Carriere 	uint32_t *array = NULL;
3606f74919dSEtienne Carriere 
3616f74919dSEtienne Carriere 	if (ptypes != exp_pt)
3626f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3636f74919dSEtienne Carriere 
3646f74919dSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
3656f74919dSEtienne Carriere 
3666f74919dSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
3676f74919dSEtienne Carriere 	if (rv)
3686f74919dSEtienne Carriere 		return rv;
3696f74919dSEtienne Carriere 
3706f74919dSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
3716f74919dSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
3726f74919dSEtienne Carriere 
3736f74919dSEtienne Carriere 	token = get_token(token_id);
3746f74919dSEtienne Carriere 	if (!token)
3756f74919dSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
3766f74919dSEtienne Carriere 
3776f74919dSEtienne Carriere 	count = out->memref.size / sizeof(*array);
3786f74919dSEtienne Carriere 	array = tee_malloc_mechanism_list(&count);
3796f74919dSEtienne Carriere 
3806f74919dSEtienne Carriere 	if (out->memref.size < count * sizeof(*array)) {
3816f74919dSEtienne Carriere 		assert(!array);
3826f74919dSEtienne Carriere 		out->memref.size = count * sizeof(*array);
3836459f267SEtienne Carriere 		if (out->memref.buffer)
3846f74919dSEtienne Carriere 			return PKCS11_CKR_BUFFER_TOO_SMALL;
3856459f267SEtienne Carriere 		else
3866459f267SEtienne Carriere 			return PKCS11_CKR_OK;
3876f74919dSEtienne Carriere 	}
3886f74919dSEtienne Carriere 
3896f74919dSEtienne Carriere 	if (!array)
3906f74919dSEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
3916f74919dSEtienne Carriere 
3926f74919dSEtienne Carriere 	dmsg_print_supported_mechanism(token_id, array, count);
3936f74919dSEtienne Carriere 
3946f74919dSEtienne Carriere 	out->memref.size = count * sizeof(*array);
3956f74919dSEtienne Carriere 	TEE_MemMove(out->memref.buffer, array, out->memref.size);
3966f74919dSEtienne Carriere 
3976f74919dSEtienne Carriere 	TEE_Free(array);
3986f74919dSEtienne Carriere 
3996f74919dSEtienne Carriere 	return rv;
4006f74919dSEtienne Carriere }
4011d3ebedbSEtienne Carriere 
4021d3ebedbSEtienne Carriere static void supported_mechanism_key_size(uint32_t proc_id,
4031d3ebedbSEtienne Carriere 					 uint32_t *max_key_size,
4041d3ebedbSEtienne Carriere 					 uint32_t *min_key_size)
4051d3ebedbSEtienne Carriere {
4061d3ebedbSEtienne Carriere 	switch (proc_id) {
4071d3ebedbSEtienne Carriere 	/* Will be filled once TA supports mechanisms */
4081d3ebedbSEtienne Carriere 	default:
4091d3ebedbSEtienne Carriere 		*min_key_size = 0;
4101d3ebedbSEtienne Carriere 		*max_key_size = 0;
4111d3ebedbSEtienne Carriere 		break;
4121d3ebedbSEtienne Carriere 	}
4131d3ebedbSEtienne Carriere }
4141d3ebedbSEtienne Carriere 
4151d3ebedbSEtienne Carriere uint32_t entry_ck_token_mecha_info(uint32_t ptypes, TEE_Param *params)
4161d3ebedbSEtienne Carriere {
4171d3ebedbSEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
4181d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE,
4191d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
4201d3ebedbSEtienne Carriere 						TEE_PARAM_TYPE_NONE);
4211d3ebedbSEtienne Carriere 	TEE_Param *ctrl = &params[0];
4221d3ebedbSEtienne Carriere 	TEE_Param *out = &params[2];
4231d3ebedbSEtienne Carriere 	uint32_t rv = 0;
4241d3ebedbSEtienne Carriere 	struct serialargs ctrlargs = { };
4251d3ebedbSEtienne Carriere 	uint32_t token_id = 0;
4261d3ebedbSEtienne Carriere 	uint32_t type = 0;
4271d3ebedbSEtienne Carriere 	struct ck_token *token = NULL;
4281d3ebedbSEtienne Carriere 	struct pkcs11_mechanism_info info = { };
4291d3ebedbSEtienne Carriere 
4301d3ebedbSEtienne Carriere 	if (ptypes != exp_pt || out->memref.size != sizeof(info))
4311d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4321d3ebedbSEtienne Carriere 
4331d3ebedbSEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
4341d3ebedbSEtienne Carriere 
4351d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
4361d3ebedbSEtienne Carriere 	if (rv)
4371d3ebedbSEtienne Carriere 		return rv;
4381d3ebedbSEtienne Carriere 
4391d3ebedbSEtienne Carriere 	rv = serialargs_get(&ctrlargs, &type, sizeof(uint32_t));
4401d3ebedbSEtienne Carriere 	if (rv)
4411d3ebedbSEtienne Carriere 		return rv;
4421d3ebedbSEtienne Carriere 
4431d3ebedbSEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
4441d3ebedbSEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
4451d3ebedbSEtienne Carriere 
4461d3ebedbSEtienne Carriere 	token = get_token(token_id);
4471d3ebedbSEtienne Carriere 	if (!token)
4481d3ebedbSEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
4491d3ebedbSEtienne Carriere 
4501d3ebedbSEtienne Carriere 	if (!mechanism_is_valid(type))
4511d3ebedbSEtienne Carriere 		return PKCS11_CKR_MECHANISM_INVALID;
4521d3ebedbSEtienne Carriere 
4531d3ebedbSEtienne Carriere 	info.flags = mechanism_supported_flags(type);
4541d3ebedbSEtienne Carriere 
4551d3ebedbSEtienne Carriere 	supported_mechanism_key_size(type, &info.min_key_size,
4561d3ebedbSEtienne Carriere 				     &info.max_key_size);
4571d3ebedbSEtienne Carriere 
4581d3ebedbSEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
4591d3ebedbSEtienne Carriere 
4601d3ebedbSEtienne Carriere 	DMSG("PKCS11 token %"PRIu32": mechanism 0x%"PRIx32" info",
4611d3ebedbSEtienne Carriere 	     token_id, type);
4621d3ebedbSEtienne Carriere 
4631d3ebedbSEtienne Carriere 	return PKCS11_CKR_OK;
4641d3ebedbSEtienne Carriere }
4656e4f8f17SEtienne Carriere 
4666e4f8f17SEtienne Carriere /* Select the ReadOnly or ReadWrite state for session login state */
4676e4f8f17SEtienne Carriere static void set_session_state(struct pkcs11_client *client,
4686e4f8f17SEtienne Carriere 			      struct pkcs11_session *session, bool readonly)
4696e4f8f17SEtienne Carriere {
4706e4f8f17SEtienne Carriere 	struct pkcs11_session *sess = NULL;
4716e4f8f17SEtienne Carriere 	enum pkcs11_session_state state = PKCS11_CKS_RO_PUBLIC_SESSION;
4726e4f8f17SEtienne Carriere 
4736e4f8f17SEtienne Carriere 	/* Default to public session if no session already registered */
4746e4f8f17SEtienne Carriere 	if (readonly)
4756e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RO_PUBLIC_SESSION;
4766e4f8f17SEtienne Carriere 	else
4776e4f8f17SEtienne Carriere 		state = PKCS11_CKS_RW_PUBLIC_SESSION;
4786e4f8f17SEtienne Carriere 
4796e4f8f17SEtienne Carriere 	/*
4806e4f8f17SEtienne Carriere 	 * No need to check all client sessions, the first found in
4816e4f8f17SEtienne Carriere 	 * target token gives client login configuration.
4826e4f8f17SEtienne Carriere 	 */
4836e4f8f17SEtienne Carriere 	TAILQ_FOREACH(sess, &client->session_list, link) {
4846e4f8f17SEtienne Carriere 		assert(sess != session);
4856e4f8f17SEtienne Carriere 
4866e4f8f17SEtienne Carriere 		if (sess->token == session->token) {
4876e4f8f17SEtienne Carriere 			switch (sess->state) {
4886e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_PUBLIC_SESSION:
4896e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_PUBLIC_SESSION:
4906e4f8f17SEtienne Carriere 				if (readonly)
4916e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_PUBLIC_SESSION;
4926e4f8f17SEtienne Carriere 				else
4936e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_PUBLIC_SESSION;
4946e4f8f17SEtienne Carriere 				break;
4956e4f8f17SEtienne Carriere 			case PKCS11_CKS_RO_USER_FUNCTIONS:
4966e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_USER_FUNCTIONS:
4976e4f8f17SEtienne Carriere 				if (readonly)
4986e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RO_USER_FUNCTIONS;
4996e4f8f17SEtienne Carriere 				else
5006e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_USER_FUNCTIONS;
5016e4f8f17SEtienne Carriere 				break;
5026e4f8f17SEtienne Carriere 			case PKCS11_CKS_RW_SO_FUNCTIONS:
5036e4f8f17SEtienne Carriere 				if (readonly)
5046e4f8f17SEtienne Carriere 					TEE_Panic(0);
5056e4f8f17SEtienne Carriere 				else
5066e4f8f17SEtienne Carriere 					state = PKCS11_CKS_RW_SO_FUNCTIONS;
5076e4f8f17SEtienne Carriere 				break;
5086e4f8f17SEtienne Carriere 			default:
5096e4f8f17SEtienne Carriere 				TEE_Panic(0);
5106e4f8f17SEtienne Carriere 			}
5116e4f8f17SEtienne Carriere 			break;
5126e4f8f17SEtienne Carriere 		}
5136e4f8f17SEtienne Carriere 	}
5146e4f8f17SEtienne Carriere 
5156e4f8f17SEtienne Carriere 	session->state = state;
5166e4f8f17SEtienne Carriere }
5176e4f8f17SEtienne Carriere 
5186e4f8f17SEtienne Carriere uint32_t entry_ck_open_session(struct pkcs11_client *client,
5196e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
5206e4f8f17SEtienne Carriere {
5216e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
5226e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
5236e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
5246e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
5256e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
5266e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
5276e4f8f17SEtienne Carriere 	uint32_t rv = 0;
5286e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
5296e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
5306e4f8f17SEtienne Carriere 	uint32_t flags = 0;
5316e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
5326e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
5336e4f8f17SEtienne Carriere 	bool readonly = false;
5346e4f8f17SEtienne Carriere 
5356e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt ||
5366e4f8f17SEtienne Carriere 	    out->memref.size != sizeof(session->handle))
5376e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5386e4f8f17SEtienne Carriere 
5396e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
5406e4f8f17SEtienne Carriere 
5416e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(token_id));
5426e4f8f17SEtienne Carriere 	if (rv)
5436e4f8f17SEtienne Carriere 		return rv;
5446e4f8f17SEtienne Carriere 
5456e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &flags, sizeof(flags));
5466e4f8f17SEtienne Carriere 	if (rv)
5476e4f8f17SEtienne Carriere 		return rv;
5486e4f8f17SEtienne Carriere 
5496e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
5506e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5516e4f8f17SEtienne Carriere 
5526e4f8f17SEtienne Carriere 	token = get_token(token_id);
5536e4f8f17SEtienne Carriere 	if (!token)
5546e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
5556e4f8f17SEtienne Carriere 
5566e4f8f17SEtienne Carriere 	/* Sanitize session flags */
5576e4f8f17SEtienne Carriere 	if (!(flags & PKCS11_CKFSS_SERIAL_SESSION) ||
5586e4f8f17SEtienne Carriere 	    (flags & ~(PKCS11_CKFSS_RW_SESSION |
5596e4f8f17SEtienne Carriere 		       PKCS11_CKFSS_SERIAL_SESSION)))
5606e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
5616e4f8f17SEtienne Carriere 
5626e4f8f17SEtienne Carriere 	readonly = !(flags & PKCS11_CKFSS_RW_SESSION);
5636e4f8f17SEtienne Carriere 
5646e4f8f17SEtienne Carriere 	if (!readonly && token->state == PKCS11_TOKEN_READ_ONLY)
5656e4f8f17SEtienne Carriere 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
5666e4f8f17SEtienne Carriere 
5676e4f8f17SEtienne Carriere 	if (readonly) {
5686e4f8f17SEtienne Carriere 		/* Specifically reject read-only session under SO login */
5696e4f8f17SEtienne Carriere 		TAILQ_FOREACH(session, &client->session_list, link)
5706e4f8f17SEtienne Carriere 			if (pkcs11_session_is_so(session))
5716e4f8f17SEtienne Carriere 				return PKCS11_CKR_SESSION_READ_WRITE_SO_EXISTS;
5726e4f8f17SEtienne Carriere 	}
5736e4f8f17SEtienne Carriere 
5746e4f8f17SEtienne Carriere 	session = TEE_Malloc(sizeof(*session), TEE_MALLOC_FILL_ZERO);
5756e4f8f17SEtienne Carriere 	if (!session)
5766e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5776e4f8f17SEtienne Carriere 
5786e4f8f17SEtienne Carriere 	session->handle = handle_get(&client->session_handle_db, session);
5796e4f8f17SEtienne Carriere 	if (!session->handle) {
5806e4f8f17SEtienne Carriere 		TEE_Free(session);
5816e4f8f17SEtienne Carriere 		return PKCS11_CKR_DEVICE_MEMORY;
5826e4f8f17SEtienne Carriere 	}
5836e4f8f17SEtienne Carriere 
5846e4f8f17SEtienne Carriere 	session->token = token;
5856e4f8f17SEtienne Carriere 	session->client = client;
5866e4f8f17SEtienne Carriere 
5876e4f8f17SEtienne Carriere 	set_session_state(client, session, readonly);
5886e4f8f17SEtienne Carriere 
5896e4f8f17SEtienne Carriere 	TAILQ_INSERT_HEAD(&client->session_list, session, link);
5906e4f8f17SEtienne Carriere 
5916e4f8f17SEtienne Carriere 	session->token->session_count++;
5926e4f8f17SEtienne Carriere 	if (!readonly)
5936e4f8f17SEtienne Carriere 		session->token->rw_session_count++;
5946e4f8f17SEtienne Carriere 
5956e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &session->handle,
5966e4f8f17SEtienne Carriere 		    sizeof(session->handle));
5976e4f8f17SEtienne Carriere 
5986e4f8f17SEtienne Carriere 	DMSG("Open PKCS11 session %"PRIu32, session->handle);
5996e4f8f17SEtienne Carriere 
6006e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6016e4f8f17SEtienne Carriere }
6026e4f8f17SEtienne Carriere 
6036e4f8f17SEtienne Carriere static void close_ck_session(struct pkcs11_session *session)
6046e4f8f17SEtienne Carriere {
6056e4f8f17SEtienne Carriere 	TAILQ_REMOVE(&session->client->session_list, session, link);
6066e4f8f17SEtienne Carriere 	handle_put(&session->client->session_handle_db, session->handle);
6076e4f8f17SEtienne Carriere 
6086e4f8f17SEtienne Carriere 	session->token->session_count--;
6096e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
6106e4f8f17SEtienne Carriere 		session->token->rw_session_count--;
6116e4f8f17SEtienne Carriere 
6126e4f8f17SEtienne Carriere 	TEE_Free(session);
6136e4f8f17SEtienne Carriere 
6146e4f8f17SEtienne Carriere 	DMSG("Close PKCS11 session %"PRIu32, session->handle);
6156e4f8f17SEtienne Carriere }
6166e4f8f17SEtienne Carriere 
6176e4f8f17SEtienne Carriere uint32_t entry_ck_close_session(struct pkcs11_client *client,
6186e4f8f17SEtienne Carriere 				uint32_t ptypes, TEE_Param *params)
6196e4f8f17SEtienne Carriere {
6206e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6216e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6226e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6236e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6246e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6256e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6266e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6276e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
6286e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6296e4f8f17SEtienne Carriere 
6306e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6316e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6326e4f8f17SEtienne Carriere 
6336e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6346e4f8f17SEtienne Carriere 
6356e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
6366e4f8f17SEtienne Carriere 	if (rv)
6376e4f8f17SEtienne Carriere 		return rv;
6386e4f8f17SEtienne Carriere 
6396e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6406e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6416e4f8f17SEtienne Carriere 
6426e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
6436e4f8f17SEtienne Carriere 	if (!session)
6446e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
6456e4f8f17SEtienne Carriere 
6466e4f8f17SEtienne Carriere 	close_ck_session(session);
6476e4f8f17SEtienne Carriere 
6486e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6496e4f8f17SEtienne Carriere }
6506e4f8f17SEtienne Carriere 
6516e4f8f17SEtienne Carriere uint32_t entry_ck_close_all_sessions(struct pkcs11_client *client,
6526e4f8f17SEtienne Carriere 				     uint32_t ptypes, TEE_Param *params)
6536e4f8f17SEtienne Carriere {
6546e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6556e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6566e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6576e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6586e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6596e4f8f17SEtienne Carriere 	uint32_t rv = 0;
6606e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
6616e4f8f17SEtienne Carriere 	uint32_t token_id = 0;
6626e4f8f17SEtienne Carriere 	struct ck_token *token = NULL;
6636e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
6646e4f8f17SEtienne Carriere 	struct pkcs11_session *next = NULL;
6656e4f8f17SEtienne Carriere 
6666e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt)
6676e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6686e4f8f17SEtienne Carriere 
6696e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
6706e4f8f17SEtienne Carriere 
6716e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
6726e4f8f17SEtienne Carriere 	if (rv)
6736e4f8f17SEtienne Carriere 		return rv;
6746e4f8f17SEtienne Carriere 
6756e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
6766e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
6776e4f8f17SEtienne Carriere 
6786e4f8f17SEtienne Carriere 	token = get_token(token_id);
6796e4f8f17SEtienne Carriere 	if (!token)
6806e4f8f17SEtienne Carriere 		return PKCS11_CKR_SLOT_ID_INVALID;
6816e4f8f17SEtienne Carriere 
6826e4f8f17SEtienne Carriere 	DMSG("Close all sessions for PKCS11 token %"PRIu32, token_id);
6836e4f8f17SEtienne Carriere 
6846e4f8f17SEtienne Carriere 	TAILQ_FOREACH_SAFE(session, &client->session_list, link, next)
6856e4f8f17SEtienne Carriere 		if (session->token == token)
6866e4f8f17SEtienne Carriere 			close_ck_session(session);
6876e4f8f17SEtienne Carriere 
6886e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
6896e4f8f17SEtienne Carriere }
6906e4f8f17SEtienne Carriere 
6916e4f8f17SEtienne Carriere uint32_t entry_ck_session_info(struct pkcs11_client *client,
6926e4f8f17SEtienne Carriere 			       uint32_t ptypes, TEE_Param *params)
6936e4f8f17SEtienne Carriere {
6946e4f8f17SEtienne Carriere 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
6956e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE,
6966e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_MEMREF_OUTPUT,
6976e4f8f17SEtienne Carriere 						TEE_PARAM_TYPE_NONE);
6986e4f8f17SEtienne Carriere 	TEE_Param *ctrl = &params[0];
6996e4f8f17SEtienne Carriere 	TEE_Param *out = &params[2];
7006e4f8f17SEtienne Carriere 	uint32_t rv = 0;
7016e4f8f17SEtienne Carriere 	struct serialargs ctrlargs = { };
7026e4f8f17SEtienne Carriere 	uint32_t session_handle = 0;
7036e4f8f17SEtienne Carriere 	struct pkcs11_session *session = NULL;
7046e4f8f17SEtienne Carriere 	struct pkcs11_session_info info = {
7056e4f8f17SEtienne Carriere 		.flags = PKCS11_CKFSS_SERIAL_SESSION,
7066e4f8f17SEtienne Carriere 	};
7076e4f8f17SEtienne Carriere 
7086e4f8f17SEtienne Carriere 	if (!client || ptypes != exp_pt || out->memref.size != sizeof(info))
7096e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7106e4f8f17SEtienne Carriere 
7116e4f8f17SEtienne Carriere 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
7126e4f8f17SEtienne Carriere 
7136e4f8f17SEtienne Carriere 	rv = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
7146e4f8f17SEtienne Carriere 	if (rv)
7156e4f8f17SEtienne Carriere 		return rv;
7166e4f8f17SEtienne Carriere 
7176e4f8f17SEtienne Carriere 	if (serialargs_remaining_bytes(&ctrlargs))
7186e4f8f17SEtienne Carriere 		return PKCS11_CKR_ARGUMENTS_BAD;
7196e4f8f17SEtienne Carriere 
7206e4f8f17SEtienne Carriere 	session = pkcs11_handle2session(session_handle, client);
7216e4f8f17SEtienne Carriere 	if (!session)
7226e4f8f17SEtienne Carriere 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
7236e4f8f17SEtienne Carriere 
7246e4f8f17SEtienne Carriere 	info.slot_id = get_token_id(session->token);
7256e4f8f17SEtienne Carriere 	info.state = session->state;
7266e4f8f17SEtienne Carriere 	if (pkcs11_session_is_read_write(session))
7276e4f8f17SEtienne Carriere 		info.flags |= PKCS11_CKFSS_RW_SESSION;
7286e4f8f17SEtienne Carriere 
7296e4f8f17SEtienne Carriere 	TEE_MemMove(out->memref.buffer, &info, sizeof(info));
7306e4f8f17SEtienne Carriere 
7316e4f8f17SEtienne Carriere 	DMSG("Get find on PKCS11 session %"PRIu32, session->handle);
7326e4f8f17SEtienne Carriere 
7336e4f8f17SEtienne Carriere 	return PKCS11_CKR_OK;
7346e4f8f17SEtienne Carriere }
735f485be04SJens Wiklander 
736f485be04SJens Wiklander uint32_t entry_ck_token_initialize(uint32_t ptypes, TEE_Param *params)
737f485be04SJens Wiklander {
738f485be04SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
739f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
740f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE,
741f485be04SJens Wiklander 						TEE_PARAM_TYPE_NONE);
742f485be04SJens Wiklander 	char label[PKCS11_TOKEN_LABEL_SIZE] = { 0 };
743f485be04SJens Wiklander 	struct pkcs11_client *client = NULL;
744f485be04SJens Wiklander 	struct pkcs11_session *sess = NULL;
745f485be04SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
746f485be04SJens Wiklander 	struct serialargs ctrlargs = { };
747f485be04SJens Wiklander 	struct ck_token *token = NULL;
748f485be04SJens Wiklander 	TEE_Param *ctrl = params;
749f485be04SJens Wiklander 	uint32_t token_id = 0;
750f485be04SJens Wiklander 	uint32_t pin_size = 0;
751f485be04SJens Wiklander 	void *pin = NULL;
752f485be04SJens Wiklander 
753f485be04SJens Wiklander 	if (ptypes != exp_pt)
754f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
755f485be04SJens Wiklander 
756f485be04SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
757f485be04SJens Wiklander 
758f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &token_id, sizeof(uint32_t));
759f485be04SJens Wiklander 	if (rc)
760f485be04SJens Wiklander 		return rc;
761f485be04SJens Wiklander 
762f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
763f485be04SJens Wiklander 	if (rc)
764f485be04SJens Wiklander 		return rc;
765f485be04SJens Wiklander 
766f485be04SJens Wiklander 	rc = serialargs_get(&ctrlargs, &label, PKCS11_TOKEN_LABEL_SIZE);
767f485be04SJens Wiklander 	if (rc)
768f485be04SJens Wiklander 		return rc;
769f485be04SJens Wiklander 
770f485be04SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
771f485be04SJens Wiklander 	if (rc)
772f485be04SJens Wiklander 		return rc;
773f485be04SJens Wiklander 
774f485be04SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
775f485be04SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
776f485be04SJens Wiklander 
777f485be04SJens Wiklander 	token = get_token(token_id);
778f485be04SJens Wiklander 	if (!token)
779f485be04SJens Wiklander 		return PKCS11_CKR_SLOT_ID_INVALID;
780f485be04SJens Wiklander 
781f485be04SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED) {
782f485be04SJens Wiklander 		IMSG("Token %"PRIu32": SO PIN locked", token_id);
783f485be04SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
784f485be04SJens Wiklander 	}
785f485be04SJens Wiklander 
786f485be04SJens Wiklander 	/* Check there's no open session on this token */
787f485be04SJens Wiklander 	TAILQ_FOREACH(client, &pkcs11_client_list, link)
788f485be04SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
789f485be04SJens Wiklander 			if (sess->token == token)
790f485be04SJens Wiklander 				return PKCS11_CKR_SESSION_EXISTS;
791f485be04SJens Wiklander 
792f485be04SJens Wiklander 	if (!token->db_main->so_pin_salt) {
793f485be04SJens Wiklander 		/*
794f485be04SJens Wiklander 		 * The spec doesn't permit returning
795f485be04SJens Wiklander 		 * PKCS11_CKR_PIN_LEN_RANGE for this function, take another
796f485be04SJens Wiklander 		 * error code.
797f485be04SJens Wiklander 		 */
798f485be04SJens Wiklander 		if (pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
799f485be04SJens Wiklander 		    pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
800f485be04SJens Wiklander 			return PKCS11_CKR_ARGUMENTS_BAD;
801f485be04SJens Wiklander 
802f485be04SJens Wiklander 		rc = hash_pin(PKCS11_CKU_SO, pin, pin_size,
803f485be04SJens Wiklander 			      &token->db_main->so_pin_salt,
804f485be04SJens Wiklander 			      token->db_main->so_pin_hash);
805f485be04SJens Wiklander 		if (rc)
806f485be04SJens Wiklander 			return rc;
807f485be04SJens Wiklander 
808f485be04SJens Wiklander 		update_persistent_db(token);
809f485be04SJens Wiklander 
810f485be04SJens Wiklander 		goto inited;
811f485be04SJens Wiklander 	}
812f485be04SJens Wiklander 
813f485be04SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
814f485be04SJens Wiklander 			token->db_main->so_pin_salt,
815f485be04SJens Wiklander 			token->db_main->so_pin_hash);
816f485be04SJens Wiklander 	if (rc) {
817f485be04SJens Wiklander 		unsigned int pin_count = 0;
818f485be04SJens Wiklander 
819f485be04SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
820f485be04SJens Wiklander 			return rc;
821f485be04SJens Wiklander 
822f485be04SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
823f485be04SJens Wiklander 		token->db_main->so_pin_count++;
824f485be04SJens Wiklander 
825f485be04SJens Wiklander 		pin_count = token->db_main->so_pin_count;
826f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
827f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
828f485be04SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
829f485be04SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
830f485be04SJens Wiklander 
831f485be04SJens Wiklander 		update_persistent_db(token);
832f485be04SJens Wiklander 
833f485be04SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
834f485be04SJens Wiklander 	}
835f485be04SJens Wiklander 
836f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
837f485be04SJens Wiklander 				   PKCS11_CKFT_SO_PIN_FINAL_TRY);
838f485be04SJens Wiklander 	token->db_main->so_pin_count = 0;
839f485be04SJens Wiklander 
840f485be04SJens Wiklander inited:
841f485be04SJens Wiklander 	TEE_MemMove(token->db_main->label, label, PKCS11_TOKEN_LABEL_SIZE);
842f485be04SJens Wiklander 	token->db_main->flags |= PKCS11_CKFT_TOKEN_INITIALIZED;
843f485be04SJens Wiklander 	/* Reset user PIN */
844f485be04SJens Wiklander 	token->db_main->user_pin_salt = 0;
845f485be04SJens Wiklander 	token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_INITIALIZED |
846f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_COUNT_LOW |
847f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_FINAL_TRY |
848f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_LOCKED |
849f485be04SJens Wiklander 				   PKCS11_CKFT_USER_PIN_TO_BE_CHANGED);
850f485be04SJens Wiklander 
851f485be04SJens Wiklander 	update_persistent_db(token);
852f485be04SJens Wiklander 
853f485be04SJens Wiklander 	IMSG("PKCS11 token %"PRIu32": initialized", token_id);
854f485be04SJens Wiklander 
855f485be04SJens Wiklander 	return PKCS11_CKR_OK;
856f485be04SJens Wiklander }
857e8dbd92cSJens Wiklander 
858e8dbd92cSJens Wiklander static enum pkcs11_rc set_pin(struct pkcs11_session *session,
859e8dbd92cSJens Wiklander 			      uint8_t *new_pin, size_t new_pin_size,
860e8dbd92cSJens Wiklander 			      enum pkcs11_user_type user_type)
861e8dbd92cSJens Wiklander {
862e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
863e8dbd92cSJens Wiklander 	uint32_t flags_clear = 0;
864e8dbd92cSJens Wiklander 	uint32_t flags_set = 0;
865e8dbd92cSJens Wiklander 
866e8dbd92cSJens Wiklander 	if (session->token->db_main->flags & PKCS11_CKFT_WRITE_PROTECTED)
867e8dbd92cSJens Wiklander 		return PKCS11_CKR_TOKEN_WRITE_PROTECTED;
868e8dbd92cSJens Wiklander 
869e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_read_write(session))
870e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
871e8dbd92cSJens Wiklander 
872e8dbd92cSJens Wiklander 	if (new_pin_size < PKCS11_TOKEN_PIN_SIZE_MIN ||
873e8dbd92cSJens Wiklander 	    new_pin_size > PKCS11_TOKEN_PIN_SIZE_MAX)
874e8dbd92cSJens Wiklander 		return PKCS11_CKR_PIN_LEN_RANGE;
875e8dbd92cSJens Wiklander 
876e8dbd92cSJens Wiklander 	switch (user_type) {
877e8dbd92cSJens Wiklander 	case PKCS11_CKU_SO:
878e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
879e8dbd92cSJens Wiklander 			      &session->token->db_main->so_pin_salt,
880e8dbd92cSJens Wiklander 			      session->token->db_main->so_pin_hash);
881e8dbd92cSJens Wiklander 		if (rc)
882e8dbd92cSJens Wiklander 			return rc;
883e8dbd92cSJens Wiklander 		session->token->db_main->so_pin_count = 0;
884e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_SO_PIN_COUNT_LOW |
885e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_FINAL_TRY |
886e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_LOCKED |
887e8dbd92cSJens Wiklander 			      PKCS11_CKFT_SO_PIN_TO_BE_CHANGED;
888e8dbd92cSJens Wiklander 		break;
889e8dbd92cSJens Wiklander 	case PKCS11_CKU_USER:
890e8dbd92cSJens Wiklander 		rc = hash_pin(user_type, new_pin, new_pin_size,
891e8dbd92cSJens Wiklander 			      &session->token->db_main->user_pin_salt,
892e8dbd92cSJens Wiklander 			      session->token->db_main->user_pin_hash);
893e8dbd92cSJens Wiklander 		if (rc)
894e8dbd92cSJens Wiklander 			return rc;
895e8dbd92cSJens Wiklander 		session->token->db_main->user_pin_count = 0;
896e8dbd92cSJens Wiklander 		flags_clear = PKCS11_CKFT_USER_PIN_COUNT_LOW |
897e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_FINAL_TRY |
898e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_LOCKED |
899e8dbd92cSJens Wiklander 			      PKCS11_CKFT_USER_PIN_TO_BE_CHANGED;
900e8dbd92cSJens Wiklander 		flags_set = PKCS11_CKFT_USER_PIN_INITIALIZED;
901e8dbd92cSJens Wiklander 		break;
902e8dbd92cSJens Wiklander 	default:
903e8dbd92cSJens Wiklander 		return PKCS11_CKR_FUNCTION_FAILED;
904e8dbd92cSJens Wiklander 	}
905e8dbd92cSJens Wiklander 
906e8dbd92cSJens Wiklander 	session->token->db_main->flags &= ~flags_clear;
907e8dbd92cSJens Wiklander 	session->token->db_main->flags |= flags_set;
908e8dbd92cSJens Wiklander 
909e8dbd92cSJens Wiklander 	update_persistent_db(session->token);
910e8dbd92cSJens Wiklander 
911e8dbd92cSJens Wiklander 	return PKCS11_CKR_OK;
912e8dbd92cSJens Wiklander }
913e8dbd92cSJens Wiklander 
914e8dbd92cSJens Wiklander uint32_t entry_ck_init_pin(struct pkcs11_client *client,
915e8dbd92cSJens Wiklander 			   uint32_t ptypes, TEE_Param *params)
916e8dbd92cSJens Wiklander {
917e8dbd92cSJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
918e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
919e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE,
920e8dbd92cSJens Wiklander 						TEE_PARAM_TYPE_NONE);
921e8dbd92cSJens Wiklander 	struct pkcs11_session *session = NULL;
922e8dbd92cSJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
923e8dbd92cSJens Wiklander 	struct serialargs ctrlargs = { };
924e8dbd92cSJens Wiklander 	uint32_t session_handle = 0;
925e8dbd92cSJens Wiklander 	TEE_Param *ctrl = params;
926e8dbd92cSJens Wiklander 	uint32_t pin_size = 0;
927e8dbd92cSJens Wiklander 	void *pin = NULL;
928e8dbd92cSJens Wiklander 
929e8dbd92cSJens Wiklander 	if (!client || ptypes != exp_pt)
930e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
931e8dbd92cSJens Wiklander 
932e8dbd92cSJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
933e8dbd92cSJens Wiklander 
934e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
935e8dbd92cSJens Wiklander 	if (rc)
936e8dbd92cSJens Wiklander 		return rc;
937e8dbd92cSJens Wiklander 
938e8dbd92cSJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
939e8dbd92cSJens Wiklander 	if (rc)
940e8dbd92cSJens Wiklander 		return rc;
941e8dbd92cSJens Wiklander 
942e8dbd92cSJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
943e8dbd92cSJens Wiklander 	if (rc)
944e8dbd92cSJens Wiklander 		return rc;
945e8dbd92cSJens Wiklander 
946e8dbd92cSJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
947e8dbd92cSJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
948e8dbd92cSJens Wiklander 
949e8dbd92cSJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
950e8dbd92cSJens Wiklander 	if (!session)
951e8dbd92cSJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
952e8dbd92cSJens Wiklander 
953e8dbd92cSJens Wiklander 	if (!pkcs11_session_is_so(session))
954e8dbd92cSJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
955e8dbd92cSJens Wiklander 
956e8dbd92cSJens Wiklander 	assert(session->token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
957e8dbd92cSJens Wiklander 
958e8dbd92cSJens Wiklander 	IMSG("PKCS11 session %"PRIu32": init PIN", session_handle);
959e8dbd92cSJens Wiklander 
960e8dbd92cSJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
961e8dbd92cSJens Wiklander }
9621dbb91e7SJens Wiklander 
9631dbb91e7SJens Wiklander static uint32_t check_so_pin(struct pkcs11_session *session,
9641dbb91e7SJens Wiklander 			     uint8_t *pin, size_t pin_size)
9651dbb91e7SJens Wiklander {
9661dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
9671dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
9681dbb91e7SJens Wiklander 
9691dbb91e7SJens Wiklander 	assert(token->db_main->flags & PKCS11_CKFT_TOKEN_INITIALIZED);
9701dbb91e7SJens Wiklander 
9711dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
9721dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
9731dbb91e7SJens Wiklander 
9741dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_SO, pin, pin_size,
9751dbb91e7SJens Wiklander 			token->db_main->so_pin_salt,
9761dbb91e7SJens Wiklander 			token->db_main->so_pin_hash);
9771dbb91e7SJens Wiklander 	if (rc) {
9781dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
9791dbb91e7SJens Wiklander 
9801dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
9811dbb91e7SJens Wiklander 			return rc;
9821dbb91e7SJens Wiklander 
9831dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_SO_PIN_COUNT_LOW;
9841dbb91e7SJens Wiklander 		token->db_main->so_pin_count++;
9851dbb91e7SJens Wiklander 
9861dbb91e7SJens Wiklander 		pin_count = token->db_main->so_pin_count;
9871dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX - 1)
9881dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_FINAL_TRY;
9891dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_SO_PIN_COUNT_MAX)
9901dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_SO_PIN_LOCKED;
9911dbb91e7SJens Wiklander 
9921dbb91e7SJens Wiklander 		update_persistent_db(token);
9931dbb91e7SJens Wiklander 
9941dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_SO_PIN_LOCKED)
9951dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
9961dbb91e7SJens Wiklander 
9971dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
9981dbb91e7SJens Wiklander 	}
9991dbb91e7SJens Wiklander 
10001dbb91e7SJens Wiklander 	if (token->db_main->so_pin_count) {
10011dbb91e7SJens Wiklander 		token->db_main->so_pin_count = 0;
10021dbb91e7SJens Wiklander 
10031dbb91e7SJens Wiklander 		update_persistent_db(token);
10041dbb91e7SJens Wiklander 	}
10051dbb91e7SJens Wiklander 
10061dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_SO_PIN_COUNT_LOW |
10071dbb91e7SJens Wiklander 				     PKCS11_CKFT_SO_PIN_FINAL_TRY)) {
10081dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_SO_PIN_COUNT_LOW |
10091dbb91e7SJens Wiklander 					   PKCS11_CKFT_SO_PIN_FINAL_TRY);
10101dbb91e7SJens Wiklander 
10111dbb91e7SJens Wiklander 		update_persistent_db(token);
10121dbb91e7SJens Wiklander 	}
10131dbb91e7SJens Wiklander 
10141dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
10151dbb91e7SJens Wiklander }
10161dbb91e7SJens Wiklander 
10171dbb91e7SJens Wiklander static uint32_t check_user_pin(struct pkcs11_session *session,
10181dbb91e7SJens Wiklander 			       uint8_t *pin, size_t pin_size)
10191dbb91e7SJens Wiklander {
10201dbb91e7SJens Wiklander 	struct ck_token *token = session->token;
10211dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
10221dbb91e7SJens Wiklander 
10231dbb91e7SJens Wiklander 	if (!token->db_main->user_pin_salt)
10241dbb91e7SJens Wiklander 		return PKCS11_CKR_USER_PIN_NOT_INITIALIZED;
10251dbb91e7SJens Wiklander 
10261dbb91e7SJens Wiklander 	if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
10271dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_LOCKED;
10281dbb91e7SJens Wiklander 
10291dbb91e7SJens Wiklander 	rc = verify_pin(PKCS11_CKU_USER, pin, pin_size,
10301dbb91e7SJens Wiklander 			token->db_main->user_pin_salt,
10311dbb91e7SJens Wiklander 			token->db_main->user_pin_hash);
10321dbb91e7SJens Wiklander 	if (rc) {
10331dbb91e7SJens Wiklander 		unsigned int pin_count = 0;
10341dbb91e7SJens Wiklander 
10351dbb91e7SJens Wiklander 		if (rc != PKCS11_CKR_PIN_INCORRECT)
10361dbb91e7SJens Wiklander 			return rc;
10371dbb91e7SJens Wiklander 
10381dbb91e7SJens Wiklander 		token->db_main->flags |= PKCS11_CKFT_USER_PIN_COUNT_LOW;
10391dbb91e7SJens Wiklander 		token->db_main->user_pin_count++;
10401dbb91e7SJens Wiklander 
10411dbb91e7SJens Wiklander 		pin_count = token->db_main->user_pin_count;
10421dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX - 1)
10431dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_FINAL_TRY;
10441dbb91e7SJens Wiklander 		if (pin_count == PKCS11_TOKEN_USER_PIN_COUNT_MAX)
10451dbb91e7SJens Wiklander 			token->db_main->flags |= PKCS11_CKFT_USER_PIN_LOCKED;
10461dbb91e7SJens Wiklander 
10471dbb91e7SJens Wiklander 		update_persistent_db(token);
10481dbb91e7SJens Wiklander 
10491dbb91e7SJens Wiklander 		if (token->db_main->flags & PKCS11_CKFT_USER_PIN_LOCKED)
10501dbb91e7SJens Wiklander 			return PKCS11_CKR_PIN_LOCKED;
10511dbb91e7SJens Wiklander 
10521dbb91e7SJens Wiklander 		return PKCS11_CKR_PIN_INCORRECT;
10531dbb91e7SJens Wiklander 	}
10541dbb91e7SJens Wiklander 
10551dbb91e7SJens Wiklander 	if (token->db_main->user_pin_count) {
10561dbb91e7SJens Wiklander 		token->db_main->user_pin_count = 0;
10571dbb91e7SJens Wiklander 
10581dbb91e7SJens Wiklander 		update_persistent_db(token);
10591dbb91e7SJens Wiklander 	}
10601dbb91e7SJens Wiklander 
10611dbb91e7SJens Wiklander 	if (token->db_main->flags & (PKCS11_CKFT_USER_PIN_COUNT_LOW |
10621dbb91e7SJens Wiklander 				     PKCS11_CKFT_USER_PIN_FINAL_TRY)) {
10631dbb91e7SJens Wiklander 		token->db_main->flags &= ~(PKCS11_CKFT_USER_PIN_COUNT_LOW |
10641dbb91e7SJens Wiklander 					   PKCS11_CKFT_USER_PIN_FINAL_TRY);
10651dbb91e7SJens Wiklander 
10661dbb91e7SJens Wiklander 		update_persistent_db(token);
10671dbb91e7SJens Wiklander 	}
10681dbb91e7SJens Wiklander 
10691dbb91e7SJens Wiklander 	return PKCS11_CKR_OK;
10701dbb91e7SJens Wiklander }
10711dbb91e7SJens Wiklander 
10721dbb91e7SJens Wiklander uint32_t entry_ck_set_pin(struct pkcs11_client *client,
10731dbb91e7SJens Wiklander 			  uint32_t ptypes, TEE_Param *params)
10741dbb91e7SJens Wiklander {
10751dbb91e7SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
10761dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
10771dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE,
10781dbb91e7SJens Wiklander 						TEE_PARAM_TYPE_NONE);
10791dbb91e7SJens Wiklander 	struct pkcs11_session *session = NULL;
10801dbb91e7SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
10811dbb91e7SJens Wiklander 	struct serialargs ctrlargs = { };
10821dbb91e7SJens Wiklander 	uint32_t session_handle = 0;
10831dbb91e7SJens Wiklander 	uint32_t old_pin_size = 0;
10841dbb91e7SJens Wiklander 	TEE_Param *ctrl = params;
10851dbb91e7SJens Wiklander 	uint32_t pin_size = 0;
10861dbb91e7SJens Wiklander 	void *old_pin = NULL;
10871dbb91e7SJens Wiklander 	void *pin = NULL;
10881dbb91e7SJens Wiklander 
10891dbb91e7SJens Wiklander 	if (!client || ptypes != exp_pt)
10901dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
10911dbb91e7SJens Wiklander 
10921dbb91e7SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
10931dbb91e7SJens Wiklander 
10941dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
10951dbb91e7SJens Wiklander 	if (rc)
10961dbb91e7SJens Wiklander 		return rc;
10971dbb91e7SJens Wiklander 
10981dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &old_pin_size, sizeof(uint32_t));
10991dbb91e7SJens Wiklander 	if (rc)
11001dbb91e7SJens Wiklander 		return rc;
11011dbb91e7SJens Wiklander 
11021dbb91e7SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
11031dbb91e7SJens Wiklander 	if (rc)
11041dbb91e7SJens Wiklander 		return rc;
11051dbb91e7SJens Wiklander 
11061dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &old_pin, old_pin_size);
11071dbb91e7SJens Wiklander 	if (rc)
11081dbb91e7SJens Wiklander 		return rc;
11091dbb91e7SJens Wiklander 
11101dbb91e7SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
11111dbb91e7SJens Wiklander 	if (rc)
11121dbb91e7SJens Wiklander 		return rc;
11131dbb91e7SJens Wiklander 
11141dbb91e7SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
11151dbb91e7SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
11161dbb91e7SJens Wiklander 
11171dbb91e7SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
11181dbb91e7SJens Wiklander 	if (!session)
11191dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
11201dbb91e7SJens Wiklander 
11211dbb91e7SJens Wiklander 	if (!pkcs11_session_is_read_write(session))
11221dbb91e7SJens Wiklander 		return PKCS11_CKR_SESSION_READ_ONLY;
11231dbb91e7SJens Wiklander 
11241dbb91e7SJens Wiklander 	if (pkcs11_session_is_so(session)) {
11251dbb91e7SJens Wiklander 		if (!(session->token->db_main->flags &
11261dbb91e7SJens Wiklander 		      PKCS11_CKFT_TOKEN_INITIALIZED))
11271dbb91e7SJens Wiklander 			return PKCS11_CKR_GENERAL_ERROR;
11281dbb91e7SJens Wiklander 
11291dbb91e7SJens Wiklander 		rc = check_so_pin(session, old_pin, old_pin_size);
11301dbb91e7SJens Wiklander 		if (rc)
11311dbb91e7SJens Wiklander 			return rc;
11321dbb91e7SJens Wiklander 
11331dbb91e7SJens Wiklander 		IMSG("PKCS11 session %"PRIu32": set PIN", session_handle);
11341dbb91e7SJens Wiklander 
11351dbb91e7SJens Wiklander 		return set_pin(session, pin, pin_size, PKCS11_CKU_SO);
11361dbb91e7SJens Wiklander 	}
11371dbb91e7SJens Wiklander 
11381dbb91e7SJens Wiklander 	if (!(session->token->db_main->flags &
11391dbb91e7SJens Wiklander 	      PKCS11_CKFT_USER_PIN_INITIALIZED))
11401dbb91e7SJens Wiklander 		return PKCS11_CKR_GENERAL_ERROR;
11411dbb91e7SJens Wiklander 
11421dbb91e7SJens Wiklander 	rc = check_user_pin(session, old_pin, old_pin_size);
11431dbb91e7SJens Wiklander 	if (rc)
11441dbb91e7SJens Wiklander 		return rc;
11451dbb91e7SJens Wiklander 
11461dbb91e7SJens Wiklander 	IMSG("PKCS11 session %"PRIu32": set PIN", session_handle);
11471dbb91e7SJens Wiklander 
11481dbb91e7SJens Wiklander 	return set_pin(session, pin, pin_size, PKCS11_CKU_USER);
11491dbb91e7SJens Wiklander }
1150f7cc36c0SJens Wiklander 
1151f7cc36c0SJens Wiklander static void session_login_user(struct pkcs11_session *session)
1152f7cc36c0SJens Wiklander {
1153f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1154f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1155f7cc36c0SJens Wiklander 
1156f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1157f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1158f7cc36c0SJens Wiklander 			continue;
1159f7cc36c0SJens Wiklander 
1160f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1161f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_USER_FUNCTIONS;
1162f7cc36c0SJens Wiklander 		else
1163f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_USER_FUNCTIONS;
1164f7cc36c0SJens Wiklander 	}
1165f7cc36c0SJens Wiklander }
1166f7cc36c0SJens Wiklander 
1167f7cc36c0SJens Wiklander static void session_login_so(struct pkcs11_session *session)
1168f7cc36c0SJens Wiklander {
1169f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1170f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1171f7cc36c0SJens Wiklander 
1172f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1173f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1174f7cc36c0SJens Wiklander 			continue;
1175f7cc36c0SJens Wiklander 
1176f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1177f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_SO_FUNCTIONS;
1178f7cc36c0SJens Wiklander 		else
1179f7cc36c0SJens Wiklander 			TEE_Panic(0);
1180f7cc36c0SJens Wiklander 	}
1181f7cc36c0SJens Wiklander }
1182f7cc36c0SJens Wiklander 
1183f7cc36c0SJens Wiklander static void session_logout(struct pkcs11_session *session)
1184f7cc36c0SJens Wiklander {
1185f7cc36c0SJens Wiklander 	struct pkcs11_client *client = session->client;
1186f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1187f7cc36c0SJens Wiklander 
1188f7cc36c0SJens Wiklander 	TAILQ_FOREACH(sess, &client->session_list, link) {
1189f7cc36c0SJens Wiklander 		if (sess->token != session->token)
1190f7cc36c0SJens Wiklander 			continue;
1191f7cc36c0SJens Wiklander 
1192f7cc36c0SJens Wiklander 		if (pkcs11_session_is_read_write(sess))
1193f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RW_PUBLIC_SESSION;
1194f7cc36c0SJens Wiklander 		else
1195f7cc36c0SJens Wiklander 			sess->state = PKCS11_CKS_RO_PUBLIC_SESSION;
1196f7cc36c0SJens Wiklander 	}
1197f7cc36c0SJens Wiklander }
1198f7cc36c0SJens Wiklander 
1199f7cc36c0SJens Wiklander uint32_t entry_ck_login(struct pkcs11_client *client,
1200f7cc36c0SJens Wiklander 			uint32_t ptypes, TEE_Param *params)
1201f7cc36c0SJens Wiklander {
1202f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1203f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1204f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1205f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1206f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1207f7cc36c0SJens Wiklander 	struct pkcs11_session *sess = NULL;
1208f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1209f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1210f7cc36c0SJens Wiklander 	uint32_t session_handle = 0;
1211f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1212f7cc36c0SJens Wiklander 	uint32_t user_type = 0;
1213f7cc36c0SJens Wiklander 	uint32_t pin_size = 0;
1214f7cc36c0SJens Wiklander 	void *pin = NULL;
1215f7cc36c0SJens Wiklander 
1216f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1217f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1218f7cc36c0SJens Wiklander 
1219f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1220f7cc36c0SJens Wiklander 
1221f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
1222f7cc36c0SJens Wiklander 	if (rc)
1223f7cc36c0SJens Wiklander 		return rc;
1224f7cc36c0SJens Wiklander 
1225f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &user_type, sizeof(uint32_t));
1226f7cc36c0SJens Wiklander 	if (rc)
1227f7cc36c0SJens Wiklander 		return rc;
1228f7cc36c0SJens Wiklander 
1229f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &pin_size, sizeof(uint32_t));
1230f7cc36c0SJens Wiklander 	if (rc)
1231f7cc36c0SJens Wiklander 		return rc;
1232f7cc36c0SJens Wiklander 
1233f7cc36c0SJens Wiklander 	rc = serialargs_get_ptr(&ctrlargs, &pin, pin_size);
1234f7cc36c0SJens Wiklander 	if (rc)
1235f7cc36c0SJens Wiklander 		return rc;
1236f7cc36c0SJens Wiklander 
1237f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1238f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1239f7cc36c0SJens Wiklander 
1240f7cc36c0SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
1241f7cc36c0SJens Wiklander 	if (!session)
1242f7cc36c0SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
1243f7cc36c0SJens Wiklander 
1244f7cc36c0SJens Wiklander 	switch (user_type) {
1245f7cc36c0SJens Wiklander 	case PKCS11_CKU_SO:
1246f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1247f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1248f7cc36c0SJens Wiklander 
1249f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1250f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1251f7cc36c0SJens Wiklander 
1252f7cc36c0SJens Wiklander 		TAILQ_FOREACH(sess, &client->session_list, link)
1253f7cc36c0SJens Wiklander 			if (sess->token == session->token &&
1254f7cc36c0SJens Wiklander 			    !pkcs11_session_is_read_write(sess))
1255f7cc36c0SJens Wiklander 				return PKCS11_CKR_SESSION_READ_ONLY_EXISTS;
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 		 *
1261f7cc36c0SJens Wiklander 		 * The spec says:
1262f7cc36c0SJens Wiklander 		 * CKR_USER_TOO_MANY_TYPES: An attempt was made to have
1263f7cc36c0SJens Wiklander 		 * more distinct users simultaneously logged into the token
1264f7cc36c0SJens Wiklander 		 * than the token and/or library permits. For example, if
1265f7cc36c0SJens Wiklander 		 * some application has an open SO session, and another
1266f7cc36c0SJens Wiklander 		 * application attempts to log the normal user into a
1267f7cc36c0SJens Wiklander 		 * session, the attempt may return this error. It is not
1268f7cc36c0SJens Wiklander 		 * required to, however. Only if the simultaneous distinct
1269f7cc36c0SJens Wiklander 		 * users cannot be supported does C_Login have to return
1270f7cc36c0SJens Wiklander 		 * this value. Note that this error code generalizes to
1271f7cc36c0SJens Wiklander 		 * true multi-user tokens.
1272f7cc36c0SJens Wiklander 		 *
1273f7cc36c0SJens Wiklander 		 * So it's permitted to have another user or SO logged in
1274f7cc36c0SJens Wiklander 		 * from another client.
1275f7cc36c0SJens Wiklander 		 */
1276f7cc36c0SJens Wiklander 
1277f7cc36c0SJens Wiklander 		rc = check_so_pin(session, pin, pin_size);
1278f7cc36c0SJens Wiklander 		if (!rc)
1279f7cc36c0SJens Wiklander 			session_login_so(session);
1280f7cc36c0SJens Wiklander 
1281f7cc36c0SJens Wiklander 		break;
1282f7cc36c0SJens Wiklander 
1283f7cc36c0SJens Wiklander 	case PKCS11_CKU_USER:
1284f7cc36c0SJens Wiklander 		if (pkcs11_session_is_so(session))
1285f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ANOTHER_ALREADY_LOGGED_IN;
1286f7cc36c0SJens Wiklander 
1287f7cc36c0SJens Wiklander 		if (pkcs11_session_is_user(session))
1288f7cc36c0SJens Wiklander 			return PKCS11_CKR_USER_ALREADY_LOGGED_IN;
1289f7cc36c0SJens Wiklander 
1290f7cc36c0SJens Wiklander 		/*
1291f7cc36c0SJens Wiklander 		 * This is the point where we could check if another client
1292f7cc36c0SJens Wiklander 		 * has another user or SO logged in.
1293f7cc36c0SJens Wiklander 		 * See comment on CKR_USER_TOO_MANY_TYPES above.
1294f7cc36c0SJens Wiklander 		 */
1295f7cc36c0SJens Wiklander 
1296f7cc36c0SJens Wiklander 		rc = check_user_pin(session, pin, pin_size);
1297f7cc36c0SJens Wiklander 		if (!rc)
1298f7cc36c0SJens Wiklander 			session_login_user(session);
1299f7cc36c0SJens Wiklander 
1300f7cc36c0SJens Wiklander 		break;
1301f7cc36c0SJens Wiklander 
1302f7cc36c0SJens Wiklander 	case PKCS11_CKU_CONTEXT_SPECIFIC:
1303f7cc36c0SJens Wiklander 		return PKCS11_CKR_OPERATION_NOT_INITIALIZED;
1304f7cc36c0SJens Wiklander 
1305f7cc36c0SJens Wiklander 	default:
1306f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_TYPE_INVALID;
1307f7cc36c0SJens Wiklander 	}
1308f7cc36c0SJens Wiklander 
1309f7cc36c0SJens Wiklander 	if (!rc)
1310f7cc36c0SJens Wiklander 		IMSG("PKCS11 session %"PRIu32": login", session_handle);
1311f7cc36c0SJens Wiklander 
1312f7cc36c0SJens Wiklander 	return rc;
1313f7cc36c0SJens Wiklander }
1314f7cc36c0SJens Wiklander 
1315f7cc36c0SJens Wiklander uint32_t entry_ck_logout(struct pkcs11_client *client,
1316f7cc36c0SJens Wiklander 			 uint32_t ptypes, TEE_Param *params)
1317f7cc36c0SJens Wiklander {
1318f7cc36c0SJens Wiklander 	const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
1319f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1320f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE,
1321f7cc36c0SJens Wiklander 						TEE_PARAM_TYPE_NONE);
1322f7cc36c0SJens Wiklander 	struct pkcs11_session *session = NULL;
1323f7cc36c0SJens Wiklander 	enum pkcs11_rc rc = PKCS11_CKR_OK;
1324f7cc36c0SJens Wiklander 	struct serialargs ctrlargs = { };
1325f7cc36c0SJens Wiklander 	uint32_t session_handle = 0;
1326f7cc36c0SJens Wiklander 	TEE_Param *ctrl = params;
1327f7cc36c0SJens Wiklander 
1328f7cc36c0SJens Wiklander 	if (!client || ptypes != exp_pt)
1329f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1330f7cc36c0SJens Wiklander 
1331f7cc36c0SJens Wiklander 	serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size);
1332f7cc36c0SJens Wiklander 
1333f7cc36c0SJens Wiklander 	rc = serialargs_get(&ctrlargs, &session_handle, sizeof(uint32_t));
1334f7cc36c0SJens Wiklander 	if (rc)
1335f7cc36c0SJens Wiklander 		return rc;
1336f7cc36c0SJens Wiklander 
1337f7cc36c0SJens Wiklander 	if (serialargs_remaining_bytes(&ctrlargs))
1338f7cc36c0SJens Wiklander 		return PKCS11_CKR_ARGUMENTS_BAD;
1339f7cc36c0SJens Wiklander 
1340f7cc36c0SJens Wiklander 	session = pkcs11_handle2session(session_handle, client);
1341f7cc36c0SJens Wiklander 	if (!session)
1342f7cc36c0SJens Wiklander 		return PKCS11_CKR_SESSION_HANDLE_INVALID;
1343f7cc36c0SJens Wiklander 
1344f7cc36c0SJens Wiklander 	if (pkcs11_session_is_public(session))
1345f7cc36c0SJens Wiklander 		return PKCS11_CKR_USER_NOT_LOGGED_IN;
1346f7cc36c0SJens Wiklander 
1347f7cc36c0SJens Wiklander 	session_logout(session);
1348f7cc36c0SJens Wiklander 
1349f7cc36c0SJens Wiklander 	IMSG("PKCS11 session %"PRIu32": logout", session_handle);
1350f7cc36c0SJens Wiklander 
1351f7cc36c0SJens Wiklander 	return PKCS11_CKR_OK;
1352f7cc36c0SJens Wiklander }
1353